1 / 93

Syntax Directed Translation

Syntax Directed Translation. Chapter 5. LR(k) ≡ LR(1). Context-Free Languages. Context-free languages. Deterministic languages (LR(k)). LL(k) languages. Simple precedence languages. Operator precedence languages. LL(1) languages. The inclusion hierarchy for context-free languages.

Download Presentation

Syntax Directed Translation

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Syntax Directed Translation Chapter 5

  2. LR(k) ≡ LR(1) Context-Free Languages Context-free languages Deterministic languages (LR(k)) LL(k) languages Simple precedence languages Operator precedence languages LL(1) languages The inclusion hierarchy for context-free languages

  3. Context-Free Grammars Context-free grammars Floyd-Evans Parsable Unambiguous CFGs Operator Precedence LR(k) LL(k) • Operator precedence includes some ambiguous grammars • LL(1) is a subset of SLR(1) LR(1) LALR(1) SLR(1) LL(1) The inclusion hierarchy for context-free grammars LR(0)

  4. Beyond Syntax • There is a level of correctness that is deeper than grammar fie(a,b,c,d) int a, b, c, d; { … } fee() { int f[3],g[0], h, i, j, k; char *p; fie(h,i,“ab”,j, k); k = f * i + j; h = g[17]; printf(“<%s,%s>.\n”, p,q); p = 10; } What is wrong with this program? (let me count the ways …)

  5. Semantics • There is a level of correctness that is deeper than grammar fie(a,b,c,d) int a, b, c, d; { … } fee() { int f[3],g[0], h, i, j, k; char *p; fie(h,i,“ab”,j, k); k = f * i + j; h = g[17]; printf(“<%s,%s>.\n”, p,q); p = 10; } What is wrong with this program? (let me count the ways …) • declared g[0], used g[17] • wrong number of args to fie() •“ab” is not an int • wrong dimension on use of f • undeclared variable q • 10 is not a character string All of these are “deeper than syntax”

  6. Syntax-directed translation • In syntax-directed translation, we attach ATTRIBUTES to grammar symbols. • The values of the attributes are computed by SEMANTIC RULES associated with grammar productions. • Conceptually, we have the following flow: • In practice, however, we do everything in a single pass.

  7. Syntax-directed translation • There are two ways to represent the semantic rules we associate with grammar symbols. • SYNTAX-DIRECTED DEFINITIONS (SDDs) do not specify the order in which semantic actions should be executed • TRANSLATION SCHEMES explicitly specify the ordering of the semantic actions. • SDDs are higher level; translation schemes are closer to • an implementation

  8. Syntax-Directed Definitions

  9. Syntax-directed definitions • The SYNTAX-DIRECTED DEFINITION (SDD) is a generalization of the context-free grammar. • Each grammar symbol in the CFG is given a set of ATTRIBUTES. • Attributes can be any type (string, number, memory loc, etc) • SYNTHESIZED attributes are computed from the values of the CHILDREN of a node in the parse tree. • INHERITED attributes are computed from the attributes of the parents and/or siblings of a node in the parse tree.

  10. Attribute dependencies • Given a SDD, we can describe the dependencies between the attributes with a DEPENDENCY GRAPH. • A parse tree annotated with attributes is called an ANNOTATED parse tree. • Computing the attributes of the nodes in a parse tree is called ANNOTATING or DECORATING the tree.

  11. Form of a syntax-directed definition • In a SDD, each grammar production A -> α has associated with it semantic rules • b := f( c1, c2, …, ck ) • where f() is a function, and either • b is a synthesized attribute of A, and c1, c2, …, are attributes of the grammar symbols of α, or • b is an inherited attribute of one of the symbols on the RHS, and c1, c2, … are attributes of the grammar symbols of α • in either case, we say b DEPENDS on c1, c2, …, ck.

  12. Semantic rules • Usually we actually write the semantic rules with expressions instead of functions. • If the rule has a SIDE EFFECT, e.g. updating the symbol table, we write the rule as a procedure call. • When a SDD has no side effects, we call it an ATTRIBUTE GRAMMAR.

  13. Synthesized attributes • Synthesized attributes depend only on the attributes of • children. They are the most common attribute type. • If a SDD has synthesized attributes ONLY, it is called a S-ATTRIBUTED DEFINITION. • S-attributed definitions are convenient since theattributes can be calculated in a bottom-up traversal of the parse tree.

  14. Example SDD: desk calculator • ProductionSemantic Rule • L -> E newline print( E.val ) • E -> E1 + T E.val := E1.val + T.val • E -> T E.val := T.val • T -> T1 * F T.val := T1.val x F.val • T -> F T.val := F.val • F -> ( E ) F.val := E.val • F -> number F.val := number.lexval • Notice the similarity to the yacc spec from last lecture.

  15. Calculating synthesized attributes Input string: 3*5+4 newline Annotated tree:

  16. Inherited attributes • An inherited attribute is defined in terms of theattributes of the node’s parents and/or siblings. • Inherited attributes are often used in compilers for passing contextual information forward, for example, the type keyword in a variable declaration statement.

  17. Example SDD with an inherited attribute • Suppose we want to describe decls like “real x, y, z” • Production Semantic Rules • D -> T L L.in := T.type • T -> int T.type := integer • T -> real T.type := real • L -> L1, id L1.in := L.in • addtype( id.entry, L.in ) • L -> id addtype( id.entry, L.in ) • L.in is inherited since it depends on a sibling or parent. addtype() is just a procedure that sets the type field in the symbol table.

  18. Annotated parse tree for real id1, id2, id3 What are the dependencies?

  19. Dependency Graphs

  20. Dependency graphs • If an attribute b depends on attribute c, then attribute b has to be evaluated AFTER c. • DEPENDENCY GRAPHS visualize these requirements. • Each attribute is a node • We add edges from the node for attribute c to the node for attribute b, if b depends on c. • For procedure calls, we introduce a dummy synthesized attribute that depends on the parameters of the procedure calls.

  21. Dependency graph example • ProductionSemantic Rule • E -> E1 + E2 E.val := E1.val + E2.val • Wherever this rule appears in the parse, tree we draw:

  22. Example dependency graph

  23. Example dependency graph

  24. Finding a valid evaluation order • A TOPOLOGICAL SORT of a directed acyclic graph orders the nodes so that for any nodes a and b such that a -> b, a appears BEFORE b in the ordering. • There are many possible topological orderings for a DAG. • Each of the possible orderings gives a valid order for evaluation of the semantic rules.

  25. Example dependency graph

  26. S-Attributed Definitions • Given an SDD and a parse tree, it is easy to tell (by doing a topological sort) whether a suitable evaluation exists (and to find one). • However, a very difficult problem is, given an SDD, are there any parse trees with cycles in their dependency graphs, i.e., are there suitable evaluation orders for all parse trees. • Fortunately, there are classes of SDDs for which a suitable evaluation order is guaranteed. • SDD is S-attributed if every attribute is synthesized. • For these SDDs all attributes are calculated from attribute values at the children since the other possibility, the tail attribute is at the same node, is impossible since the tail attribute must be inherited for such arrows. • Thus no cycles are possible and the attributes can be evaluated by a postorder traversal of the parse tree.

  27. S-Attributed Definitions postorder (N) { for ( each child C of N, from the left ) postorder(C); evaluate the attributes associated with node N; } • Since postorder corresponds to the actions of an LR parser when reducing the body of a production to its head, it is often convenient to evaluate synthesized attributes during an LR parse.

  28. L-Attributed Definitions • Unfortunately, it is hard to live without inherited attributes. So we define a class that permits certain kinds of inherited attributes.

  29. L-Attributed Definitions • Case three must be handled specially whenever it occurs. • The tree on the previous slide illustrates what the first two cases look like and suggest why there cannot be any cycles. Definition: An SDD is L-Attributed if each attribute is either • Synthesized. • Inherited from the left, and hence the name L-attributed. If the production is A → X1X2...Xn, then the inherited attributes for Xj can depend only on • Inherited attributes of A, the LHS. • Any attribute of X1, ..., Xj-1, i.e. only on symbols to the left of Xj. • Attributes of Xj, *BUT* you must guarantee (separately) that these attributes do not by themselves cause a cycle.

  30. Evaluating L-Attributed Definitions • do a depth first traversal of the tree. • The first time you visit a node, evaluate its inherited attributes (since you will know the value of everything it depends on), • and the last time you visit it, evaluate the synthesized attributes. • Suppose we have a production A → B C D. Each of the four non-terminals has two attributes s, which is synthesized, and i, which is inherited. For each set of rules below, tell whether the rules are consistent with (i) an S-attributed definition, (ii) an L-attributed definition, (iii) any evaluation order at all. • A.s = B.i + C.i • A.s = B.i + C.s and D.i = A.i + B.s • A.s = B.s + D.s

  31. Semantic Rules with Controlled Side Effects • When we have side effects such as printing or adding an entry to a table we must ensure that we have not added a constraint to the evaluation order that causes a cycle. • For example, the left-recursive SDD shown in the table on the right propagates type information from a declaration to entries in an identifier table.

  32. Semantic Rules with Controlled Side Effects • The function addTypeadds the type information in the second argument to the identifier table entry specified in the first argument. Note that the side effect, adding the type info to the table, does not affect the evaluation order. • Draw the dependency graph

  33. Syntax Trees

  34. Application: syntax tree construction • One thing SDDs are useful for is construction of SYNTAX TREES. • Recall from Lecture 1 that a syntax tree is a condensed form of parse tree. • Syntax trees are useful for representing programming language constructs like expressions and statements. • They help compiler design by decoupling parsing from translation.

  35. Syntax trees • Leaf nodes for operators and keywords are removed. • Internal nodes corresponding to uninformative non-terminals are replaced by the more meaningful operators.

  36. SDD for syntax tree construction • We need some functions to help us build the syntax tree: • mknode(op,left,right) constructs an operator node with label op, and two children, left and right • mkleaf(id,entry) constructs a leaf node with label id and a pointer to a symbol table entry • mkleaf(num,val) constructs a leaf node with label num and the token’s numeric value val • Use these functions to build a syntax tree for a-4+c: • P1 := mkleaf( id, st_entry_for_a ) • P2 := …

  37. SDD for syntax tree construction • ProductionSemantic Rules • E -> E1 + T E.nptr := mknode( ‘+’, E1.nptr,T.nptr) • E -> E1 - T E.nptr := mknode( ‘-’, E1.nptr,T.nptr) • E -> T E.nptr := T.nptr • T -> ( E ) T.nptr := E.nptr • T -> id T.nptr := mkleaf( id, id.entry ) • T -> num T.nptr := mkleaf( num, num.val ) • Note that this is a S-attributed definition. • Try to derive the annotated parse tree for a-4+c.

  38. Evaluating SDDs Bottom-up

  39. Bottom-up evaluation of S-attributed defn • How can we build a translator for a given SDD? • For S-attributed definitions, it’s pretty easy! • A bottom-up shift-reduce parser can evaluate the (synthesized) attributes as the input is parsed. • We store the computed attributes with the grammar symbols and states on the stack. • When a reduction is made, we calculate the values of any synthesized attributes using the already-computed attributes from the stack.

  40. Bottom-up evaluation of S-attributed defns • In the scheme, our parser’s stack now stores grammar symbols AND attribute values. • For every production A -> XYZ with semantic rule A.a := f( X.x, Y.y, Z.z ), before XYZ is reduced to A, we should already have X.x Y.y and Z.z on the stack.

  41. Desk calculator example • If attribute values are placed on the stack as described, it is now easy to implement the semantic rules for the desk calculator. • ProductionSemantic RuleCode • L -> E newline print( E.val ) print val[top-1] • E -> E1 + T E.val := E1.val + T.val val[newtop] = val[top-2]+val[top] • E -> T E.val := T.val /*newtop==top, so nothing to do*/ • T -> T1 * F T.val := T1.val x F.val val[newtop] = val[top-2]+val[top] • T -> F T.val := F.val /*newtop==top, so nothing to do*/ • F -> ( E ) F.val := E.val val[newtop] = val[top-1] • F -> number F.val := number.lexval /*newtop==top, so nothing to do*/

  42. Desk calculator example • For input 3 * 5 + 4 newline, what happens? • Assume when a terminal’s attribute is shifted when it is. • InputStatesValuesAction • 3*5+4n shift • *5+4n number 3 reduce F->number • reduce T->F • shift • shift • reduce F->number • reduce T->T*F • reduce E->T • shift • shift • reduce F->number • reduce T->F • reduce E->E+T • shift • reduce E->En

  43. L-attributed definitions • S-attributed definitions only allow synthesized attributes. • We saw earlier that inherited attributes are useful. • But we prefer definitions that can be evaluated in one pass. • L-ATTRIBUTED definitions are the set of SDDs whose attributes can be evaluated in a DEPTH-FIRST traversal of the parse tree.

  44. Depth-first traversal • algorithm dfvisit( node n ) { • for each child m of n, in left-to-right order, do { • evaluate the inherited attributes of m • dfvisit( m ) • } • evaluate the synthesized attributes of n • }

  45. L-attributed definitions • If a definition can be evaluated by dfvisit() we say it is L-attributed. • Another way of putting it: a SDD is L-attributed if each INHERITED attribute of Xi on the RHS of a production A -> X1 X2… Xn depends ONLY on: • The attributes of X1, …, Xi-1 (to the LEFT of Xi in the production) • The INHERITED attributes of A. • Since S-attributed definitions have no inherited attributes, they are necessarily L-attributed.

  46. L-attributed definitions • Is the following SDD L-attributed? • ProductionSemantic Rules • A -> L M L.i := l(A.i) • M.i := m(L.s) • A.s := f(M.s) • A -> Q R R.i := r(A.i) • Q.i := q(R.s) • A.s := f(Q.s)

  47. Translation Schemes

  48. Translation schemes • Translation schemes are another way to describe syntax-directed translation. • Translation schemes are closer to a real implementation because the specify when, during the parse, attributes should be computed. • Example, for conversion of INFIX expressions to POSTFIX: • E -> T R • R -> addop T { print ( addop.lexeme ) } | ε • T -> num { print( num.val ) } • This translation scheme will turn 9-5+2 into 95-2+

  49. Turning a SDD into a translation scheme • For a translation scheme to work, it must be the case that an attribute is computed BEFORE it is used. • If the SDD is S-attributed, it is easy to create the translation scheme implementing it: • ProductionSemantic Rule • T -> T1 * F T.val := T1.val x F.val • Translation scheme: • T -> T1 * F { T.val = T1.val * F.val } • That is, we just turn the semantic rule into an action and add at the far right hand side. This DOES NOT WORK for inherited attribs!

  50. Turning a SDD into a translation scheme • With inherited attributes, the translation scheme designer needs to follow three rules: • An inherited attribute for a symbol on the RHS MUST be computed in an action BEFORE the occurrence of the symbol. • An action MUST NOT refer to the synthesized attribute of a symbol to the right of the action. • A synthesized attribute for the LHS nonterminal can ONLY be computed in an action FOLLOWING the symbols for all the attributes it references.

More Related