Académique Documents
Professionnel Documents
Culture Documents
Renaire Odarve
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.
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.
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.
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
a production of
a syntax directed definition
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.
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:
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.
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.
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.
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).
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
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
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)}
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
E R T
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}
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