Review Symbol Tables in JastAdd • What is a symbol table used for? • Determining the origin and the Andrew Casey properties of a given symbol Review Attribute Grammars • What goes in a symbol table? • Name • Introduced by Knuth as a way to specify • Definition site programming language semantics • Type • Other annotations/attributes
Attribute Grammars Synthetic Attributes • An attribute is a function from parse tree • Attributes that depend on values in the nodes to a domain of your choosing descendants of a node are called synthetic attributes • The value of an attribute at a given node is • Synthetic attributes pass information up the defined in terms of the values of attributes of neighbouring nodes in the parse tree parse tree Inherited Attributes Example • Attributes that depend on values in the • From Knuth’s original paper ancestors of a node are called inherited • Suppose we want to determine a value for attributes the binary number XX...X.X...X, where X is • Inherited attributes pass information down a single bit the parse tree
Grammar Approach 1 B → 0 B → 1 • Use only synthetic attributes L → B • Each subtree is independent L → LB N → L N → L . L Approach 1 Approach 1 B → 0 v(B) = 0 v = 2 + 3/4 = 2.75 N B → 1 v(B) = 1 v = 2 v = 3 l = 2 . l = 2 L L L → B v(L) = v(B); l(L) = 1 v = 1 v = 1 v(L 1 ) = 2v(L 2 ) + v(B); l(L 1 ) = l(L 2 ) + 1 L 1 → L 2 B L B L B v = 0 v = 1 l = 1 l = 1 v(N) = v(L) N → L B B 0 1 v = 1 v = 1 v(N) → v(L 1 ) + v(L 2 )/2 l(L2) N → L 1 . L 2 1 1
Approach 2 Approach 2 B → 0 v(B) = 0 B → 1 v(B) = 2 s(B) • Use inherited attributes to make things v(L) = v(B); l(L) = 1(B); s(B) = s(L) L → B more intuitive (i.e. close to our mental v(L 1 ) = v(L 2 ) + v(B); l(L 1 ) = l(L 2 ) + 1; L 1 → L 2 B model of how binary numbers work) s(L 2 ) = s(L 1 ) + 1; s(B) = s(L 1 ) • e.g. the ‘1’ in ‘100’ means ‘8’ v(N) = v(L); s(L) = 0 N → L v(N) → v(L 1 ) + v(L 2 ); s(L 1 ) = 0; s(L 2 ) = -l(L 2 ) N → L 1 . L 2 Approach 2 Approach 2 B → 0 B → 0 v(B) = 0 v(B) = 0 B → 1 v(B) = 2 s(B) B → 1 v(B) = 2 s(B) v(L) = v(B); l(L) = 1(B); s(B) = s(L) v(L) = v(B); l(L) = 1(B); s(B) = s(L) L → B L → B v(L 1 ) = v(L 2 ) + v(B); l(L 1 ) = l(L 2 ) + 1; v(L 1 ) = v(L 2 ) + v(B); l(L 1 ) = l(L 2 ) + 1; L 1 → L 2 B L 1 → L 2 B s(L 2 ) = s(L 1 ) + 1; s(B) = s(L 1 ) s(L 2 ) = s(L 1 ) + 1; s(B) = s(L 1 ) v(N) = v(L); s(L) = 0 v(N) = v(L); s(L) = 0 N → L N → L v(N) → v(L 1 ) + v(L 2 ); s(L 1 ) = 0; s(L 2 ) = -l(L 2 ) v(N) → v(L 1 ) + v(L 2 ); s(L 1 ) = 0; s(L 2 ) = -l(L 2 ) N → L 1 . L 2 N → L 1 . L 2
Approach 2 Practical Concerns v = 2 + 0.75 = 2.75 N v = 2 v = 0.75 • If information can move both up and down . s = 0 s = -2 L L l = 2 l = 2 the parse tree, then it is possible to define v = 2 v = 0 v = 0.5 v = 0.25 attributes cyclically! L B L B s = 1 s = 0 s = -1 s = -2 l = 1 l = 1 B B 0 1 v = 2 v = 0.5 s = 1 s = -1 1 1 Practical Concerns JastAdd • If we restrict ourselves to certain combinations of attributes, then we can compute their values more • An attribute grammar system for Java efficiently • Primarily used for creating extensible • Synthetic-only: single post-order pass compilers • Inherited-only: single pre-order pass • Primarily the work of Torbjörn Ekman • LR-attributed: single LR-parsing pass (i.e. by the time (Oxford) & Görel Hedin (Lund) a node is created, all values it depends on have already been computed).
JastAdd Abstract Syntax • Where does it fit? 1. You create a lexer and parser as usual • Since attributes are so interwoven with the (e.g. using flex and bison) abstract syntax, you have to use the 2. You specify an AST structure in JastAdd abstract syntax specification language provided by JastAdd to create your AST 3. You build the AST in the actions of your classes grammar 4. You decorate the AST with attributes Example Attributes abstract Expr; • Attributes are defined in separate files AddExpr : Expr ::= LHS:Expr RHS:Expr; (aspects) but are ultimately inserted into IDExpr : Expr ::= <Name>; the generated AST node classes NumExpr : Expr ::= <Value:int>;
Synthetic Attributes Inherited Attributes • inh ReturnType NodeType.Attribute(); • syn ReturnType NodeType.Attribute(); • eq ParentNodeType.getChild().Attribute() • eq NodeType.Attribute() = value; = value; Evaluated in the context of the parent node Extra Features JastAdd Symbol Tables • Reference attributes • Instead of building a separate symbol table, • Parameterized attributes just decorate the parse tree nodes • Broadcast inherited attributes
Example - Table Example - Attributes Symbol Type Decl Program Program A int . ⠇ ⠇ ⠇ Decl Expr Decl Expr type = int A decl = . A + 1 A A + 1 Lookup: table.lookup(“A”) returns a record Lookup: A.getDecl() returns a Decl node Detailed Example Detailed Example Listing Declarations: syn Set<Decl> ASTNode.listDecls(); • Synthetic attributes push declarations up to eq ASTNode.listDecls() { Set<Decl> decls = new HashSet<Decl>(); root node for(int i = 0; i < getNumChild(); i++) { • Inherited attributes push declarations down decls.addAll(getChild(i).listDecls()); } to use nodes return decls; } eq Decl.listDecls() = Collections.singleton(this);
Detailed Example Detailed Example Declaration Lookup: Lookup propagation: syn Decl Program.lookupDecl(String name) { for(Decl d : listDecls()) { inh Decl IDExpr.lookupDecl(String name); if(d.getName().equals(name)) { eq Parent .getIDExpr().lookupDecl(String name) = lookupDecl(name); return d; } Meta-Variable: substitute names of nodes with IDExpr children } return null; } Detailed Example Advantages Link to Decl: • Modularity syn Decl IDExpr.getDecl() = lookupDecl(getName()); • Extensibility • Laziness
Disadvantages Sources • D. Knuth, Semantics of context-free • Definition of structure is less centralized languages, Math. Sys. Theory , 2: 1 (1968), 127– 145. • May require more computation • http://jastadd.org/
Recommend
More recommend