Syntax Directed Translation
Beyond syntax analysis An identifier named x has been recognized. Is x a scalar, array or function? How big is x? If x is a function, how many and what type of arguments does it take? Is x declared before being used? Where can x be stored? Is the expression x+y type-consistent? Semantic analysis is the phase where we collect information about the types of expressions and check for type related errors. The more information we can collect at compile time, the less overhead we have at run time.
Semantic analysis Collecting type information may involve "computations" What is the type of x+y given the types of x and y? Tool: attribute grammars Each grammar symbol has a number of associated attributes: The type of a variable or expression The value of a variable or expression The code for a statement The grammar is augmented with special equations (called semantic actions) that specify how the values of attributes are computed from other attributes. The process of using semantic actions to evaluate attributes is called syntax-directed translation.
Syntax Directed Translation Syntax = form, Semantics = meaning Use the syntax to derive semantic information. Attribute grammar: Context free grammar augmented by a set of rules Each symbol in the derivation has a set of values, or attributes The rules specify how to compute a value for each attribute
Attribute Grammars Associate attributes with tree nodes (internal and leaf). Rules describe how to compute value of attributes in tree (possibly using other attributes in the tree) Two types of attributes based on how value is calculated (Synthesized & Inherited)
Attribute Grammar Production E E 1 + T E T T T 1 * T num ( E ) Semantic Actions E.val = E 1.val + T.val E.val = T.val T.val = T 1.val *.val T.val =.val.val = value(num).val = E.val Each node has single integer attribute val
Synthesized Attributes Synthesized attributes the value of a synthesized attribute for a node is computed using only information associated with the node and the node s children (or the lexical analyzer for leaf nodes). Example: Production Semantic Rules A B C D A.a := B.b + C.e
Example Problems for Synthesized Expression grammar given a valid expression (ex: 1 * 2 + 3), determine the associated value while parsing. Grid Given a starting location of 0,0 and a sequence of north, south, east, west moves (ex: NESNNE), find the final position on a unit grid.
Synthesized Attributes Expression Grammar Production E E 1 + T E T T T 1 * T num ( E ) Semantic Actions E.val = E 1.val + T.val E.val = T.val T.val = T 1.val *.val T.val =.val.val = value(num).val = E.val
Synthesized Attributes Annotating the parse tree Production Semantic Actions E E 1 + T E.val = E 1.val + T.val E T E.val = T.val T T 1 * T.val = T 1.val *.val T T.val =.val num.val = value(num) ( E ).val = E.val Input: 2 * 3 + 4 E E + T T T * Val = Val = = 2 Val = Val = Val = = 3 Val = Val = Val = = 4
Synthesized Attributes Annotating the parse tree Production Semantic Actions E E 1 + T E.val = E 1.val + T.val E T E.val = T.val T T 1 * T.val = T 1.val *.val T T.val =.val num.val = value(num) ( E ).val = E.val Input: 2 * 3 + 4 E E + T T T * Val = 2 = 2 = 3 = 4
Synthesized Attributes Annotating the parse tree Production Semantic Actions E E 1 + T E.val = E 1.val + T.val E T E.val = T.val T T 1 * T.val = T 1.val *.val T T.val =.val num.val = value(num) ( E ).val = E.val Input: 2 * 3 + 4 E E + T T T * Val =2 Val = 2 = 2 = 3 = 4
Synthesized Attributes Annotating the parse tree Production Semantic Actions E E 1 + T E.val = E 1.val + T.val E T E.val = T.val T T 1 * T.val = T 1.val *.val T T.val =.val num.val = value(num) ( E ).val = E.val Input: 2 * 3 + 4 E E + T T T * Val =2 Val = 2 = 2 Val = 3 = 3 = 4
Synthesized Attributes Annotating the parse tree Production Semantic Actions E E 1 + T E.val = E 1.val + T.val E T E.val = T.val T T 1 * T.val = T 1.val *.val T T.val =.val num.val = value(num) ( E ).val = E.val Input: 2 * 3 + 4 E E + T T T * Val =2 Val = 2 = 2 Val =2*3=6 Val = 3 = 3 = 4
Synthesized Attributes Annotating the parse tree Production Semantic Actions E E 1 + T E.val = E 1.val + T.val E T E.val = T.val T T 1 * T.val = T 1.val *.val T T.val =.val num.val = value(num) ( E ).val = E.val Input: 2 * 3 + 4 E E + T T T * Val =2 Val = 2 = 2 Val =6 Val =6 Val = 3 = 3 = 4
Synthesized Attributes Annotating the parse tree Production Semantic Actions E E 1 + T E.val = E 1.val + T.val E T E.val = T.val T T 1 * T.val = T 1.val *.val T T.val =.val num.val = value(num) ( E ).val = E.val Input: 2 * 3 + 4 E E + T T T * Val =2 Val = 2 = 2 Val =6 Val =6 Val = 3 = 3 Val =4 = 4
Synthesized Attributes Annotating the parse tree Production Semantic Actions E E 1 + T E.val = E 1.val + T.val E T E.val = T.val T T 1 * T.val = T 1.val *.val T T.val =.val num.val = value(num) ( E ).val = E.val Input: 2 * 3 + 4 E E + T T T * Val =2 Val = 2 = 2 Val =6 Val =6 Val = 3 = 3 Val =4 Val =4 = 4
Synthesized Attributes Annotating the parse tree Production Semantic Actions E E 1 + T E.val = E 1.val + T.val E T E.val = T.val T T 1 * T.val = T 1.val *.val T T.val =.val num.val = value(num) ( E ).val = E.val Input: 2 * 3 + 4 E E + T T T * Val =2 Val = 2 = 2 Val =6 Val =6 Val = 3 = 3 Val =6 + 4 = 10 Val =4 Val =4 = 4
Synthesized Attributes Annotating the parse tree Production Semantic Actions E E 1 + T E.val = E 1.val + T.val E T E.val = T.val T T 1 * T.val = T 1.val *.val T T.val =.val num.val = value(num) ( E ).val = E.val Input: 2 + 3* 4 E E + T T Val = Val = Val = = 2 Val = T * Val = Val = = 3 Val = Val = = 4
Synthesized Attributes Annotating the parse tree Production Semantic Actions E E 1 + T E.val = E 1.val + T.val E T E.val = T.val T T 1 * T.val = T 1.val *.val T T.val =.val num.val = value(num) ( E ).val = E.val Input: 2 + 3 * 4 E E + T T Val =2 = 2 Val =2 Val =2 Val =14 T * Val =3 Val =3 = 3 Val =12 Val =4 = 4
Grid Example Given a starting location of 0,0 and a sequence of north, south, east, west moves (ex: NEENNW), find the final position on a unit grid. start final
Synthesized Attributes Grid Positions Production Semantic Actions seq seq 1 instr seq.x = seq 1.x + instr.dx seq.y = seq 1.y + instr.dy seq BEGIN seq.x = 0, seq.y = 0 instr NORTH instr.dx = 0, instr.dy = 1 instr SOUTH instr.dx = 0, instr.dy = -1 instr EAST instr.dx = 1, instr.dy = 0 instr WEST instr.dx = -1, instr.dy = 0
Synthesized Attributes Annotating the parse tree Production Semantic Actions seq seq 1 instr seq.x = seq 1.x + instr.dx seq.y = seq 1.y + instr.dy seq BEGIN seq.x = 0, seq.y = 0 instr NORTH instr.dx = 0, instr.dy = 1 instr SOUTH instr.dx = 0, instr.dy = -1 instr EAST instr.dx = 1, instr.dy = 0 instr WEST instr.dx = -1, instr.dy = 0 x= y= x= y= seq x= y= seq x= y= seq dx= dy= instr seq dx= dy= instr S dx= dy= instr S Input: BEGIN N W S S x= y= seq BEGIN dx= dy= instr N W
Synthesized Attributes Annotating the parse tree Production Semantic Actions seq seq 1 instr seq.x = seq 1.x + instr.dx seq.y = seq 1.y + instr.dy seq BEGIN seq.x = 0, seq.y = 0 instr NORTH instr.dx = 0, instr.dy = 1 instr SOUTH instr.dx = 0, instr.dy = -1 instr EAST instr.dx = 1, instr.dy = 0 instr WEST instr.dx = -1, instr.dy = 0 x=0 y=1 x=-1 y=1 seq x=-1 y=0 seq x=-1 y=01 seq dx=-1 dy=0 instr seq dx=0 dy=-1 instr S dx=0 dy=-1 instr S Input: BEGIN N W S S x=0 y=0 seq BEGIN dx=0 dy=1 instr N W
Inherited Attributes Inherited attributes if an attribute is not synthesized, it is inherited. Example: Production A B C D Semantic Rules B.b := A.a + C.b Convenient for expressing the dependence of a programming language construct in the context in which it appears inherited attribute can keep track of whether an identifier appears on the left or right side of an assignment inherited attribute can keep track of type information
Inherited Attributes Determining types Productions Decl Type Type int Type real 1, id id Semantic Actions.in = Type.type Type.type = INT T.type = REAL 1.in =.in, addtype(id.entry..in) addtype(id.entry,.in)
Inherited Attributes Example Productions Decl Type Type int Semantic Actions.in = Type.type Type.type = INT type= Decl Type in= Type real T.type = REAL 1, id id 1.in =.in, addtype(id.entry..in) addtype(id.entry,.in) int in=,, in= id = c id = b Input: int a,b,c id = a
Inherited Attributes Example Productions Decl Type Type int Type real 1, id id Input: int a,b,c Semantic Actions.in = Type.type Type.type = INT T.type = REAL 1.in =.in, addtype(id.entry..in) addtype(id.entry,.in) type=int Type int Decl in=int,, id = a in=int in=int id = c id = b
Example grammar ber Sign Sign + Bit Bit Bit 0 1 This grammar describes signed binary numbers We would like to augment it with rules that compute the decimal value of each valid input string
Examples or 1 or 101 ber Sign Bit 1 ber Sign Sign Bit Sign 1 Sign Bit 1 Sign 1 1 Sign ber Sign Bit 0 1 ber Sign 1 0 1 101 Bit Bit 1 Sign Bit Bit 0 1 1
Add rules to compute the decimal value of a signed binary number Productions Attribution Rules ber Sign.pos 0 If Sign.neg then ber.val.val else ber.val.val Sign + Sign.neg false Sign.neg true 0 1 Bit 1.pos 0.pos + 1 Bit.pos 0.pos 0.val 1.val + Bit.val Bit Bit.pos.pos.val Bit.val Bit 0 Bit.val 0 1 Bit.val 2 Bit.pos Symbol ber Sign Bit Attributes val neg pos, val pos, val
Rules + parse tree imply an attribute dependence graph Back to the Examples or 1 neg true Sign ber ber.val.val 1.pos 0.val Bit.val 1 One possible evaluation order: 1.pos 2 Sign.neg 3 Bit.pos 4 Bit.val 5.val 6 ber.val Bit Bit.pos 0 Bit.val 2 Bit.pos 1 Other orders are possible 1 Knuth suggested a data-flow model for evaluation Independent attributes first Others in order as input values become available Evaluation order must be consistent with the attribute dependence graph
Back to the Examples Sign ber neg: true val: 5 pos: 1 val: 4 pos: 0 val: 5 Bit pos: 0 val: 1 This is the complete attribute dependence graph for 101. It shows the flow of all attribute values in the example. Some flow downward pos: 2 val: 4 Bit pos: 1 val: 0 1 inherited attributes Some flow upward Bit 1 pos: 2 val: 4 0 or 101 synthesized attributes A rule may use attributes in the parent, children, or siblings of a node
The Rules of the Game Attributes associated with nodes in parse tree Rules are value assignments associated with productions Attribute is defined once, using local information Label identical terms in production for uniqueness Rules & parse tree define an attribute dependence graph Graph must be non-circular This produces a high-level, functional specification Synthesized attribute Depends on values from children Inherited attribute Depends on values from siblings & parent
Using Attribute Grammars Attribute grammars can specify context-sensitive actions Take values from syntax Perform computations with values Insert tests, logic, Synthesized Attributes Use values from children & from constants S-attributed grammars Evaluate in a single bottom-up pass Good match to LR parsing Inherited Attributes Use values from parent, constants, & siblings directly express context can rewrite to avoid them Thought to be more natural Not easily done at parse time We want to use both kinds of attribute
Evaluation Methods Dynamic, dependence-based methods Build the parse tree Build the dependence graph Topological sort the dependence graph Define attributes in topological order Rule-based methods Analyze rules at compiler-generation time Determine a fixed (static) ordering Evaluate nodes in that order Oblivious methods Ignore rules & parse tree Pick a convenient order (at design time) & use it (treewalk) (passes, dataflow)
Back to the Example ber Sign Bit Bit 1 Bit 0 1 or 101
Back to the Example ber val: Sign neg: pos: 0 val: pos: val: Bit pos: val: pos: val: Bit pos: val: 1 Bit pos: val: 0 1 or 101
Back to the Example ber val: 5 Inherited Attributes Sign neg: true pos: 0 val: 5 pos: 1 val: 4 Bit pos: 0 val: 1 pos: 2 val: 4 Bit pos: 1 val: 0 1 Bit pos: 2 val: 4 0 1 or 101
Back to the Example ber val: 5 Synthesized attributes Sign neg: true pos: 0 val: 5 pos: 1 val: 4 Bit pos: 0 val: 1 pos: 2 val: 4 Bit pos: 1 val: 0 1 Bit pos: 2 val: 4 0 1 or 101
Back to the Example ber val: 5 Synthesized attributes Sign neg: true pos: 0 val: 5 pos: 1 val: 4 Bit pos: 0 val: 1 pos: 2 val: 4 Bit pos: 1 val: 0 1 Bit pos: 2 val: 4 0 1 or 101
Back to the Example ber val: 5 If we show the computation... Sign neg: true pos: 0 val: 5 pos: 1 val: 4 Bit pos: 0 val: 1 & then peel away the parse tree... pos: 2 val: 4 Bit pos: 1 val: 0 1 Bit pos: 2 val: 4 0 1 or 101
Back to the Example val: 5 All that is left is the attribute dependence graph. neg: true pos: 0 val: 5 This succinctly represents the flow of values in the problem instance. pos: 2 val: 4 pos: 1 val: 4 pos: 1 val: 0 1 pos: 0 val: 1 The dynamic methods sort this graph to find independent values, then work along graph edges. pos: 2 val: 4 0 The rule-based methods try to discover good orders by analyzing the rules. 1 or 101 The oblivious methods ignore the structure of this graph. The dependence graph must be acyclic
Attribute Dependency An attribute b depends on an attribute c if a valid value of c must be available in order to find the value of b. The relationship among attributes defines a dependency graph for attribute evaluation. Dependencies matter when considering syntax directed translation in the context of a parsing technique.
Dependency Graph rom dependencies, we can construct dependency graph which shows the order in which evaluations must be performed assuming acyclic graph do topological ordering to evaluate nodes ni evaluate ni before nj nj is dependent on ni nj Algorithm : Refer Page 296 of Aho, Sethi and Ullman Text 45
Attribute Dependencies Production E E 1 + T E T T T 1 * T num ( E ) Semantic Actions E.val = E 1.val + T.val E.val = T.val T.val = T 1.val *.val T.val =.val.val = value(num).val = E.val Synthesized attributes dependencies always up the tree E E + T T Val = 2 = 2 Val = 2 Val = 2 Val = 14 T * Val = 3 Val = 3 = 3 Val = 12 Val = 4 = 4
Acyclic Dependency Graphs for Parse Trees A.a A X Y X.x Y.y A.a := f(x.x, Y.y) A.a X.x Y.y X.x := f(a.a, Y.y) Direction of A.a value dependence X.x Y.y Y.y := f(a.a, X.x)
Dependency graph E.val = 10 E E.val = 6 E + T T.val = 4 T.val = 6 T.val = 4 T.val = 2 T *.val = 3 digit digit = 4.val = 2 digit digit = 3 Dash edges shows the dependencies digit = 2 digit
Attribute Dependencies Productions Decl Type Type int Type real 1, id id Semantic Actions.in = Type.type Type.type = INT T.type = REAL 1.in =.in, addtype(id.entry..in) addtype(id.entry,.in) Type=int Type int Decl in=int addtype(b,int),, id = a in=int addtype(c,int) id = c id = b in=int addtype(a,int)
Dependency graph of declaration grammar D T.type = int T L1 L1.in = T.type int L2 L2.in = L1.in, id addtype(id.entry, L1.in) L.in = L.in L3, id addtype(id.entry, L2.in) id addtype(id.entry, L3.in) dashed edges show dependencies
Evaluation Order A topological sort of a directed acyclic graph (DAG) is any ordering m 1, m 2,, m n of the nodes of the graph, such that if m i m j is an edge then m i appears before m j Any topological sort of a dependency graph gives a valid evaluation order for the semantic rules
Input: real p,q D L.in=real 4 T L T.type=real L1.in=real 6, addtype(q,real) 5 real L, id 3 addtype(p,real) 7 id.entry=q 2 id parse tree id.entry=p 1 dependency graph
Synthesized Attributes and LR Parsing Synthesized attributes have natural fit with LR parsing Attribute values can be stored on stack with their associated symbol When reducing by production A a, both a and the value of a s attributes will be on the top of the LR parse stack!
Examples covered in Lecture Class 54