static semantics and inter-document consistency. For an eager approach to handling these constraints, which does not tolerate errors, graph rewriting rules may restrict the applicability of the rule to contexts that do not violate static semantics. Path expressions can be used to dene these context sensitive restrictions on the left-hand side of the rule. The rule is then applicable only if a match can be found in the host graph that includes a path that is conform to the expression. As an example consider the following rule, which denes that using type place holders may only be expanded if the new value matches a declaration.
ToResType ::= end; Selection 1:Cursor 2:Function 3:PhUsingType SearchId(Id) 2’:2 ToResType 3’:UsingType 4’:4 DeclaredIn 4:TypeDecl transfer 3’.Name=Id production ExpandResultType(Id:STRING) =
Path expressions are graphically depicted in the graph rewriting rule as double-lined arrows labelled with their name and the actual parameters of their invocation. Informally, the path expressionSearchIdsearches for the node of type TypeDeclwhere the string passed as param-
eter is declared. As the path expression appears on the left-hand side of the rewriting rule, the rule can only be applied if such a path to aTypeDeclnode can be found in the host graph.
If found, the related identiers are connected with a context-sensitive edge, which reects the use/declare relation between the two nodes. The formal denition is given below:
path SearchId(p:STRING):IDENTIFIER --> IDENTIFIER = instance of UsingType & <--ToResType--
& <--ToElem-- & <--ToOpList--
& ( (--ToExpTyp--> & Definition(p)) or (--ToImpInt-->...))
end;
restriction Definition(Id:STRING) : IDENTIFIER = valid self.Name=Id;
Note that PROGRESS path expressions are more powerful than their counterpart in GTSL. PROGRESS path expressions can express parallelism which is not required for tool speci- cation and, therefore, neither included in the example nor in GTSL. PROGRESS path ex- pressions are set-oriented, i.e. intermediate steps are always sets of nodes rather than single nodes as in GTSL. GTSL path expressions are, however, safer. Firstly, steps in GTSL path expressions have an explicit cardinality and the type system can prove that the assumptions of a tool builder regarding the cardinality hold. In PROGRESS the tool builder cannot be sure whether a path expression matches multiple target nodes. In the above case, the path expressionSearchIdmust be considered wrong if it reveals a set of nodes rather than the single
node that declares the identier. The PROGRESS type system cannot nd out about that. As a further contribution to safer path expressions, GTSL oers covariant property redenition. In PROGRESS it is not possible to redene edge types in such a way that they connect more specic node types. The above example, therefore, uses aninstance ofoperator, which is the
equivalent of a GTSL type cast, to be able to traverse along an outgoingToResTypeedge from
a node whose static type is IDENTIFIER. In GTSL the use of unsafe type casts can always be
avoided with covariant redenition of abstract syntax children or semantic relationship links, for example.
The applicability of path expressions and restrictions is not conned within an abstract syntax graph of one document. Therefore, inter-document consistency constraints may be expressed in the same manner as static semantics constraints.
While PROGRESS is very appropriate for the denition of eager enforcement of static se- mantics and inter-document consistency constraints, a strategy that tolerates errors is more dicult to dene. The task that has been performed by the single rule in the eager strategy is, for the lazy strategy, split into four rules as given in Figure 6.19. The rst rule expands the place holder of a using type without checking for its consistency. The second rule binds a correct using type to its declaration with a semantic edge DefinedIn. It also removes an
error descriptor from a set of errors that is associated as an attribute to the using type node. The third rule unbinds a using type, whose declaration is no longer available, and removes the semantic edge DefinedIn. The last rule inserts an error descriptor into a set of errors for
each using type node that is not properly bound to a declaration. Note that this specication exploits the fact that PROGRESS rules are applied non-deterministically by the PROGRESS interpreter.
It is unclear to us how eciently the PROGRESS interpreter, which is still under construction, can execute lazy specications like the one above. It will involve a signicant complexity to check all types that do not have an outgoing semantic edge against path expression SearchId.
This concern is reinforced if we consider the complexity that is required for interpretation of path expressions like SearchId. In PROGRESS any step in a path expression is an operation
on a set with the inherent complexity. In GTSL steps that denote abstract syntax children or links in semantic relationships in path expressions are interpreted within the constant time that is required for dereferencing an instance variable. It would be even more complex to check whether the binding of all bound types is still correct, since it involves negation of a rather complex path expression. This might require signicant backtracking. In GTSL this problem is remedied, since the specication of static semantic rules guides an incremental evaluation in the sense that rule predicates refer to incremental changes or deletions made since the last check.
ToResType
::=
end;
Selection 1:Cursor
2:Function 3:PhUsingType 2’:2 ToResType 3’:UsingType
4’:4 DeclaredIn 4:TypeDecl DeclaredIn ::= 3:UsingType 3’:3 SearchId(3.Name)
end; transfer 3’.Errors=3.Errors \ {"TypeNotDeclared"}
4’:4 4:TypeDecl DeclaredIn ::= 3:UsingType 3’:3 SearchId(3.Name) end; 4’:4 4:TypeDecl ::= 3:UsingType 3’:3
end; transfer 3’.Errors=3.Errors ∪{"TypeNotDeclared"} DeclaredIn transfer 3’.Name=Id production ExpandResultType(Id:STRING) = production BindUnboundDecl = production UnbindWronglyBoundDecl = production MarkWronglyBoundDecl =
Figure 6.19: Scoping Rule in PROGRESS
Tool Commands:
A tool builder can dene the preconditions under which a command is oered using the left-hand side of graph rewriting rules. It is, however, not possible to dene how a user can choose to apply a particular graph rewriting rule to a host graph. Neither can PROGRESS dene particular user dialogues that are required in order to inform a user about some particular error, for example. PROGRESS specications are instead used to generate an abstract data type module which implements the graph class dened by the PROGRESS specication. Transactions and rewriting rules are generated into operations of this abstract data type and some upper layers, which have to be coded or generated otherwise, might use these operations to implement tool commands, for example.We have seen that PROGRESS transactions can be used to bind multiple graph tests and rewriting rules together into a larger execution unit. The semantics of a transaction in PROGRESS is then atomicity and durability, i.e. all rules are applied completely or not at all. Once successfully completed, the eect of a transaction is persistent. Compared with transactions in database systems, or interactions in GTSL, a PROGRESS transaction lacks the isolation property. Therefore, PROGRESS transactions cannot be used for specifying concurrent accesses of multiple users to the abstract syntax graph.
Dierent levels of abstraction:
PROGRESS does not oer dierent levels of abstraction on its specication as GTSL does. Obtaining an overview of the abstract syntax graph struc- ture is rather dicult. A tool builder, therefore, has to consider several related graph rewriting rules and must assume an order in which they are applied. In GTSL, the entity relationship model is devoted to this purpose and represents the structure in a hierarchical manner on a type level of abstraction.6.7 Summary
In this chapter, we have delineated a number of requirements of tool specication languages. These languages must support the denition of an abstract syntax for target languages to be edited and analysed by the specied tool. Moreover, the concrete syntax and unparsing schemes for target languages must be denable. Any tool specication language must enable static semantics and inter-document consistency constraints to be dened, even between doc- uments of dierent types. They have to support denition of concurrently executable user commands. These denitions should be carried out at appropriate levels of abstraction. As general specication language requirements, they should enforce structuring of specications into components to obtain comprehensible, maintainable and reusable specications.
We have introduced several languages for tool specication on dierent levels of abstraction. At a very high-level of abstraction, the syntax of the language is dened in terms of an extended and normalised BNF. At a lower level of abstraction, we have suggested an extended entity relationship model based on the OMT notation. It can be used to add structural concerns for static semantics and inter-document consistency based on an abstract syntax tree denition that is generated from an ENBNF. We have then suggested a domain-specic object- oriented language that denes the behaviour of increment classes, which have been identied in the entity relationship model. Unparsing schemes declare the textual representation of documents. Methods dene the operations that are exported to other classes in order to allow for increment modications. Semantic rules dene static semantics and inter-document consistency constraints in a declarative way. Interactions dene tool commands and their appearance in context-sensitive menus. The language distinguishes between dierent kinds of increment classes in a domain-specic way and distinguishes between dierent kinds of properties, i.e. attributes, abstract syntax, and semantic relationship links. These distinctions enable a domain-specic type system to be dened. That type system enables a number of specication errors to be detected. We have then suggested a library of predened classes that provide solutions to very common problems including command denitions for structure- oriented editing and version and simple conguration management. Inheritance dened for GTSL is then exploited to reuse classes from this library in tool-specic classes.
None of the related tool specication languages fulls all requirements. The reason is that they have been dened for dierent purposes. The Synthesizer Generator has been built to generate tools for programming environments. These environments are typically used by single users and are only built for a single language. Thus inter-document consistency constraints, concur- rency control mechanisms or version and conguration management strategies for supporting multiple-users have not been considered at all. Consequently, SSL cannot be used to dene these concerns. The Centaur environment was intended as an environment for prototyping language denitions. For this purpose, it is again not important to have concurrency control, version and conguration management and inter-document consistency constraints. Nor do
user-interactions play an important role here. Therefore, the languages used by Centaur do not address these concerns. PROGRESS is intended as a general purpose language for the denition of graph grammars. As such it does not address the specic requirements that arise during construction of syntax-directed tools, such as denition of lexical and concrete syntax, unparsing schemes and tool commands. However, what all the languages that we reviewed have in common is that their dynamic semantics is formally dened. This is not the case for GTSL which is subject to further work.