Presentation is loading. Please wait.

Presentation is loading. Please wait.

Semantic Analysis Attribute Grammar. Semantic Analysis  Beyond context free grammar  Is x declared before it is used?  Is x declared but never used?

Similar presentations


Presentation on theme: "Semantic Analysis Attribute Grammar. Semantic Analysis  Beyond context free grammar  Is x declared before it is used?  Is x declared but never used?"— Presentation transcript:

1 Semantic Analysis Attribute Grammar

2 Semantic Analysis  Beyond context free grammar  Is x declared before it is used?  Is x declared but never used?  Is an expression type consistent?  Is an array reference in bounds?  …

3 Attribute Grammar  Augment context free grammar with attributes and rules  Each grammar symbol has an associated set of attributes  Cloud be empty  Each attribute has a data type and value range  Attributes are evaluated by the semantic rules of the productions  The rule is evaluated when reduction happens during LR parsing  E.g., The rules you added to yacc input file for building a parse tree (informal)  Syntax directed translation  Attribute grammar translates input string to sequence of actions  From syntax (input string) to semantics (actions)  Type checking  Generate intermediate code or representation

4 Attribute Grammar  Example  Expression evaluation L  Eprint(E.val) E  E 1 + TE.val := E 1.val + T.val E  TE.val := T.val T  T 1 * FT.val := T 1.val * F.val T  FT.val := F.val F  ( E ) F.val := E.val F  digitF.val := digit.lexval By the way, now you see why we do not like to do left recursion elimination and left factoring. It will be more difficult to write attribute rules for an incomprehensible grammar.

5 L  E print(E.val) E  E 1 + TE.val := E 1.val + T.val E  TE.val := T.val T  T 1 * FT.val := T 1.val * F.val T  FT.val := F.val F  ( E ) T.val := E.val F  digitF.val := digit.lexval E +TE T *FT F digit F digit = 3 F.val = 3 digit = 4 F.val = 4 digit = 2 F.val = 2 T.val = 2 T.val = 6 E.val = 6 T.val = 4 E.val = 10 Input: 2 * 3 + 4

6 Semantics and Attribute Grammar  Semantics  Give the meaning of the language  What is this? S  (T), T  F T N | N F  a! | b!, N  num  Input: (a! b! a! 5 3 2 6)  With the attributed grammar S  (T)print (T.list) T  NT.list := [N.val] T  F T 1 N if (F.op = a) T.list := append (T 1.list, N.val) if (F.op = b) T.list := removeLastN (T 1.list, N.val) F  a! F.op := a F  b!F.op := b N  numN.val := num S ( T ) FTN FTN FT N a! b! a! 5 3 2 6 N Remove last N.val elements from T 1.list

7 Semantics and Attribute Grammar  Semantics  Give the meaning of the language  What is this? S  (T), T  F T N | N F  a! | b!, N  num  Input: (a! b! a! 5 3 2 6)  With the attributed grammar S  (T)print (T.val) T  F T 1 N T.val := T 1.val E.op N.val T  NT.val := N.val F  a! F.op := + F  b!F.op := * N  numN.val := num S ( T ) FTN FTN FT N a! b! a! 5 3 2 6 N Attributed grammar defines the meaning for the production rules Which gives the meaning for the input program

8 Build Parse Tree  Parse tree construction  Can be done with only synthesized attributes:  child: first child pointer  sib: right sibling pointer  addr: parse tree node address S  ABS.addr = new-node(S) S.child = A.addr; A.sib = B.addr; A  CdEA.addr = new-node(A); d.addr = new-node(d); A.child = C.addr; C.sib = d.addr; d.sib = E.addr; A  FA.addr = new-node(A) A.child = F.addr; B  EFB.addr = new-node(B) B.child = E.addr; E.sib = F.addr……

9 Build Parse Tree  Parse tree construction example L  E L.addr = new-node(L); L.child = E.addr; E  E 1 + TE.addr := new-node(E); add.addr = new-node(+); E.child = E 1.addr; E 1.sib = add.addr; add.sib = T.addr; E  TE.addr = new-node(E); E.child := T.addr; T  digitT.addr = new-node(T); T.child = new-node(digit);

10 L  E L.addr = new-node(L); L.child = E.addr; E  E 1 + T E.addr := new-node(E); add.addr = new-node(+); E.child = E 1.addr; E 1.sib = add.addr; add.sib = T.addr; E  T L.addr = new-node(L); E.child := T.addr; T  digit T.addr = new-node(T); T.child = new-node(digit); E + TE +TE T digit Input: 1 + 2 + 3 Reverse of rightmost derivation L   E E   E + T E   T T   digit

11 L  E L.addr = new-node(L); L.child = E.addr; E  E 1 + T E.addr := new-node(E); add.addr = new-node(+); E.child = E 1.addr; E 1.sib = add.addr; add.sib = T.addr; E  T L.addr = new-node(L); E.child := T.addr; T  digit T.addr = new-node(T); T.child = new-node(digit); E + TE +TE T digit Input: 1 + 2 + 3 T  digit (1) L   E E   E + T E   T T   digit

12 L  E L.addr = new-node(L); L.child = E.addr; E  E 1 + T E.addr := new-node(E); add.addr = new-node(+); E.child = E 1.addr; E 1.sib = add.addr; add.sib = T.addr; E  T L.addr = new-node(L); E.child := T.addr; T  digit T.addr = new-node(T); T.child = new-node(digit); E + TE +TE T digit Input: 1 + 2 + 3 T  digit (1) E  T L   E E   E + T E   T T   digit

13 L  E L.addr = new-node(L); L.child = E.addr; E  E 1 + T E.addr := new-node(E); add.addr = new-node(+); E.child = E 1.addr; E 1.sib = add.addr; add.sib = T.addr; E  T L.addr = new-node(L); E.child := T.addr; T  digit T.addr = new-node(T); T.child = new-node(digit); E + TE +TE T digit Input: 1 + 2 + 3 T  digit (1) E  T Shift + T  digit (2) L   E E   E + T E   T T   digit

14 L  E L.addr = new-node(L); L.child = E.addr; E  E 1 + T E.addr := new-node(E); add.addr = new-node(+); E.child = E 1.addr; E 1.sib = add.addr; add.sib = T.addr; E  T L.addr = new-node(L); E.child := T.addr; T  digit T.addr = new-node(T); T.child = new-node(digit); E + TE +TE T digit Input: 1 + 2 + 3 T  digit (1) E  T Shift + T  digit (2) E  E 1 + T L   E E   E + T E   T T   digit How to keep track of the values of E and T - Keep them with the symbols in the parsing stack - In Yacc, user can define stack type - $$, $1, $2, $3  $1.ptr = …, $3.ptr = …

15 L  E L.addr = new-node(L); L.child = E.addr; E  E 1 + T E.addr := new-node(E); add.addr = new-node(+); E.child = E 1.addr; E 1.sib = add.addr; add.sib = T.addr; E  T L.addr = new-node(L); E.child := T.addr; T  digit T.addr = new-node(T); T.child = new-node(digit); E + TE +TE T digit Input: 1 + 2 + 3 T  digit (1) E  T Shift + T  digit (2) E  E 1 + T Shift + T  digit (3) L   E E   E + T E   T T   digit

16 L  E L.addr = new-node(L); L.child = E.addr; E  E 1 + T E.addr := new-node(E); add.addr = new-node(+); E.child = E 1.addr; E 1.sib = add.addr; add.sib = T.addr; E  T L.addr = new-node(L); E.child := T.addr; T  digit T.addr = new-node(T); T.child = new-node(digit); E +TE +TE T digit Input: 1 + 2 + 3 T  digit (1) E  T Shift + T  digit (2) E  E 1 + T Shift + T  digit (3) E  E 1 + T L   E E   E + T E   T T   digit

17 Yacc and Attribute Grammar  Similar to attribute grammar  Follow the LR parsing technique (actually LALR)  At reduction time, perform the specified action  Maintain the stack in LR parsing  Yacc maintains two stacks during parsing  Parse stack  Contains terminals and nonterminals and state inforamtion, just like LR parsing  Value stack  Associates a value with each element in the parse stack  Default type of the value stack content is integer, can be changed to other types using “Union” in the definition section  User can only manipulate value stack, not parse stack

18 Attribute Grammar  Two types of attributes  Synthesized attributes  Attribute values are evaluated from bottom up  The value of the parent is defined on the values of the children  Inherited attributes  Attribute values are evaluated from top down  The value of a node is defined on the values of its parent and/or siblings  Attribute rules  Only reference local information  only refer to symbols in the corresponding production DEF A DEF A

19 S-Attribute Grammar  Only has synthesized attributes  Suitable for shift-reduce parsing  Example  Expression evaluation L  Eprint(E.val) E  E 1 + TE.val := E 1.val + T.val E  TE.val := T.val T  T 1 * FT.val := T 1.val * F.val T  FT.val := F.val F  ( E ) F.val := E.val F  digitF.val := digit.lexval lexval: value from lex Derive parent’s value from children’s values E + T E T digit F T F F * Derive parent’s value from children’s values

20 Inherited Attributes  Example  Adding type to symbol table D  TLL.type := T.type T  intT.type := integer T  realT.type := real L  L 1, idL 1.type := L.type; addtype (id.entry, L.type) L  idaddtype (id.entry, L.type)  Id.entry is the entry to the symbol table L 1 ’s attribute value “type” depends on its parent “type” value  “type” is an inherited attribute L’s attribute value “type” depends on left sibling T’s “type” Attribute “type” is still synthesized

21 D TL1L1 L2L2 id, L3L3, L 3.type = L 2.type T.type = int int L 1.type = T.type L 2.type = L 1.type addtype(id.entry, L 3.type) addtype(id.entry, L 2.type) addtype(id.entry, L 1.type) Dependency Graph D  TL L.type := T.type T  int T.type := integer T  real T.type := real L  L 1, id L 1.type := L.type, addtype (id.entry, L,type) L  id addtype (id.entry, L.type) Dependency specifies the evaluation order Input: int id, id, id

22 Dependency Graph  Evaluation based on the dependencies  Circularity check  Dependency graph should be acyclic  Build pass tree  Fist build the parse tree, then evaluate  Cannot be done with parsing, require a separate evaluation pass  Can we do better?  L-attributed grammar  Parser stack based technique  Marker nonterminals (not covered)  Rewrite grammar rules

23 Left-Attributed Grammar  L-attributed grammar  May have synthesized attributes  Has inherited attributes  For any production: A  X 1 X 2 … X n  Any attribute of X k only depends on the attributes of X 1, X 2, …, X k–1, and/or the inherited attributes of A oAll the symbols to the left  Earlier inherited attribute example is an L-attributed grammar D  T LL.type := T.type T  intT.type := integer T  realT.type := real L  L 1, idL 1.type := L.type, addtype (id.entry, L.type) L  idaddtype (id.entry, L.type)

24 Left-Attributed Grammar  What’s the importance of L-attributed grammar  The needed attribute value has already been evaluated Generally, not possible for the starting symbol to contribute to the attribute value D TL1L1 L2L2 id, L3L3, L 3.type = L 2.type T.type = int int L 1.type = T.type L 2.type = L 1.type addtype(id.entry, L 3.type) addtype(id.entry, L 2.type) addtype(id.entry, L 1.type) The attribute value comes from the left sibling  Already evaluated The attribute value comes from the parent More specifically, the parent’s left sibling  Also already evaluated But how to obtain the value even though it is already evaluated?

25 Technique based on Parser Stack  What’s the importance of L-attributed  The needed attribute value has already been evaluated  But how to obtain the value even though it is already evaluated?  From stack Input Stack Action real p, q, r $ shift p, q, r $ real T  real p, q, r $ T shift, q, r $ T p L  id, q, r $ T L shift q, r $ T L, shift, r $ T L, q L  L, id, r $ T L shift r $ T L, shift $ T L, r L  L, id $ T L D  TL $ D accept D  TL L.type := T.type T  int T.type := integer T  real T.type := real L  L 1, id L 1.type := L.type, addtype(…, L.type) L  id addtype (…, L.type)

26 Technique based on Parser Stack  What’s the importance of L-attributed  The needed attribute value has already been evaluated  But how to obtain the value even though it is already evaluated?  From stack Input Stack Action real p, q, r $ shift p, q, r $ real T  real p, q, r $ T shift, q, r $ T p L  id, q, r $ T L shift q, r $ T L, shift, r $ T L, q L  L, id, r $ T L shift r $ T L, shift $ T L, r L  L, id $ T L D  TL $ D accept D  TL L.type := T.type T  int T.type := integer T  real T.type := real L  L 1, id L 1.type := L.type, addtype(…, L.type) L  id addtype (…, L.type) T.type = real Obtain L 1.type by: + Knowing that T is below L type the stack + Knowing that L.type comes from the T.type + Obtain T.type directly T.type = real T is kept in the stack till the D reduction addtype (id.entry, L.type) In this case, T is 3 below

27 Technique based on Parser Stack  L-attributed grammar D  T LL.type = T.type T  intT.type = integer T  realT.type = real L  L 1, idL 1.type = L.type, addtype (id.entry, L.type) L  idaddtype (id.entry, L.type)  Convert to parser stack based attributes D  T L-- no longer need to do any action T  intval[top] := integer T  realval[top] := real L  L 1, idaddtype (id.entry, val[top–3].type) L  idaddtype (id.entry, val[top–1].type)

28 Inherited Attribute  Example: not an L-attributed grammar D  L : T L.type = T.type L  L 1, idL 1.type = L.type, addtype (id.entry, L.type) L  idaddtype (id.entry, L.type) T  intT.type = integer T  realT.type = real  Parse p, q, r : int  Inherited attribute  Needs two-pass evaluation  First build the parse tree  Then evaluate Depend on right sibling No longer L-attributed D T L1L1 L2L2 r, L3L3 q, p int :

29 Rewrite Grammar  Example: D  L : T T  int T  real L  L 1, id L  id  Rewrite the grammar D  id LD.type := L.type; addtype (id.entry, L 1.type) L , id L 1 L.type := L 1.type; addtype (id.entry, L 1.type) L  : TL.type := T.type T  intT.type := integer T  realT.type := real Force id’s to go into stack This grammar will reduce nothing till T presents When reduction starts, type information is ready Input Stack Action p, q: real $ shift (D   id  L), q: real $ p shift (L  ,  id L) q: real $ p, shift (L ,  id  L) : real $ p, q shift (L   :  T) real $ p, q: shift (T   real  ) $ p, q: real reduce (T  real) $ p, q: T reduce (L  : T) $ p, q L reduce (L , id L) $ p L reduce (D  id L) $ D accept Upon reduction Type infor is ready

30 Issues in Attributed Grammar  Attribute rules are confined to local production info  Only allow references to local symbols  May have a lot of copying A  aBA.u := B.u + h3(a); print (A.u, B.v); B  bCB.u := C.u; B.v := C.v + g3(b) C  cDC.u := D.u + h2(c); C.v := D.v D  dEFD.u := E.u; D.v := F.v + g2(d) E  eE.u := h1(e) F  fF.v := g1(f)  Both u and v are synthesized attributes  A.u is computed from C.u and E.u  B.v is computed from D.v and F.v  D.u := E.u, C.v := D.v, B.u := C.u are only for value passing Can something be done to save the copying effort?  Use global table Is global attribute worse than stack technique?

31 Issues in Attributed Grammar A  aB A.u := B.u + h3(a); print (A.u, B.v); B  bC B.u := C.u; B.v := C.v + g3(b) C  cD C.u := D.u + h2(c); C.v := D.v D  EF D.u := E.u; D.v := F.v E  e E.u := h1(e) F  f F.v := g1(f) Can something be done to save the copying effort?  Use global variable Is global variable worse than stack technique? A B a Cb Dc E F e f

32 Issues in Attributed Grammar  Attribute rules are confined to local production info  Excessive copying due to production rules in the grammar E  E 1 + TE.val := E 1.val + T.val E  TE.val := T.val T  T 1 * FT.val := T 1.val * F.val T  FT.val := F.val F  ( E ) T.val := E.val F  digitF.val := id.digit  E  T, T  F causes additional copying of val attribute Can something be done to save the copying effort?  Use global variable

33 Issues in Attributed Grammar  Attribute rules are confined to local production info  Not able to optimize  Need to build the parse tree  Need to have a separate optimization phase  Requires tree traversal E +E T *FT b a F T *FT b a F * * Reuse the result

34 Semantic Analysis -- Summary  Read Chapters 5 and 6  Sections 5.1, 5.2, 5.3, 5.4, 5.5  Section 6.1, 6.2, 6.3, 6.4, 6.6, 6.7, 6.8, 6.9  Attributes and attribution rules  Synthesized and inherited attributes  S-attributed grammar  L-attributed grammar  Hack to the parser stack  Rewrite grammar rules  Efficiency issues -- Excessive copying  Intermediate code generation  For various types of statements


Download ppt "Semantic Analysis Attribute Grammar. Semantic Analysis  Beyond context free grammar  Is x declared before it is used?  Is x declared but never used?"

Similar presentations


Ads by Google