Vous êtes sur la page 1sur 38

Marc Fortes

Renaire Odarve

To be able to define syntax directed translation and explain the

mechanism on how to specify and implement it. To show how syntax-directed definitions can be used to specify the construction of syntax trees and other graphical representations of language constructs. To discuss how to implement a translator using bottom-up evaluation. To elaborate how a recursive evaluation works.

A method of translating a string into a sequence of

actions by attaining one such action to each rule of grammar. It uses a grammar to direct the translation which defines the syntax of the input language.

The principle of syntax directed translation states that the meaning of an input sentence is related to its syntactic nature. Steps to do this are as follows. We associate Attributes to the grammar symbols representing the language constraints. Values for attributes are computed by Semantic Rules associated with grammar productions. The most general approach to syntax directed translation is to construct a parse tree or a syntax tree, and then compute the values of attributes at the nodes of the tree by visiting the nodes of the tree.

There are two notations for attaching semantic rules: 1. Syntax-Directed Definitions (SDDs) High-level specification hiding many specification details. Also, called Attribute Grammars. 2. Syntax-Directed Translation Schemes (SDTs) More implementation oriented: Indicate the order in which semantic rules are to be evaluated. The semantic rules are enclosed in braces. Generally, SDDs are more readable, hence more useful for specifications. However, SDTs can be efficient, hence more useful for implementations.

A context-free grammar together with attributes and rules.

Attributes are associated with grammar symbols and rules are associated with productions. Attributes may be of any kind: numbers, types, table references, strings, etc. Each grammar production A a has associated semantic rules of the form b:=f(c1, c2, , ck) where f is a function and either it is synthesized or inherited.

1. Synthesized an attribute for a nonterminal A at

a parse-tree node N is defined by a semantic rule associated with the production at N. Note that the production must have A as its head. A synthesized attribute at Node N is defined only in terms of attribute values at the children of N and at N itself. Also called S-attributed definition.

Production E E1 + T

Semantic Rule E.val = E1.val + T.val

a production of
a syntax directed definition

E E1 + T { E.val = E1.val + T.val } the production of


the corresponding translation scheme

2. Inherited an attribute for a nonterminal B at a

parse-tree node N is defined by a semantic rule associated with the production at THE PARENT of N. Note that the production must have B as a symbol in its body. An inherited attribute at Node N is defined only in terms of attribute values at JVs parent, N itself and Ns siblings. Also called L-attributed definition.

The interdependencies among the inherited and synthesized attributes

at the nodes in a parse trees can be depicted by a directed graph called a dependency graph. To construct a dependency graph given a parse tree is as follows:

It is a condensed form of parse tree useful for representing

language constructs. Operators and keywords do not appear as leaves, but rather are associated with the interior node that would be parent of those leaves of the parse tree. Syntax-directed translation can be based on syntax trees as well as parse trees.

Similar to the translation of the expression into postfix

form. Construct sub-trees for the sub-expressions by creating a node for each operator and operand. Children of an operator node are the roots of the nodes representing the sub-expressions constituting the operands of that operator.

Each node in a syntax tree can be implemented as

a record with several fields. - One field identifies the operator and the remaining
fields contain pointers to the nodes for the operands. The operator is called label of the node. There are number of functions defined to create the nodes of syntax trees. It returns a pointer to a newly created node.

In the following examples, well use the following

functions:

We put the values of the synthesized attributes of the grammar symbols into a parallel stack. When an entry of the parser stack holds a grammar symbol X (terminal or non-

terminal), the corresponding entry in the parallel stack will hold the synthesized attribute(s) of the symbol X.

We evaluate the values of the attributes during reductions. A XYZ A.a=f(X.x,Y.y,Z.z) where all attributes are synthesized.

stack parallel-stack

top

Z
Y

Z.z
Y.y X.x .

top

X
.

A .

A.a .

Production
L E return E E1 + T ET T T1 * F TF F(E) F digit

Semantic Rules
print(val[top-1]) val[ntop] = val[top-2] + val[top]
val[ntop] = val[top-2] * val[top] val[ntop] = val[top-1]

At each shift of digit, we also push digit.lexval into val-stack. At all other shifts, we do not put anything into val-stack because other

terminals do not have attributes (but we increment the stack pointer for valstack).

Using a bottom-up translation scheme, we can also

implement any L-attributed definition based on a LL(1) grammar (each LL(1) grammar is also an LR(1) grammar). In addition to the L-attributed definitions based on LL(1) grammars, we can implement some of Lattributed definitions based on LR(1) grammars (not all of them) using the bottom-up translation scheme.

Steps to follow.
Remove embedded semantic actions in the translation

scheme. Same as the S-Attributed Definitions

A {S1} X1 {S2} X2 ... {Sn} Xn

remove embedding semantic actions


A M1 X1 M2 X2 ... Mn Xn M1 {S1} M2 {S2} . . Mn {Sn}

ETR R + T { print(+) } R1 R T id { print(id.name) }

remove embedding semantic actions


ETR R + T M R1 R T id { print(id.name) } M { print(+) }

Recursive Evaluators can be constructed from a

syntax-directed definition.
The function accepts the values of the inherited

attributes in its formal parameters and returns the values of the synthesized attributes. If there are multiple synthesized attributes their values can be returned in a record or a pointer to a record

Given this translation.

E T {R.i := T.nptr} r {E.nptr := R.s} R + T {R1.i := mknode (+, R.i, T.nptr)}R1 {R.s := R1.s} R - T {R1.i := mknode (-, R.i, T.nptr)}R1 {R.s := R1.s} R {R.s := R.i} T (E) {T.nptr := E.nptr} T id {T.nptr := mkleaf (id, id.entry)} T num {T.nptr := mkleaf (num, num.value)}

Considering the three

nonterminals E, R and T. Write three recursive functions. E and T have no arguments. Function E handles the production: E T {R.i := T.nptr} R {E.nptr := R.s} function E : tree_node; begin e := R (T) end;

Function

Synthesized Attributes E.Nptr R.S T.Nptr

Inherited Attributes (none) R>I (none)

E R T

Function R handles three productions:

R + T {R1.i := mknode (+, R.i, T.nptr)}R1 {R.s := R1.s} R - T {R1.i := mknode (-, R.i, T.nptr)} R1 {R.s := R1.s} R {R.s := R.i}

function R (I : tree_node) : tree-node;

var nptr, i1 : tree_node; begin if lookahead = + then begin match (+); nptr := T; i1 := mknode (+, I nptr); R := R (i1) end else if lookahead = - then begin match (-); nptr := T; i1 := mknode (-, I, nptr); R := R (i1) end else R := i end;

Using the given functions mknode(op,left,right), mkleaf(id, carry), and mkleaf(num,val), write the postfix, the function calls and the syntax tree of the expression below. a + a * (b c) + (b c) * d

Vous aimerez peut-être aussi