Top Banner
Syntax Directed Translation Chapter 5 1
93

Syntax Directed Translation

Jan 04, 2016

Download

Documents

Steven Bowman

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. - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Syntax Directed Translation

1

Syntax Directed Translation

Chapter 5

Page 2: Syntax Directed Translation

2

Context-Free Languages

The inclusion hierarchy for

context-free languages

Context-free languages

Deterministic languages (LR(k))

LL(k) languages Simple precedencelanguages

LL(1) languages Operator precedencelanguages

LR(k) ≡ LR(1)

Page 3: Syntax Directed Translation

3

Context-Free Grammars

• Operator precedence includes some am-biguous grammars

• LL(1) is a subset of SLR(1)

The inclusion hierarchy forcontext-free grammars

Context-free grammars

Floyd-EvansParsable

Unambigu-ous

CFGs

OperatorPrece-dence

LR(k)

LR(1)

LALR(1)

SLR(1)

LR(0)

LL(1)

LL(k)

Page 4: Syntax Directed Translation

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 pro-gram?

(let me count the ways …)

Page 5: Syntax Directed Translation

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 pro-gram?

(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 thansyntax”

Page 6: Syntax Directed Translation

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.

Page 7: Syntax Directed Translation

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

Page 8: Syntax Directed Translation

8

Syntax-Directed Definitions

Page 9: Syntax Directed Translation

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.

Page 10: Syntax Directed Translation

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.

Page 11: Syntax Directed Translation

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

1. b is a synthesized attribute of A, and c1, c2, …, are attributes of the grammar symbols of α, or

2. 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.

Page 12: Syntax Directed Translation

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.

Page 13: Syntax Directed Translation

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.

Page 14: Syntax Directed Translation

14

Example SDD: desk calculator

• Production Semantic 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.

Page 15: Syntax Directed Translation

15

Calculating synthesized attributesInput string: 3*5+4 new-lineAnnotated tree:

Page 16: Syntax Directed Translation

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.

Page 17: Syntax Directed Translation

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 justa procedure that

sets the typefield in the

symbol table.

Page 18: Syntax Directed Translation

18

Annotated parse tree for real id1, id2, id3

What are thedependen-

cies?

Page 19: Syntax Directed Translation

19

Dependency Graphs

Page 20: Syntax Directed Translation

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.

Page 21: Syntax Directed Translation

21

Dependency graph example

• Production Semantic Rule• E -> E1 + E2 E.val := E1.val + E2.val

• Wherever this rule appears in the parse, tree we draw:

Page 22: Syntax Directed Translation

22

Example dependency graph

Page 23: Syntax Directed Translation

23

Example dependency graph

Page 24: Syntax Directed Translation

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.

Page 25: Syntax Directed Translation

25

Example dependency graph

Page 26: Syntax Directed Translation

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.

Page 27: Syntax Directed Translation

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.

Page 28: Syntax Directed Translation

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.

Page 29: Syntax Directed Translation

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 1.Synthesized. 2.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 a.Inherited attributes of A, the LHS. b.Any attribute of X1, ..., Xj-1, i.e. only on symbols to the left of Xj.

3.Attributes of Xj, *BUT* you must guarantee (separately) that these

attributes do not by themselves cause a cycle.

Page 30: Syntax Directed Translation

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

Page 31: Syntax Directed Translation

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.

• Production Semantic Rule Type

D → T L L.type = T.type inherited

T → INT T.type = integer synthesized

L → L1 , ID L1.type = L.type inherited

addType(ID.entry,L.type) synthesized, side effect

L → ID addType(ID.entry,L.type) synthesized, side effect

Page 32: Syntax Directed Translation

32

Semantic Rules with Controlled Side Effects

• The function addType adds 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

Page 33: Syntax Directed Translation

33

Syntax Trees

Page 34: Syntax Directed Translation

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.

Page 35: Syntax Directed 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.

Page 36: Syntax Directed Translation

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 := …

Page 37: Syntax Directed Translation

37

SDD for syntax tree construction

• Production Semantic 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.

Page 38: Syntax Directed Translation

38

Evaluating SDDs Bottom-up

Page 39: Syntax Directed Translation

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.

Page 40: Syntax Directed Translation

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.

Page 41: Syntax Directed Translation

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.

• Production Semantic Rule Code• 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*/

Page 42: Syntax Directed Translation

42

Desk calculator example

• For input 3 * 5 + 4 newline, what happens?• Assume when a terminal’s attribute is shifted when it is.

• Input States Values Action• 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

Page 43: Syntax Directed Translation

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.

Page 44: Syntax Directed Translation

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• }

Page 45: Syntax Directed Translation

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.

Page 46: Syntax Directed Translation

46

L-attributed definitions

• Is the following SDD L-attributed?

• Production Semantic 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)

Page 47: Syntax Directed Translation

47

Translation Schemes

Page 48: Syntax Directed Translation

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+

Page 49: Syntax Directed Translation

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:

• Production Semantic 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!

Page 50: Syntax Directed Translation

50

Turning a SDD into a translation scheme

• With inherited attributes, the translation scheme designer needs to follow three rules:

1. An inherited attribute for a symbol on the RHS MUST be computed in an action BEFORE the occurrence of the symbol.

2. An action MUST NOT refer to the synthesized attribute of a symbol to the right of the action.

3. A synthesized attribute for the LHS nonterminal can ONLY be computed in an action FOLLOWING the symbols for all the attributes it references.

Page 51: Syntax Directed Translation

51

Example

• This translation scheme does NOT follow the rules:

• S -> A1 A2 { A1.in = 1; A2.in = 2 }• A -> a { print( A.in ) }

• If we traverse the parse tree depth first, A1.in has not been set when referred to in the action print( A.in )

• S -> { A1.in = 1 } A1 { A2.in = 2 } A2

• A -> a { print( A.in ) }

Page 52: Syntax Directed Translation

52

Bottom-up evaluation of inherited attributes

• The first step is to convert the SDD to a valid translation scheme.• Then a few “tricks” have to be applied to the translation scheme.• It is possible, with the right tricks, to do one-pass bottom-up attribute

evaluation for ALL LL(1) grammars and MOST LR(1) grammars, if the SDD is L-attributed.

• This means when adding semantic actions to your yacc specifications, you might run into trouble. See section 5.6 of the text!

Page 53: Syntax Directed Translation

53

Beyond Syntax

• These questions are part of context-sensitive analysis• Answers depend on values, not parts of speech• Questions & answers involve non-local information• Answers may involve computation

• How can we answer these questions?• Use formal methods

• Context-sensitive grammars?• Attribute grammars? (attributed grammars?)

• Use ad-hoc techniques• Symbol tables• Ad-hoc code (action routines)

• In scanning & parsing, formalism won; different story here.

Page 54: Syntax Directed Translation

54

Beyond Syntax

• Telling the story• The attribute grammar formalism is important

• Succinctly makes many points clear• Sets the stage for actual, ad-hoc practice

• The problems with attribute grammars motivate practice• Non-local computation• Need for centralized information

• Some folks in the community still argue for attribute grammars

• We will cover attribute grammars, then move on to ad-hoc ideas

Page 55: Syntax Directed Translation

55

Attribute Grammars

• What is an attribute grammar?• A context-free grammar augmented with 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

Example grammar

Number → Sign ListSign → + | –List → List Bit | BitBit → 0 | 1

This grammar describessigned binary numbers

We would like to augmentit with rules that computethe decimal value of eachvalid input string

Page 56: Syntax Directed Translation

56

Examples

For “-1”Number → Sign List

→ – List→ – Bit→ – 1

Number

Sign List

Bit–

1

For “-101”

Number → Sign List → Sign List Bit → Sign List 1 → Sign List Bit 1 → Sign List 1 1 → Sign Bit 0 1 → Sign 1 0 1 → – 101

Number

Sign List

Bit–

1

List

BitList

Bit 0

1

Page 57: Syntax Directed Translation

57

Attribute Grammars

•Add rules to compute the decimal value of a signed binary number

Symbol Attributes

Number val

Sign neg

List pos, val

Bit pos, val

Productions Attribution Rules

Number → Sign List List.pos ← 0If Sign.neg then Number.val ← – List.val else Number.val ← List.val

Sign → + Sign.neg ← false

| – Sign.neg ← true

List0 → List1 Bit List1.pos ← List0.pos + 1Bit.pos ← List0.posList0.val ← List1.val + Bit.val

| Bit Bit.pos ← List.posList.val ← Bit.val

Bit → 0 Bit.val ← 0

| 1 Bit.val ← 2Bit.pos

Page 58: Syntax Directed Translation

58

Back to The Examples

•Knuth suggested a data-flow model for evaluation• Independent attributes first• Others in order as input values become available

For “-1” One possible evaluation order:

1. List.pos2. Sign.neg3. Bit.pos4. Bit.val5. List.val6. Number.val

Other orders are possible

neg ← true

Number.val ← –List.val≡ –1

List.pos ← 0List.val ← Bit.val≡ 1

Bit.pos ← 0Bit.val ← 2Bit.pos ≡ 1

Number

Sign List

Bit–

1

Rules + parse treeimply an attributedependence graph

Evaluation ordermust be consis-tentwith the at-tributedependence graph

Page 59: Syntax Directed Translation

59

Back to the Examples

This is the completeattribute dependencegraph for “–101”.

It shows the flow of allattribute values in theexample.

Some flow downward→ inherited attributes

Some flow upward→ synthesized at-tributes

A rule may use at-tributesin the parent, children, orsiblings of a node

Page 60: Syntax Directed Translation

60

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

Page 61: Syntax Directed Translation

61

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 passGood match to LR parsing

Inherited Attributes• Use values from parent,

constants, & siblings• directly express context• can rewrite to avoid them• Thought to be more natu-

ralNot easily done at parse time

We want to use both kinds of attribute

Page 62: Syntax Directed Translation

62

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 (treewalk)• Analyze rules at compiler-generation time• Determine a fixed (static) ordering• Evaluate nodes in that order

• Oblivious methods (passes, dataflow)• Ignore rules & parse tree• Pick a convenient order (at design time) & use it

Page 63: Syntax Directed Translation

63

Back to the Example

Number

Sign List

Bit–

1

List

List

Bit

Bit

0

1 For “-101”

Page 64: Syntax Directed Translation

64

Back to the Example

Number

Sign List

Bit–

1

List

List

Bit

Bit

0

1

val:

neg:pos:0val:

pos:val:

pos:val:

pos:val:

pos:val:

pos:val:

For “-101”

Page 65: Syntax Directed Translation

65

Back to the Example

Number

Sign List

Bit–

1

List

List

Bit

Bit

0

1 For “-101”

val:-5

neg:truepos:0val:5

pos:1val:4

pos:2val:4

pos:2val:4

pos:1val:0

pos:0val:1

Inherited Attributes

Page 66: Syntax Directed Translation

66

Back to the Example

Number

Sign List

Bit–

1

List

List

Bit

Bit

0

1 For “-101”

val:-5

neg:truepos:0val:5

pos:1val:4

pos:2val:4

pos:2val:4

pos:1val:0

pos:0val:1

Synthesized Attributes

Page 67: Syntax Directed Translation

67

Back to the Example

Number

Sign List

Bit–

1

List

List

Bit

Bit

0

1 For “-101”

val:-5

neg:truepos:0val:5

pos:1val:4

pos:2val:4

pos:2val:4

pos:1val:0

pos:0val:1

Synthesized Attributes

Page 68: Syntax Directed Translation

68

Back to the Example

Number

Sign List

Bit–

1

List

List

Bit

Bit

0

1 For “-101”

val:-5

neg:truepos:0val:5

pos:1val:4

pos:2val:4

pos:2val:4

pos:1val:0

pos:0val:1

If we show the computation …

& then peel away the parse tree …

Page 69: Syntax Directed Translation

69

Back to the Example

1

0

1 For “-101”

val:-5

neg:truepos:0val:5

pos:1val:4

pos:2val:4

pos:2val:4

pos:1val:0

pos:0val:1

All that is left is the attributedependence graph.

This succinctly represents theflow of values in the probleminstance.

The dynamic methods sort thisgraph to find independentvalues, then work along graphedges.

The rule-based methods try todiscover “good” orders byanalyzing the rules.

The oblivious methods ignorethe structure of this graph.

The dependence graph must be acyclic

Page 70: Syntax Directed Translation

70

Circularity

• We can only evaluate acyclic instances• We can prove that some grammars can only generate instances with acyclic

dependence graphs• Largest such class is “strongly non-circular” grammars (SNC )• SNC grammars can be tested in polynomial time• Failing the SNC test is not conclusive

• Many evaluation methods discover circularity dynamically• ⇒ Bad property for a compiler to have

• SNC grammars were first defined by Kennedy & Warren

Page 71: Syntax Directed Translation

71

A Circular Attribute Grammar

Productions Attribution Rules

Number → List List.a ← 0

List0 → List1 Bit List1.a ← List0.a + 1List0.b ← List1.b List1.c ← List1.b + Bit.val

| Bit List0.b ← List0.a + List0.c + Bit.val

Bit → 0 Bit.val ← 0

| 1 Bit.val ← 2Bit.pos

Page 72: Syntax Directed Translation

72

An Extended Example

Block0 → Block1 Assign | AssignAssign → Ident = Expr ;Expr0 → Expr1 + Term | Expr1 – Term | TermTerm0 → Term1 * Factor | Term1 / Factor | FactorFactor → ( Expr ) | Number | Identifier

Let’s estimate cycle counts

• Each operation has a COST

• Add them, bottom up

• Assume a load per value

• Assume no reuse

Simple problem for an AG

Hey, this looks useful !

Grammar for a basic block (§ 4.3.3)

Page 73: Syntax Directed Translation

73

An Extended Example

Block0 → Block1 Assign

| AssignAssign → Ident = Expr ;Expr0 → Expr1 + Term

| Expr1 – Term

| TermTerm0 → Term1 * Factor

| Term1 / Factor

| FactorFactor → ( Expr ) | Number | Identifier

Block0.cost ← Block1.cost + Assign.costBlock0.cost ← Assign.costAssign.cost ← COST(st ore) + Expr.costExpr0.cost ← Expr1.cost + COST(add) + Term.costExpr0.cost ← Expr1.cost + COST(add) + Term.costExpr0.cost ← Term.costTerm0.cost ← Term1.cost + COST(mult ) + Factor.costTerm0.cost ← Term1.cost + COST(div) + Factor.costTerm0.cost ← Factor.costFactor.cost ← Expr.costFactor.cost ← COST(loadI)Factor.cost ← COST(load)

Adding attribution rules

All theseattributesaresynthe-sized!

Page 74: Syntax Directed Translation

74

An Extended Example

• Properties of the example grammar• All attributes are synthesized S-attributed grammar⇒• Rules can be evaluated bottom-up in a single pass

• Good fit to bottom-up, shift/reduce parser• Easily understood solution• Seems to fit the problem well

• What about an improvement?• Values are loaded only once per block (not at each use)• Need to track which values have been already loaded

Page 75: Syntax Directed Translation

75

A Better Execution Model•Adding load tracking• Need sets Before and After for each production• Must be initialized, updated, and passed around the tree

Factor → ( Expr )

| Number

| Identifier

Factor.cost ← Expr.cost ;Expr.Before ← Factor.Before ;Factor.After ← Expr.AfterFactor.cost ← COST(loadi) ;Factor.After ← Factor.Beforeif(Identifier.name ∉ Factor.Before) then Factor.cost ← COST(load); Factor.After ← Factor.Before ∪ Identifier.name else Factor.cost ← 0 Factor.After ← Factor.Before

This looks more complex!

Page 76: Syntax Directed Translation

76

A Better Execution Model• Load tracking adds complexity• But, most of it is in the “copy rules”• Every production needs rules to copy Before & After

•A Sample Production

Expr0 → Expr1 + Term Expr0 .cost ← Expr1.cost + COST(add) + Term.cost ;Expr1.Before ← Expr0.Before ;Term.Before ← Expr1.After;Expr0.After ← Term.After

These copy rules multiply rapidlyEach creates an instance of the setLots of work, lots of space, lots of rules to write

Page 77: Syntax Directed Translation

77

An Even Better Model

• What about accounting for finite register sets?• Before & After must be of limited size• Adds complexity to Factor→Identifier• Requires more complex initialization

• Jump from tracking loads to tracking registers is small• Copy rules are already in place• Some local code to perform the allocation

Page 78: Syntax Directed Translation

78

The Extended Example

• Tracking loads• Introduced Before and After sets to record loads• Added ≥ 2 copy rules per production

• Serialized evaluation into execution order

• Made the whole attribute grammar large & cumbersome

• Finite register set• Complicated one production (Factor → Identifier)• Needed a little fancier initialization• Changes were quite limited

• Why is one change hard and the other easy?

Page 79: Syntax Directed Translation

79

The Moral of the Story

• Non-local computation needed lots of supporting rules• Complex local computation was relatively easy

• The Problems• Copy rules increase cognitive overhead• Copy rules increase space requirements

• Need copies of attributes• Can use pointers, for even more cognitive overhead

• Result is an attributed tree• Must build the parse tree• Either search tree for answers or copy them to the root

Page 80: Syntax Directed Translation

80

Addressing the Problem

• Ad-hoc techniques• Introduce a central repository for facts• Table of names

• Field in table for loaded/not loaded state

• Avoids all the copy rules, allocation & storage headaches• All inter-assignment attribute flow is through table

• Clean, efficient implementation• Good techniques for implementing the table (hashing, § B.4)• When its done, information is in the table !• Cures most of the problems

• Unfortunately, this design violates the functional paradigm• Do we care?

Page 81: Syntax Directed Translation

81

The Realist’s Alternative

• Ad-hoc syntax-directed translation• Associate a snippet of code with each production• At each reduction, the corresponding snippet runs• Allowing arbitrary code provides complete flexibility

• Includes ability to do tasteless & bad things

• To make this work• Need names for attributes of each symbol on lhs & rhs

• Typically, one attribute passed through parser + arbitrary code (structures, globals, statics, …)

• Yacc introduced $$, $1, $2, … $n, left to right ANTLR allows defining variables

• Need an evaluation scheme• Should fit into the parsing algorithm

Page 82: Syntax Directed Translation

82

Reworking the Example

Block0 → Block1 Assign | AssignAssign → Ident = Expr ;Expr0 → Expr1 + Term | Expr1 – Term | TermTerm0 → Term1 * Factor | Term1 / Factor | FactorFactor → ( Expr ) | Number | Identifier

cost← cost + COST(store);cost← cost + COST(add);cost← cost + COST(sub);

cost← cost + COST(mult);cost← cost + COST(div);

cost← cost + COST(loadi);{ i← hash(Identifier); if(Table[i].loaded = false) then { cost ← cost + COST(load); Table[i].loaded ← true; }}

This lookscleaner &simpler thanthe AG sol’n !

One missing de-tail:initializing cost

Page 83: Syntax Directed Translation

83

Reworking the Example

• Before parser can reach Block, it must reduce Init• Reduction by Init sets cost to zero•This is an example of splitting a production to create a reduction•in the middle — for the sole purpose of hanging an action routine•there!

Start → Init BlockInit → εBlock0 → Block1 Assign

| AssignAssign → Ident = Expr ;

cost ← 0;

cost← cost + COST(store);

… and so on as in the previous version of the example …

Page 84: Syntax Directed Translation

84

Reworking the ExampleBlock0 → Block1 Assign | AssignAssign → Ident = Expr ;Expr0 → Expr1 + Term | Expr1 – Term | TermTerm0 → Term1 * Factor | Term1 / Factor | FactorFactor → ( Expr ) | Number | Identifier

$$ ← $1 + $2 ;$$ ← $1 ;$$ ← COST(store) + $3;$$ ← $1 + COST(add) + $3;$$ ← $1 + COST(sub) + $3;$$ ← $1;$$ ← $1 + COST(mult) + $3;$$ ← $1 + COST(div) + $3;$$ ← $1;$$ ← $2;$$ ← COST(loadi);{ i← hash(Identifier); if (Table[i].loaded = false) then { $$ ← COST(load); Table[i].loaded ← true; } else $$ ← 0}

This versionpasses thevalues throughattributes. Itavoids the needfor initializing“cost”

Page 85: Syntax Directed Translation

85

Reworking the Example

• Assume constructors for each node• Assume stack holds pointers to nodes• Assume yacc syntax

Goal → ExprExpr → Expr + Term | Expr – Term | TermTerm → Term * Factor | Term / Factor | FactorFactor → ( Expr ) | number | id

$$ = $1;$$ = MakeAddNode($1,$3);$$ = MakeSubNode($1,$3);$$ = $1;$$ = MakeMulNode($1,$3);$$ = MakeDivNode($1,$3);$$ = $1;$$ = $2;$$ = MakeNumNode(token);$$ = MakeIdNode(token);

Page 86: Syntax Directed Translation

86

Reality

• Most parsers are based on this ad-hoc style of context-sensitive analysis

• Advantages• Addresses the shortcomings of the AG paradigm• Efficient, flexible

• Disadvantages• Must write the code with little assistance• Programmer deals directly with the details• Annotate action code with grammar rules

Page 87: Syntax Directed Translation

87

Typical Uses

• Building a symbol table• Enter declaration information as processed• At end of declaration syntax, do some post processing• Use table to check errors as parsing progresses

• Simple error checking/type checking• Define before use → lookup on reference• Dimension, type, ... → check as encountered• Type conformability of expression → bottom-up walk• Procedure interfaces are harder

• Build a representation for parameter list & types• Create list of sites to check• Check offline, or handle the cases for arbitrary orderings

Page 88: Syntax Directed Translation

88

Is This Really “Ad-hoc” ?

• Relationship between practice and attribute grammars

• Similarities• Both rules & actions associated with productions• Application order determined by tools, not author• (Somewhat) abstract names for symbols

• Differences• Actions applied as a unit; not true for AG rules• Anything goes in ad-hoc actions; AG rules are functional• AG rules are higher level than ad-hoc actions

Page 89: Syntax Directed Translation

89

Making Ad-hoc SDT Work

• What about a rule that must work in mid-production?• Can transform the grammar

• Split it into two parts at the point where rule must go• Apply the rule on reduction to the appropriate part

• Can also handle reductions on shift actions• Add a production to create a reduction

• Was: fee → fum• Make it: fee → fie → fum and tie action to this reduction

• ANTLR supports the above automatically

• Together, these let us apply rule at any point in the parse

Page 90: Syntax Directed Translation

90

Limitations of Ad-hoc SDT

• Forced to evaluate in a given order: postorder• Left to right only• Bottom up only

• Implications• Declarations before uses• Context information cannot be passed down

• How do you know what rule you are called from within?• Example: cannot pass bit position from right down

• Could you use globals?• Requires initialization & some re-thinking of the solution

• Can we rewrite it in a form that is better for the ad-hoc sol’n

Page 91: Syntax Directed Translation

91

Alternative Strategy

• Build an abstract syntax tree• Use tree walk routines• Use “visitor” design pattern to add functionality

TreeNodeVisitor

VisitAssignment(AssignmentNode)

VisitVariableRef(VariableRefNode)

TypeCheckVisitor

VisitAssignment(AssignmentNode

)

VisitVariableRef(VariableRefNode)

AnalysisVisitor

VisitAssignment(AssignmentNode)

VisitVariableRef(VariableRefNode)

Page 92: Syntax Directed Translation

92

Visitor Treewalk

• Parallel structure of tree:• Separates treewalk code from node handling code • Facilitates change in processing without change to tree structure

TreeNode

Accept(NodeVisitor)

AssignmentNode

Accept(NodeVisitor v)

v.VisitAssignment(this)

VariableRefNode

Accept(NodeVisitor v)

v.VisitVariableRef(this)

Page 93: Syntax Directed Translation

93

Summary

• Wrap-up of parsing• More example to build LR(1) table

• Attribute Grammars• Pros: Formal, powerful, can deal with propagation strategies• Cons: Too many copy rules, no global tables, works on parse tree

• Ad-hoc SDT• Annotate production with ad-hoc action code• Postorder Code Execution

• Pros: Simple and functional, can be specified in grammar, does not require parse tree• Cons: Rigid evaluation order, no context inheritance

• Generalized Tree Walk• Pros: Full power and generality, operates on abstract syntax tree (using Visitor pattern)• Cons: Requires specific code for each tree node type, more complicated• Powerful tools like ANTLR can help with this