Aspect-Oriented Attribute Grammars

Attribute grammars were introduced by D. Knuth [1] and since then have proved to be useful in specifying the semantics of programming languages and in the automatic construction of compilers and interpreters. While implementation of programming languages is the original and most-widely recognized area of attribute grammars, they are also used in many other areas such as [2]: natural language interfaces, graphical user interfaces, visual programming, pattern recognition, hardware design, communication protocols, software engineering, static analysis of programs, databases, etc. However, only a few commercial compilers have been developed using attribute grammars as a design and implementation tool. It has been argued that attribute grammars are unsuitable for the production of high-speed compilers for general-purpose programming languages, since they are just a model of compilation and, thus, too primitive for real engineering discipline, and that they do not directly support the generation and optimization of machine code. The first problem is concerned with the pragmatic aspects of ordinary attribute grammars. Ordinary attribute grammars have deficiencies which become apparent in specifications for real programming languages. Such specifications are large, unstructured, and hard to understand, modify and maintain. Yet worse still, small modifications of some parts in the specification have widespread effects on the other specification parts. There has been a lot of research work on augmenting ordinary attribute grammars with extensions in order to overcome the deficiencies of attribute grammars, such as lack of modularity, extensibility and reusability. Several concepts, such as remote attribute access, object-orientation, templates, rule models, symbol computations, high order features etc., have been implemented in various attribute grammar specification languages. This problem is still insufficiently solved, despite all these different approaches. The aspectoriented attribute grammar, introduced in this paper, is proposed to better solve this problem. In aspect-oriented attribute grammar, concepts from aspect-oriented programming [3] have been integrated with attribute grammars. Aspect-oriented programming is a recently proven approach for describing crosscutting concerns in a modular manner. The second problem of attribute grammars, the lack of proper support for code generation and optimization, has also been insufficiently solved as yet and is out of the scope of this paper. An immediate conclusion might be, however, that attribute grammars are more appropriate in the design and implementation of Domain-Specific Languages (DSLs) [4] rather than for development of conventional optimizing compilers. Domain-specific languages, such as database query languages, robot-control languages, hardware design languages, and mark-up languages are usually developed with an emphasis on high-level application abstractions rather than on optimal performance. On the other hand, there is a strong case for formally specifying the syntax and semantics of DSLs [4]. The proposed aspect-oriented attribute grammar is a feasible formalism from which a DSL compiler, as well as related tools, (e.g., debuggers) [5] can be automatically generated.


Introduction
Attribute grammars were introduced by D. Knuth [1] and since then have proved to be useful in specifying the semantics of programming languages and in the automatic construction of compilers and interpreters. While implementation of programming languages is the original and most-widely recognized area of attribute grammars, they are also used in many other areas such as [2]: natural language interfaces, graphical user interfaces, visual programming, pattern recognition, hardware design, communication protocols, software engineering, static analysis of programs, databases, etc. However, only a few commercial compilers have been developed using attribute grammars as a design and implementation tool. It has been argued that attribute grammars are unsuitable for the production of high-speed compilers for general-purpose programming languages, since they are just a model of compilation and, thus, too primitive for real engineering discipline, and that they do not directly support the generation and optimization of machine code. The first problem is concerned with the pragmatic aspects of ordinary attribute grammars. Ordinary attribute grammars have deficiencies which become apparent in specifications for real programming languages. Such specifications are large, unstructured, and hard to understand, modify and maintain. Yet worse still, small modifications of some parts in the specification have widespread effects on the other specification parts. There has been a lot of research work on augmenting ordinary attribute grammars with extensions in order to overcome the deficiencies of attribute grammars, such as lack of modularity, extensibility and reusability. Several concepts, such as remote attribute access, object-orientation, templates, rule models, symbol computations, high order features etc., have been implemented in various attribute grammar specification languages. This problem is still insufficiently solved, despite all these different approaches. The aspectoriented attribute grammar, introduced in this paper, is proposed to better solve this problem. In aspect-oriented attribute grammar, concepts from aspect-oriented programming [3] have been integrated with attribute grammars. Aspect-oriented programming is a recently proven approach for describing crosscutting concerns in a modular manner. The second problem of attribute grammars, the lack of proper support for code generation and optimization, has also been insufficiently solved as yet and is out of the scope of this paper. An immediate conclusion might be, however, that attribute grammars are more appropriate in the design and implementation of Domain-Specific Languages (DSLs) [4] rather than for development of conventional optimizing compilers. Domain-specific languages, such as database query languages, robot-control languages, hardware design languages, and mark-up languages are usually developed with an emphasis on high-level application abstractions rather than on optimal performance. On the other hand, there is a strong case for formally specifying the syntax and semantics of DSLs [4]. The proposed aspect-oriented attribute grammar is a feasible formalism from which a DSL compiler, as well as related tools, (e.g., debuggers) [5] can be automatically generated.

Attribute grammars
Attribute grammars are a generalization of Context-Free Grammars (CFGs) in which each symbol has an associated set of attributes that carry semantic information. Attribute values are defined by attribute evaluation rules associated with each production of context-free grammar. These rules specify how to compute the values of certain attribute occurrences as a function of other attribute occurrences. Semantic rules are localized to each contextfree grammar production. Formally an attribute grammar consists of three components, a context-free grammar G, a set of attributes A, and set of semantic rules R AG = (G, A, R).
(1) symbol, which appear only on the left-hand side of the first production rule; and P is a set of productions (P = {p 0 , p 1 , ..., p z }, z > 0) in which elements (also called grammar symbols) of set VNT appear in the form of pairs X, where XN and V*. An empty right-hand side of production is denoted by the symbol . A set of attributes A(X) is associated with each symbol XV. A(X) is divided into two mutually disjointed subsets I(X) of inherited attributes and S(X) of synthesized attributes. Now A = A(X).
A set of semantic rules R is defined within the scope of a single production. A production pP, p:X 0 X 1 ...X n (n0) has an attribute occurrence X i .a if aA(X i ), 0in. A finite set of semantic rules R p contains rules for computing values of attributes that occur in the production p, i.e., it contains exactly one rule for each synthesized attribute X 0 .a and exactly one rule for each inherited attribute X i .a, 1in. Thus R p is a collection of rules of the form X i .a = f(y 1 , ..., y k ), k0, where y j , 1jk, is an attribute occurrence in p and f is a semantic function. In the rule X i .a = f(y 1 , ..., y k ), the occurrence X i .a depends on each attribute occurrence y j , 1jk. Now set R = R p . For each production pP, p:X 0 X 1 ...X n (n0) the set of defining attribute occurrences is DefAttr(p)={X i .a|X i .a=f(...)R p }. An attribute X.a is called synthesized (X.aS(X)) if there exists a production p:XX 1 ...X n and X.aDefAttr(p). It is called inherited (X.aI(X)) if there exists a production q:YX 1 ...X...X n and X.aDefAttr(q).
The meaning of a program (values of the synthesized attributes of starting non-terminal symbol) is defined during the attribute evaluation process where the values of attribute occurrences are calculated for each node of an attributed tree of a particular program. More details about attribute grammars can be found in [1,2].

Aspect-oriented attribute grammars
Several extensions of attribute grammars have been proposed [2,6], where authors have tried to improve the modularity and reusability of attribute grammars. However, some problems still remain or haven't been sufficiently solved yet. In this section we propose an extension of attribute grammars with features known from aspect-oriented programming [3], in order to address some of these problems.
Aspect-oriented programming provides a way of modularizing crosscutting concerns. Crosscutting concerns can be found in various representations of software artifacts and in different steps of software life cycle (e.g., source code, models, requirements, language grammars), and attribute grammars are no exception. If we take a closer look at extensibility and reusability of language specifications as written in attribute grammars, we discover several points where the features of new language cannot be specified modularly (specifications of semantics of new language crosscut with basic specifications). There are certain types of language extensions (e.g., type checking, environment propagation, code generation) that may require changes in many (if not all) of the grammar productions. Because language specifications are also used to generate parsers, compilers, and language-based tools automatically (e.g., editors, type checkers, and debuggers) [7], the various concerns associated with each language tool are often scattered throughout the core language specification. Such language extensions for supporting tool generation emerge as aspects that crosscut language components. As such, these concerns often represent refinements over the structure of the grammar. Note, that we are only dealing with the crosscutting concerns of semantic part of specifications. The problem of extending/modularizing the syntax part of specifications is already sufficiently solved using mechanisms such as inheritance and templates in attribute grammars [8].
An important part of aspect-oriented languages is the join-point model (JPM). If we want to extend attribute grammars with aspect-oriented paradigms we should define the join-point model first. Since attribute grammar specifications are non-executable and declarative, joinpoints are static points where additional semantics might be applied. In attribute grammars semantics is specified within the scope of a single production. Therefore, joinpoints are grammar productions. The aspect part of specifications is defined within the advice and advice application part. Semantic concepts that crosscut basic grammar structures are defined in advice, and are further applied to join-points (defined by pointcuts) using the advice application part of specifications [10].
The definition of Aspect-Oriented Attribute Grammar (AOAG) starts here, but the reader is kindly invited to check the example given in the next section while reading the definition. AOAG is an attribute grammar (AG) extended with pointcut specifications, advice specifications and the advice application part. AOAG is, therefore, defined as AOAG = (G, A, R, Pc, Ad, Aa). ( A set of pointcuts Pc is a set of pointcut productions, Pc = {pc 1 , ..., pc m }, where pointcut production pc i , 1im, is used to match a set of grammar productions. Pointcut production has the form pName : LeftSRightS, where pName is an unique identifier, LeftS is the matching rule for the lefthand side non-terminal of a grammar production, and RightS is the matching rule for right-hand side of a grammar production. A pointcut production pName : LeftSRightS, selects a production pP, p : where aName is an unique identifier, symbols F r VA, r0, are formal parameters in semantic rules (Rs v ) specified in advice ad k , and Rs v , v0 is a set of semantic rules with following form: Rs v = {X j .a = f(y 1 , ..., y k ) | aA(X j ), y i A(X 0 )...A(X n ), 0ik}, where X 0 , ..., X n are non-terminal symbols from grammar production matched by a pointcut. The abstractions of semantic rules that are independent of the production rules structure can be specified in the body of advice. These abstractions can be used for specifying common patterns in language specifications, such as value distribution, value construction, bucket brigade, list distribution, and many others. Two additional pseudo-identifiers have been defined for this reason. Pseudo-identifiers LHS and RHS denote a left-hand side non-terminal, and a list of the righthand side non-terminal symbols of a production. Last component, Aa is a set of advice application statements, Aa={aa 1 ,...,aa t }, where advice application statement aa u , 1ut, has the following form apply aName < S 1 , ..., S q > on pName, where apply is a reserved word, aName is the name of existing advice specification, pName is the name of existing pointcut specification, and S q VA, q0, is a set of actual parameters which are substituted with formal parameters of Ad during aspect weaving. Aspect weaving is a process of composing core functionality modules with aspects, thereby yielding a working system. Attribute grammar aspect weaving is, therefore, a process of formulating monolite attribute grammar specifications from core specifications and additional modules and aspects. There are many different mechanisms for weaving. We propose static weaving for aspect oriented attribute grammars, which means final attribute grammar specifications are constructed from aspect-oriented specifications before attribute grammar specifications are further processed (e.g., by a compiler generator tool where the compiler is generated automatically). The weaving process in aspect-oriented attribute grammars is defined as follows. Defining attributes attached to symbols X j , 0jn, defined in Ad, are defined by semantic rules in Rs v . Advice ad k (aName) is weaved on pointcut pc i (pName), which match productions Pm i . For each matched production p i Pm i , the actual set of semantic rules Ra ki is obtained by replacing formal parameters F j (specified in ad k ) by actual parameters S j (specified in aa u ) in Rs v (number of actual parameters of aa u and formal parameters of ad k must be the same; q = r). The set of semantic rules Ra obtained from advice Ad and pointcuts Pc is defined as Ra =  k=1..l,i=1..m Ra ki (7) and needs to be weaved with core semantic rules Rp i to obtain well defined attribute grammar AG = (G, A, R') in the following manner: (G, A, R') = (G, A, R, Pc, Ad, Aa).
The weaving algorithm is presented in Fig. 1 (the input of the algorithm is aspect-oriented attribute grammar).
for u = 1 to t do // find matching pair (advice, pointcut) advice pointcut = find matching pair(aau); ad = advice_pointcut.get advice(); pc = advice_pointcut.get pointcut()); // find a list of matching production rules P = match(pc); for x = 1 to P.size() do // substitute formal parameters of advice with // actual parameters // apply semantic rules to a grammar production rule // obtained by P.get(x) weave(ad, P.get(x)); end for end for Fig. 1. The weaving algorithm

An example
Some of the benefits regarding the aspect-oriented features of attribute grammars can be observed in the following small example. It can be observed that aspectoriented features are very useful for extending language semantics in a modular manner thus avoiding repetition of the same semantic rules in many grammar productions. Another useful feature is generic advice specifications which can be applied to many syntax-independent grammar productions. Note, that this is a small example for proof of concept. The benefits are more extensive for larger languages [9]. The first part of the example presents ordinary attribute-grammar specifications. Each production has semantic rules which define attributes x (synthesized attribute) and y (inherited attribute). The attribute x represents the total number of symbols 'a','b','c', and 'd' in a given string, where the symbols 'a' and 'b' count once, the symbol 'c' twice, and the symbol 'd' three times.The pointcuts (pc 1 , ..., pc 5 ) match productions where additional semantics from advice can be attached to original productions. Special wildcard symbols ('..', '*') can be used for defining LeftS and RightS matching rule in pointcut production pc i . Wildcard symbol '*' denotes a grammar symbol or some part of its name and can be used in the LeftS and RightS. Wildcard symbol '..' denotes zero or more grammar symbols V, and can be used only in the RightS. The pointcuts (pc 1 , ..., pc 5 ) match productions where additional semantics from advice can be attached to original productions. The 'advice' part of example shows advice (ad 1 , ..., ad 4 ) with semantics. Semantics of ad 4 is a generic abstraction of semantic rules and presents a value distribution pattern. In the 'apply' part of the example apply rules are presented. The final part of example shows results after weaving advice semantics to selected productions. As can be seen from the example, advice ad 3 is applied to three different pointcuts which match different productions. This is possible due to parameterization of the advice and advice application part. Fig. 2 depicts the semantic tree of ordinary attribute grammar before additional semantic rules are added using aspect-oriented approach. The semantic tree after weaving is depicted in Fig. 3. As can be seen from the figures, many semantic operations can be added easily in a modular way, using the aspect-oriented attribute grammars.

Experiences and conclusions
The proposed aspect-oriented attribute grammars have already been implemented and incorporated into our compiler-generator tool LISA (Fig. 4). LISA tool is also suitable for lifelong learning courses [9] and it is available at marcel.uni-mb.si/lisa. From initial experiments in the implementation of various small domain-specific languages, we have noticed several benefits of aspectoriented attribute grammar specifications. Such specifications are not only shorter but, more importantly, more modular and reusable. Repetition of semantic rules can be completely avoided and several generic modules can easily be reused. The initial study shows that a developer's effort decreases down to 50% [10], which is encouraging enough to proceed with our research.
In this paper, aspect-oriented attribute grammars have been proposed and formally defined with the aim of better addressing crosscutting concerns that appear in language specifications (e.g. environment propagation, code generation, additional semantic rules needed to generate various language-based tools). Such specifications become more modular and reusable. The proposed aspect-oriented attribute grammars is a feasible formalism from which a DSL compiler [4,11,12] can be automatically generated, as well as related tools such as editors, simulators, and animators [13]. The approach can be useful also in modeldriven engineering where code is automatically generated from models [14][15][16].