Pierre-Etienne Moreau, Christophe Ringeissen. LORIA-INRIA and UHP. Campus Scientifique BP 239. F-54506 Vandoeuvre-l`es-Nancy Cedex. Abstract.
URL: http://www.elsevier.nl/locate/entcs/volume15.html 17 pages
Handling ELAN Rewrite Programs via an Exchange Format 1 Peter Borovansk´y, Salma Jamoussi Pierre-Etienne Moreau, Christophe Ringeissen LORIA-INRIA and UHP Campus Scientifique BP 239 F-54506 Vandoeuvre-l`es-Nancy Cedex
Abstract Designing a programming environment raises difficult implementation problems since such software is not just one piece of code able to execute programs expressed in a given programming language, but consists generally of several heterogeneous tools. The idea behind a data exchange format is to provide a common representation for the interconnection of these different tools. Moreover, an exchange format is a way to handle programs like any kind of objects in the programming language, and so it is useful for instance in the context of the reflection problem. In this paper, we report our experiments with the current exchange format created and used by the actual implementation of the rule-based programming language ELAN.
1
Introduction
The design of a complete programming environment is quite a hard and endless task including several heterogeneous tools dedicated to the design of programs, such as a powerful parser, an expressive pre-processor, a user-friendly interpreter and a fast compiler. Some environments are currently under investigation for rule-based programming. The ASF+SDF environment [16] is a good example in which different tools are connected to a ToolBus and communicate via the same common language based on an intermediate format [2]. Moreover, a rule-based programming language should be powerful enough to implement such tools handling rule-based programs expressed in the same language. So the existence of a format clearly relies to the reflection problem, since an exchange format also provides a way to represent programs as terms. 1
This work has been partially supported by the Esprit Basic Research Working Group 22457 - Construction of Computational Logics II.
c
1999 Published by Elsevier Science B. V.
´, Jamoussi, Moreau, Ringeissen Borovansky
The reflection problem has been solved in a way fully integrated in the Maude language [5,6]. Nowadays, cooperative systems have attracted considerable interest in many fields of Computer Science like Software Engineering, Artificial Intelligence, Automated Deduction, Constraint Programming and Computer Algebra [7,8,12]. The need of a common exchange format is now well-established, and this can be easily explained by several obvious reasons. •
First of all, different tools based on the same format can be developed separately and safely by different groups or individuals.
•
Second, this format can be understood as an easily accessible representation of an object, in our case a rewrite program, which is rather difficult to parse as it is. This representation may be useful not only for one environment but for all analogous environments handling the same kind of objects.
•
Third, as shown in this paper, one can design tools transforming an object via its representation.
However, dealing with an exchange format has also a major drawback. This approach is not the most efficient we could imagine since a superfluous encoding/decoding overhead is introduced for all the tools to be integrated. This seems to be the price to pay for the development of a coherent environment that consists of different atomic processes. Analogously to the ASF+SDF environment, we have recently introduced an exchange format for ELAN programs, the so-called REF format where REF stands for “Reduced Elan Format”. In this paper, we report our first experiments concerning the REF format, and we describe several tools using this common interface. We use it as a termlike representation of ELAN programs in some basic tools (a partial evaluation method and a debugger) written in ELAN and handling ELAN programs. It is also useful to establish a link between ELAN and other rule-based systems like ASF+SDF, or to connect several tools written in ELAN (or not), like combining a completion procedure for rewrite systems with a procedure for proving the termination. The paper is organized as follows: Section 2 briefly introduces the REF format and its connection with the ELAN syntax. Then, we explain in Section 3 why the REF format can be seen as a common interface for rewrite specifications. Section 4 presents a case-study for the completion problem of REF programs. In Section 5, we show that partial evaluation techniques for ELAN can also be implemented via the REF format. A debugger is another typical application using both the REF format and Input/Output functions available in ELAN (Section 6). Finally, we conclude with future works involving this format (Section 7) and possible extensions (Section 8).
2
´, Jamoussi, Moreau, Ringeissen Borovansky
2
Reduced ELAN Format
The introduction of the REF format was first motivated by the recent development of the ELAN compiler written in JAVA and producing C code. This permits the design of a stand-alone compiler, independently to the current interpreter implementation. On the contrary, the first ELAN compiler initially designed by M. Vittek [21] was strongly dependent to the original interpreter, and so its maintenance was rather difficult. A new option of the ELAN interpreter (the --export option) aims at dumping into a file an image of its working memory. Basically, this image is obtained by using the mix-fix parser which is built in the interpreter. It corresponds to the Reduced ELAN Format of an ELAN Program. Conversely, another option (the --import option) enables us to load a REF program into the interpreter without using the expensive mix-fix parser. Roughly speaking, a REF program can be considered as a flat representation of an ELAN program where the same syntactic constructions occurring in different ELAN modules are merged together. A REF program consists of several lists: •
a list of identifiers,
•
a list of sort identifiers,
•
a list of module identifiers,
•
a list of grammar rules for each sort s, with one entry for each operator declaration of sort s,
•
a list of rules,
•
a list of strategies.
Every identifier occurring in the above lists is represented in the REF program by an index indicating its position in the related list. All ingredients of a REF program are now illustrated on a very simple ELAN program. Example 2.1 (Signature encoding) We give below the ELAN syntax of a signature declaration, and the related REF encoding. operators global f(@) : (T) T ; @+@ : (T T) T ; a : T ; b : T ; end GrammarForSort ⌈T⌉:0: 3:hf(@)i:0:8:0:0:0:Ident(⌈f⌉).Char(‘(’).Type(⌈T⌉).Char(‘)’).nil:nil. 3:h@+@i:0:8:0:0:0:Type(⌈T⌉).Char(‘+’).Type(⌈T⌉).nil:nil.
3
´, Jamoussi, Moreau, Ringeissen Borovansky 3:hai:0:8:0:0:0:Ident(⌈a⌉).nil:nil. 3:hbi:0:8:0:0:0:Ident(⌈b⌉).nil:nil. nil end
For a better understanding, the index of the sort T is denoted by ⌈T⌉, the indexes of the identifiers f, a, b are respectively ⌈f⌉, ⌈a⌉ and ⌈b⌉, and the ASCII code of a character c is denoted by ‘c’. Each grammar rule entry admits a unique label. For instance, the label of the first operator declaration is hf(@)i. The different parameters of a grammar rule encode respectively from the left to the right: the visibility (local or global), the label, the priority, some syntactic information (8 means printable), a flag indicating a built-in function, the equational theory satisfied by the operator (currently, an operator is either free or associative-commutative), a flag for the strategy compilation, and a list of lexical entities. A rule is made of its index in the list of identifiers, a left-hand side term, a right-hand side term and a list of boolean conditions and local assignments respectively introduced by if and where. Example 2.2 (Rule encoding, Example 2.1 continued) Consider the following set of rules written in the ELAN syntax: rules for T X,Y: T ; global [R1] X+X => f(X) end [R2] X+Y => f(X+Y) end [R3] f(X) => f(X) + f(Y) where Y:=() a+b end end The related REF encoding is: RULE( ⌈R1⌉,⌈T⌉,⌈module⌉,1,1,1, FSYM(VAR(0,⌈T⌉). VAR(0,⌈T⌉).nil, h@+@i), FSYM( VAR(0,⌈T⌉).nil, hf(@)i), nil) end RULE( ⌈R2⌉,⌈T⌉,⌈module⌉,1,1,2, FSYM(VAR(0,⌈T⌉). VAR(1,⌈T⌉).nil, h@+@i), FSYM( FSYM(VAR(0,⌈T⌉). VAR(1,⌈T⌉).nil, h@+@i).nil, hf(@)i), nil) end RULE(
4
´, Jamoussi, Moreau, Ringeissen Borovansky ⌈R3⌉,⌈T⌉,⌈module⌉,1,1,2, FSYM(VAR(0,⌈T⌉).nil, hf(@)i), FSYM( FSYM(VAR(0,⌈T⌉).nil, hf(@)i).FSYM(VAR(1,⌈T⌉).nil, hf(@)i).nil, h@+@i), WHERE( VAR(1,⌈T⌉),-1,FSYM(FSYM( nil, hai).FSYM( nil, hbi).nil, h@+@i)). nil)
One should note that ⌈R1⌉, ⌈R2⌉, ⌈R3⌉ in RULEs are the respective indexes of rule identifiers R1, R2, R3. The different parameters of RULE are respectively from the left to the right: the index of rule identifier, the index of sort identifier, the index of module identifier, some information, the theory of the left-hand side top-symbol, the number of variables, the left-hand side (see Example 2.4), the right-hand side (see Example 2.4), and finally the list of conditions and where assignments. A strategy is a way to describe the computations the user is interested in. Application of a rewrite rule in ELAN yields, in general, several results. When a rewrite rule or a strategy returns an empty set of terms, we say that it fails. The language provides a way to handle the non-determinism. This is done using some basic strategy operators such as: dc standing for don’t care choose, dk standing for don’t know choose, and first. For a set of strategies S1 , . . . , Sn , the strategy dc (S1 , . . . , Sn ) returns all the results of Si , where Si is non-deterministically taken among the successful (i.e. non-failing) strategies in S1 , . . . , Sn . first is a sequential version of don’t care choose, which takes always the first successful strategy in textual order. On the contrary, if the set of rules is applied using the dk (S1 , . . . , Sn ) strategy, then all possible results are computed and returned by the strategy. The implementation handles these several results by an appropriate back-chaining operation. Concatenation of strategies is expressed by the operator “;”. In the REF format, a strategy is made of an index in the list of identifiers and an expression built on the basic strategy operators. Example 2.3 (Strategy encoding, Example 2.2 continued) Consider the following ELAN strategy definition: strategies for T -> T implicit [] strat => dk(R1,R2) ; dc(R3) end end The corresponding REF encoding is: STRATEGY(⌈strat⌉,⌈T⌉,⌈module⌉, dk(⌈R1⌉.⌈R2⌉.nil) ; dc(⌈R3⌉.nil)) end A term is a list of subterms together with a grammar rule label corresponding to its top-symbol. 5
´, Jamoussi, Moreau, Ringeissen Borovansky
Example 2.4 (Term encoding, Example 2.1 continued) The term a+b is encoded as FSYM( FSYM( nil, hai).FSYM( nil, hbi).nil, h@+@i)) A complete specification for REF programs has been implemented in ELAN and is now available in the current ELAN library of standard modules. This module can be imported and used in ELAN for handling REF programs just like any abstract data type.
3
REF Format as a Common Interface
In the rewriting community, the idea of designing an abstract machine has been extensively studied [20,11,13,18], but none of them became a standard like the Warren Abstract Machine (WAM [1,22]) for the compilation of Prolog, mainly because the performances were not as good as expected. The main problem of the proposed abstract machines was their low-level language that made impossible high-level optimizations. The idea of compiling a rewrite system directly to an imperative language, such as C, without introducing any intermediate language, leads to implementations as efficient as functional ones. The new ELAN compiler is available as a separate tool where the REF format is used as the source language and a portable C code is generated. Due to this stand-alone design, the compiler is not only dedicated to ELAN specifications but can be considered as a rewrite abstract machine which can be used in connection with any rule-based specification language provided that a source rewrite specification is translatable into a REF program. De facto, the REF format becomes an abstract machine language. To experiment with our approach, a translator from ASF+SDF to REF has been designed in ASF+SDF itself. It consists in several transformation steps described below: •
the ASF+SDF specification is translated into a term-based structural representation: the AsFix format. During this step, all mix-fix constructions are replaced by equivalent prefix constructions in order to make the AsFix format easy to parse;
•
the AsFix program is then translated in a simpler format called µASF which no longer contains any pretty-print information. Operator names are also simplified in order to make further transformation easier;
•
several translation phases are performed on the µASF term in order to remove list-matching constructions: associative operators are replaced by a new family of operators and rules to simulate rewriting modulo associativity;
•
only after these three steps, the simplified µASF program (without any associative operator) can be translated into the REF syntax: operators have to be renamed and µASF constructions, such as matching conditions, have to be mapped to existing REF constructions;
•
the REF program can be compiled by the ELAN compiler to make an exe6
´, Jamoussi, Moreau, Ringeissen Borovansky
cutable specification. This rather complex compilation scheme has been successfully implemented and gives interesting experimental results: starting from two equivalent specifications written on one hand in ASF+SDF and on the other hand in ELAN, the two executables obtained by compiling their REF representations have roughly the same efficiency. This means that no significant run-time overhead is introduced by successively translating ASF+SDF to AsFix, and then to µASF in order to produce a REF program.
4
Integration of Proof Procedures
In this section, we illustrate the possibility to analyze and to transform REF programs on a small example. We integrate together a decision procedure for the termination problem and a completion procedure of rewrite systems to allow to transform an input REF program into its completed REF form. We so illustrate the possibility to interconnect several applications as black-boxes without modifying and merging their ELAN sources. In a more general case, these applications are even not necessarily specified in ELAN. A procedure looking for general path orderings (gpo) for rewrite systems [9] is the first integrated application. The second one is the Knuth-Bendix’s completion procedure [15], which completes rewrite systems using the general path ordering found before. These applications do not need to be modified. Other applications, even not written in ELAN, may be combined in a similar way. For example, we could replace the ELAN implementation of the procedure gpo by its ECLIPSE version [10], or by another implementation of a different ordering. An alternative approach extends these applications by a REF interface. Now, it is possible only for applications written in ELAN, C or JAVA, because the parsers of the REF format are currently available only for these environments. In our approach illustrated in Figure 1, two pre-processing phases extract all necessary components of a REF program and convert them into input formats accepted by another applications. Two ELAN modules to gpo and to completion (cf. Figure 1) represent these pre-processing phases. They create two specification files Gpo/p.spc and Compl/p.spc (see Figure 2, where p is the group theory) used by the procedures gpo and completion. The specification made by the procedure to completion is then enriched by the general path ordering p.ord produced by the procedure gpo. After termination of the completion procedure, a post-processing phase composes rules of the completed rewrite system p.rules with a signature of the original REF program p.ref, and the completed REF program constructed. This program transformation is composed of two procedures, and thus, it terminates if both of them terminate. 7
´, Jamoussi, Moreau, Ringeissen Borovansky to_completion
p.eln
export
Compl/p.spc
completion
p.ref
p.rules
compose
p’.ref
to_gpo Gpo/p.spc
gpo
p.ord
Fig. 1. The completion of REF programs module group // group.eln sort elem; end ops global o : elem; m(@,@) : (elem elem) elem; i(@) : (elem) elem; end rules for elem x, y, z : elem; global [] m(m(x,y),z) ⇒m(x,m(y,z)) end [] m(o,x) ⇒x end [] m(i(x),x) ⇒o end
//group.rules m(o, var0 ) m(var0 , o) i(i(var0 )) m(i(var0 ), var0 ) m(i(var0 ), m(var0 , var1 )) i(o) m(var0 , i(var0 )) m(var0 , m(i(var0 ), var1 )) m(m(var0 , var1 ), var2 ) i(m(var0 , var1 ))
specif group // Compl/group.spc Vars var0 var1 var2 Ops i : 1 m : 2 o : 0 Prec i : 1 o : 0 System m(m(var0 , var1 ), var2 ) ⇒ m(var0 , m(var1 , var2 )) m(o(), var0 ) ⇒ var0 m(i(var0 ), var0 ) ⇒ o()
⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒
var0 var0 var0 o var1 o o var1 m(var0 , m(var1 , var2 )) m(i(var1 ), i(var0 ))
specif group // Gpo/group.spc Vars var0 var1 var2 Ops i : 1 m : 2 o : 0 Rules m(m(var0 , var1 ), var2 ) ⇒ m(var0 , m(var1 , var2 )) m(o(), var0 ) ⇒ var0 m(i(var0 ), var0 ) ⇒ o()
Fig. 2. The completion of group.eln
5
Partial Evaluation
Different partial evaluation techniques studied from early 80’s consist of several transformations of a program P , whose inputs are partially known, to a program P ′ , which gives the same results as P , but more efficiently than P . These techniques intensively studied in functional and logic programming have been recently applied on equational (rewrite) programs [17,19]. We illustrate a particular case of these partial evaluation techniques for computational systems [14], where a partially evaluated program is an ELAN strategy applied on a non-ground term. Computational systems, e.g. ELAN programs, are composed of their logical and controlling parts. The logical part is represented by rewrite rules, and the partial evaluation techniques described in [17,19] can be applied on them. The controlling part of an ELAN program is expressed in a declarative, nondeterministic, recursive and strictly typed formalism, called strategy language. In this section, we sketch one partial evaluation technique of ELAN strate8
´, Jamoussi, Moreau, Ringeissen Borovansky
gies introduced to improve the performance of an interpreter controlled by these strategies. A non-deterministic interpreter of the high-level ELAN strategies (cf. more details in [3,4]) is an ELAN program driven by a low-level evaluation strategy eval, which treats several cases corresponding to different constructions of the interpreted language. These constructions are described by rewrite rules. The proposed partial evaluation method is used to eliminate all unusable cases of the strategy eval in each of its applications, and also to specialize rewrite rules of eventually usable cases. An input of this method is an ELAN strategy (e.g. eval) and a non-ground term, which the strategy is applied on. A result is a specialized version of this strategy preserving the operational semantics. It may refer to new rewrite rules, which are instances of the original ones. Due to this instantiation of rewrite rules, the structure of terms of new rules is more specialized, which allows to perform this specialization technique also on these rules. This partial evaluation technique was first implemented in C++ as an internal ELAN transformation fully integrated to this system. It is not evident to understand (eventually, to modify) this version, because it refers to several internal structures of the ELAN system. That is why, a new specification of this method is designed in ELAN, which is supposed to be more readable and modifiable. Another motivation of having an implementation independent on internal structures of ELAN, is a possible integration of existing partial evaluation methods for rewrite systems. This method works over REF programs (cf. Figure 3), which seems to be a more important aspect from the point of view of this section, than the detailed description of the method.
Specification
End User
preprocessing
Query
Import Interpreter
Partial Evaluation REF
REF
Export
Programmer
Logic
Super User
Rewriting Logic
RESULTS
Fig. 3. The scheme of partial evaluation
In Section 5.1, we outline the partial evaluation method of ELAN strategies, and in Section 5.2, we discuss several implementation aspects of this method w.r.t. the REF format. 9
´, Jamoussi, Moreau, Ringeissen Borovansky
5.1 Program Transformation Evaluation strategies or procedures of interpreters typically consist of many disjunctive cases, one for each language construction. In ELAN, it can be expressed by a strategy eval like: eval ⇒ first(dk(C1), dk(C2), . . . , dk(Cn)), where rewrite rules Ci interpret the language construction Ci . These cases are often exclusive, so given a term, which the strategy eval is applied to, we can select a small subset of applicable cases dk(Ci) from the strategy eval. We briefly sketch three main points of our partial evaluation method. We make an abstraction of rewrite rules of our interpreter, and for sake of simplicity, let us consider that Ci is of the form: [Ci]
[Ci (s)]t
⇒ . . . (eval)[Cj (f (s, t))]t . . .
where the expression [Ci (s)]t means an application of a parameterized construction Ci (s) to a term t. It is defined using another (more simple) construction Cj whose argument f (s, t) somehow depends on inputs of Ci . Simplification of strategies The expression [Cj (f (s, t))]t on the right-hand side of this rule, called redex of the partial evaluation method, is reduced by the evaluation strategy eval. This expression represents a partially known input of the strategy eval. For the purpose of this rewrite rule, the strategy eval can be simplified to a new strategy eval′ containing only applicable cases, i.e. cases of those rewrite rules, whose the left-hand side is unifiable with this redex. Instantiation of rules The second idea of this method is based on instantiation of the rule Cj associated to Cj and propagation of the simplification. If we assume that Cj is also of the form: [Cj]
[Cj (z)]u
⇒
. . . (eval)[Ck (g(z, u))]u . . .
then it can be partially instantiated by a non-ground substitution θ = {z 7→ f (s, t)} to: [Cj′ ]
[Cj (f (s, t))]θ(u)
⇒
. . . (eval)[Ck (g(f (s, t), θ(u)))]θ(u)
The new instantiated rule Cj′ may contain a new redex reducible by the partial evaluation method. Due to this instantiation, the specialization can be propagated while the program contains some reducible redexes, or a loop among redexes is detected. Compression of terms Finally, a compression of terms is useful to decrease the size of terms, which occur in the generated rules. While the rule Cj′ is an instance of the original 10
´, Jamoussi, Moreau, Ringeissen Borovansky
rule, and therefore, the terms of this rule are larger than those in the original one. It may decrease the performance of this system, because the matching algorithm and the term construction procedure are more time-expensive. Therefore, a term compression phase searches for common patterns occurring in the left-hand sides of rules and redexes on the right-hand side of rules, and it abbreviates them introducing new function symbols to the signature of the program. 5.2 Implementation via the REF format The partial evaluation algorithm of ELAN strategies, presented in [4], is described by a set of transformation rules. For example, the case of a strategy dk(S1 , . . . , Sn ) specialized to dk(S1′ , . . . , Sn′ ) can be sketched as follows: Sj ⋄ I ⇒ Sj′ ◦ Oj dk(S1 , . . . , Sn ) ⋄ I ⇒ dk(S1′ , . . . , Sn′ ) ◦ ∪nj=1 Oj where I and Oj are list of patterns, i.e. non-ground terms, and S ⋄ I ⇒ S ′ ◦ O represents a relation between the original and new strategies (i.e. S, S ′ ) and their possible inputs and outputs (i.e. I, O) 2 . However, this transformation rule is not completely described, because during the partial evaluation of substrategies Sj , i.e. Sj ⋄ I ⇒ Sj′ ◦ Oj , new rules and strategies may be generated. They are added to the specialized program, but they are not presented in this transformation rule. Moreover, this algorithm detects loops during the specialization process, therefore, a tree structure of dependencies between redexes should be maintained (it is not presented either). For the implementation of this algorithm in ELAN, there is a structure Env containing the following environment: a list of input/output patterns, a specialized strategy, a specialized computational system (i.e. program) and a tree of dependences. It is defined as follows: [@,@,@,@]
: (patterns:list[Term] strat:Strategy prog:Program depend:Dependencies ) Env;
and it is passed as an argument to the procedure P eval of partial evaluation. We can illustrate the ELAN form of the transformation rule mentioned above: []
Peval([I,dk(choices),P,A]) => [O,dk(choices1),P1,A1] where (Env_choice)[O,choices1,P1,A1]:= () Peval_choices([I,choices,P,A])
where I, O : list[T erm] are lists of patterns in the REF format, dk(choices), dk(choices1) are ELAN strategies before and after partial evaluation also in the REF format, where choices, choices1 : StrategyChoice are lists of substrategies specialized by the procedure P eval choices. P , P 1 : P rogram are REF programs and A, A1 : Dependencies are trees of dependences of redexes. 2
The full description of this algorithm is out of the scope of this paper
11
´, Jamoussi, Moreau, Ringeissen Borovansky
The sketched partial evaluation method is used for optimization of the high-level ELAN strategies, which are interpreted by an interpreter using the low-level strategies (those presented page 5). The partial evaluation algorithm is general enough to optimize ELAN strategies different from the particular strategy eval illustrated above. Using this program transformation, we obtain the speed-up about 2-4 (in some cases up to 5), which is a reasonable result for such techniques.
6
A Debugger for ELAN
Even if the ELAN programming language allows us to design an executable specification, the role of a debugger remains of greatest interest in order to understand and to detail what is going on during the computation of a normal form. For imperative programming languages, a debugger may be considered as a tool for performing step-by-step computation: at each step, this tool gives the current state of the environment, that is the values of variables. For a programming language like ELAN, the behavior of a program seems to be much more simple since there are no global variables. In such a language, an elementary computation transforms a term (let say a current state) into a new one by applying a rewrite rule. But this rewrite rule also integrates some conditions and local affectations of real importance to understand the behavior of a computation. In this context, a debugger should make explicit the instantiation computed by a rule application. To create such a trace information, our idea was to develop a debugger in ELAN by using the available Input/Output functionalities. This permits us to introduce some printing rules in order to write the current term and the values of conditions or local variables. Moreover, the debugger handles objects corresponding to ELAN programs. Thus, the use of an external representation for ELAN programs is also very convenient to implement such a tool which is aimed at enriching an ELAN program by additional tracing facilities via its REF representation. The current debugger implementation may be seen as a small interpreter written in ELAN and analyzing two different classes of commands. On one hand, some break-point commands are dedicated to the transformation of the current program in memory. On the other hand, some dump commands are in charge of the program pretty-printing. These two classes of commands strongly interact since the user wants to choose some break points among the set of all potential positions. So he must be able to know all the details about rules and strategies. These details are provided by the dump commands. 6.1 Program Transformation We give in this section a short overview of the program transformation process realized for the debugging. Two possible transformation schemes can be applied respectively for rules and for strategies. A transformed rule (resp. 12
´, Jamoussi, Moreau, Ringeissen Borovansky
strategy) behaves exactly like the original one, except that it incorporates a writing operation as side effect. 6.1.1 Rules ELAN enables us to deal with extra-variables which are not occurring in the left-hand side and the right-hand side of a rule. Hence, we can introduce a new where affectation: [Rule] l => r ... where X := ... where W_X := () write(stdout, X) ... end such that X is a local variable to be traced in the rule and W X is a new variable having the value of () write(stdout,X), that is X. This means that the value of X will be written on stdout during the application of the rule. Notice that the variable W X is useless to build the right-hand side r. It is just needed to store the result value of the write function. 6.1.2 Strategies A strategy or a sub-strategy, say strat, is transformed into a new strategy obtained by the concatenation of strat with the strategy dc(R) where R is an identity rule of the form [R] X => X
where W_X := () write(stdout, X)
Again, this rule writes the term on stdout and rewrites this term into itself. So, the strategy strat; dc(R) applies the strategy strat and then writes on stdout the result of its application. 6.2 Program Visualization All the different parts of a REF program can be decoded and visualized under an ELAN-like syntax. For rules and strategies, this pretty-printed form includes some numbering information. For this numbering, we use the fact that a REF program is a term where relevant subterm occurrences may be represented as lists of naturals. This numbering is used to print out all the possible positions in the REF program for potential break-points. Then, the user can give a position into a break-point command. The corresponding break-point will then be traced during the program execution. Currently, it is not possible to completely decode an ELAN program from a program in the REF format. Indeed the modules importation tree is lost and the names of local variables cannot be retrieved. Hence, the first local variable occurring in the rule is denoted by V AR(0), the second one is denoted by V AR(1), etc. Except the names of local variables, the dump commands 13
´, Jamoussi, Moreau, Ringeissen Borovansky
perform a pretty-print of the main sections of a REF program (the rules, the strategies, the signature) as they appear in the original ELAN program.
6.3 Implementation via the REF format On the abstract level, the debugger is an ELAN program which reads a REF program and writes another equivalent REF program enriched by trace commands at break-points. The user indicates these break-points by using the different commands available in the debugger.
ELAN Interpreter
User Query ELAN Compiler Import
Debugger REF
Export REF
ELAN Interpreter
ELAN Interpreter
Fig. 4. ELAN debugger written in ELAN
The main difficulty was to study the translation into the REF format of program transformations seen before in the ELAN syntax. In this context, we have implemented a few operations for the REF abstract data type. These operations aim at •
adding new local variables into rules (the variable W X)
•
adding new functions to the signature (the function write)
•
adding new rules to the set of rules (the printing rule R for the strategies trace).
The reader should be aware that the enrichment by rules and strategies has consequences in several other constituents of the REF program. For instance, just adding the write operator introduced by the printing rule R implies that different lists must be updated in the REF program. This program has been realized in ELAN thanks to the Input/Output primitives provided by the interpreter. Thus, the actual prototype is only executable with the ELAN interpreter but the idea is to finally generate a stand-alone executable debugger built thanks to the ELAN compiler improved with Input/Output primitives. 14
´, Jamoussi, Moreau, Ringeissen Borovansky
7
Towards an Intensive Use of the Exchange Format
The REF format is a first step towards an exchange format for different tools developed around ELAN. Until now, the ELAN interpreter already integrates different ingredients. For instance, the mix-fix parser was initially a strongly dependent part of the interpreter. We have recently extracted this parser from the rest of the interpreter. It is now possible to call the parsing process as a stand-alone process that communicates via the REF format. More precisely, we have implemented in C/C++ two REF tools: •
query2ref: this program parses a query with respect to a given mix-fix signature and returns the same term in the REF format.
•
ref2result: conversely, this program reads a term in the REF format and writes the same term in textual form.
Example 7.1 (Example 2.4 continued). Given the term a+b of sort T, query2ref yields: FSYM( FSYM( nil, hai).FSYM( nil, hbi).nil, h@+@i)) Conversely, given the latter, ref2result yields again the initial term a+b. These tools can be considered as the minimal requirements to realize Input/Output functionalities and we plan to call them from the C code generated by the compiler. They are also used in connection with the compiler in order to read a query term and to write result terms in a user-friendly syntax, since the compiler handles only terms in the REF format.
8
Conclusion
Several tools have been designed around ELAN to deal with the REF format which is a representation of ELAN programs. This format appears to be a convenient way for the transformation of ELAN programs thanks to ELAN itself, and so it is the key for the implementation of a reflection mechanism into ELAN. The actual REF-based tools cover a large range of applications, from proof procedures and partial evaluation to debugging aspects. Nevertheless, the actual external representation is very close to the internal architecture of the ELAN interpreter, and so it inherits the weaknesses of the current implementation. Hence, a REF program is just a flat representation of a modular ELAN program because the importation information about modules is somehow lost in the interpreter working memory. In the same way, the REF format is not really well-suited for the pre-processor actually used by the ELAN interpreter. This explains why we are trying now to improve the current REF format. The forthcoming exchange format we have in mind should encompass some features of primal interest like modularity, parameterization, and compactness. To this end, a possible solution would be to define a particular instance of the 15
´, Jamoussi, Moreau, Ringeissen Borovansky
generic AsFix format developed for the ASF+SDF environment. The choice of a good external representation is decisive since it is clearly a significant step towards a new modular open architecture for ELAN in which this format plays a central role.
Acknowledgements We would like to thank H´el`ene Kirchner for many fruitful discussions and helpful comments on a previous version of this paper.
References [1] H. A¨ıt-Kaci. The WAM: a (real) tutorial. Technical report 5, Digital Systems Research Center, Paris (France), January 1990. [2] J. Bergstra and P. Klint. The Discrete Time ToolBus. University of Amsterdam, 1995.
Technical report,
[3] P. Borovansk´ y. The control of Rewriting: Study and Implementation of a Strategy Formalism. In Proceedings of the second international workshop on rewriting logic, September 1998. [4] P. Borovansk´ y and H. Kirchner. Strategies of ELAN: meta-interpretation and partial evaluation. In Proceedings of International Workshop on Theory and Practice of Algebraic Specifications ASF+SDF 97, Workshops in Computing, Amsterdam, September 1997. Springer-Verlag. [5] M. Clavel. Reflection in general logics, rewriting logic, and Maude. PhD thesis, University of Navarre, Spain, 1998. [6] M. Clavel, F. Durn, S. Eker, P. Lincoln, and J. Meseguer. An Introduction to Maude (Beta Version). Technical report, March 1998. [7] S. Dalmas, M. Gaetano, and A. Sausse. A distributed and cooperative environment for computer algebra. Journal of Symbolic Computation, 21(46):427–439, April–June 1996. [8] S. Dalmas, M. Ga¨etano, and S. Watt. An OpenMath 1.0 implementation. In W. W. K¨ uchlin, editor, ISSAC ’97. Proceedings of the 1997 International Symposium on Symbolic and Algebraic Computation, July 21–23, 1997, Maui, Hawaii, pages 241–248, New York, NY 10036, USA, 1997. ACM Press. [9] T. Genet and I. Gnaedig. Solving GPO ordering constraints with shared term data structure. Technical Report 95-R-363, CRIN, 1995. [10] T. Genet and I. Gnaedig. Termination Proofs using gpo Ordering Constraints. In M. Dauchet, editor, Proceedings 22nd International Colloquium on Trees in Algebra and Programming, Lille (France), volume 1214 of Lecture Notes in Computer Science, pages 249–260. Springer-Verlag, 1997.
16
´, Jamoussi, Moreau, Ringeissen Borovansky
[11] L. H. Hamel. Behavioural Verification and Implementation of an Optimising Compiler for OBJ3. PhD thesis, Oxford University Computing Laboratory, GB, 1995. [12] K. Homann and J. Calmet. Combining Theorem Proving and Symbolic Mathematical Computing. In J. Calmet and J. Campbell, editors, Proc. of AISMC-2, volume 814 of Lecture Notes in Computer Science, pages 18–29. Springer-Verlag, 1995. [13] J. Kamperman. Compilation of Term Rewriting Systems. PhD thesis, UVA, Amsterdam, NL, 1996. [14] C. Kirchner, H. Kirchner, and M. Vittek. Designing constraint logic programming languages using computational systems. In P. Van Hentenryck and V. Saraswat, editors, Principles and Practice of Constraint Programming. The Newport Papers., chapter 8, pages 131–158. The MIT press, 1995. [15] H. Kirchner and P.-E. Moreau. Prototyping completion with constraints using computational systems. In J. Hsiang, editor, Proceedings 6th Conference on Rewriting Techniques and Applications, Kaiserslautern (Germany), volume 914 of Lecture Notes in Computer Science, pages 438–443. Springer-Verlag, 1995. [16] P. Klint. A meta-environment for generating programming environments. ACM Transactions on Software Engineering and Methodology, 2:176–201, 1993. [17] N. Nedjah. Pattern-matching automata for efficient evaluation in equational programming. PhD thesis, UMIST, Manchester, UK, 1997. [18] K. Ogata, K. Ohara, and K. Futatsugi. TRAM: An abstract machine for ordersorted conditional term rewriting systems. In H. Comon, editor, Proceedings of 8-th International Conference Rewriting Techniques and Applications, Lecture Notes in Computer Science, Sitges, Spain, 1997. Springer-Verlag. [19] D. J. Sherman. Run-time and Compile-time improvements to equational programs. PhD thesis, Dept. of CS, University of Chicago (USA), June 1994. [20] R. I. Strandh. Classes of equational programs that compile into efficient machine code. In N. Dershowitz, editor, Proceedings of the Third International Conference on Rewriting Techniques and Applications, pages 449–461, Chapel Hill, NC, April 1989. Vol. 355 of Lecture Notes in Computer Science, Springer, Berlin. [21] M. Vittek. A compiler for nondeterministic term rewriting systems. In H. Ganzinger, editor, Proceedings of RTA’96, volume 1103 of Lecture Notes in Computer Science, pages 154–168, New Brunswick (New Jersey), July 1996. Springer-Verlag. [22] D. H. D. Warren. An abstract Prolog instruction set. Technical Report 309, SRI International, Artificial Intelligence Center, 1983.
17