Syntax Directed Definitions

advertisement
CIS 324: Language Design and Implementation
Syntax Directed Translation
1. Syntax Directed Definitions
There are two notations for associating semantic actions with
productions: syntax-directed definitions and translation schemes.
The Syntax-Directed Definitions are a mechanism for specifying
translations for the programming language constructs. A syntax-directed
definition specifies the translation of a construct in terms of the attributes
associated with its syntactic components.
A syntax-directed definition uses a context-free grammar to specify the
structure of the input: with each grammar symbol it associates a set of
attributes; and with each production a set of semantic rules for computing
the values of the attributes associated with the symbols in it.
A Translation Scheme is like a syntax-directed translation except
that the order of evaluation of the semantic rules is explicitly shown.
A translation scheme is a context-free grammar in which program
fragments called semantic actions are embedded within the right sides
of the productions. Translation schemes show the order in which the
semantic rules has to be evaluated, so they show implementation details.
With both syntax-directed definitions and translation schemes the
input token stream is parsed, the parse tree is constructed, and next it
is traversed in order to execute the corresponding semantic actions.
The evaluation of the semantic actions could be code generation,
storing symbol table information, or printing error messages.
2. Synthesized and Inherited Attributes
Both syntax-directed definitions and translation schemes has
associated sets of attributes with each grammar symbol, which
indicate a relevant semantic action. An attribute can represent
various things, such as: a string, a number, a memory address, etc..
There are two kinds of attributes: synthesized and inherited.
The value of a synthesized attribute is computed from the values
of attributes at the children nodes of the current in the parse tree.
The value of an inherited attribute is computed from the values
of attributes at the parent nodes of the current in the parse tree.
Example: This a syntax-directed definition of a language
for implementing an arithmetic calculator
(using synthesized attributes)
Production
L  En
E  E1 + T
E  T
T  T1 * F
T  F
F  (E)
F  digit
Semantic rule
print( E.val )
E.val := E1.val + T.val
E.val := T.val
T.val := T1.val * F.val
T.val := F.val
F.val := E.val
F.val := digit.lexval
Using the above grammar there can be constructed the following
parse tree with synthesized attributes for the arithmetic expression:
3 * 5 + 4n
L
n
E.val=19
E.val=15
+
T.val=15
T.val=3
F.val=3
digit .lexval=3
*
T.val=4
F.val=4
F.val=5
digit .lexval=5
digit .lexval=4
Example: This a syntax-directed definition for specifying
declarations in a programming language
(using inherited attributes)
Production
D  TL
T  int
T  real
L  L1 , D
L  id
Semantic rule
L.in := T.type
T.type := integer
T.type := real
L1.in := L.in
addtype( id.entry, L.in )
addtype( id.entry, L.in )
Using the above grammar there can be constructed the following
parse tree with inherited attributes for the expression:
real id1, id2, id3
D
L.in=real
T.type=real
real
L.in=real
L.in=real ,
id1
,
id2
id3
3. Syntax Trees and Parse Trees
Example: Consider the following syntax-directed
Production
E  E1 + T
E  E1 - T
E  T
T  (E)
T  id
T  num
Semantic rule
E.nptr := mknode( '+', E1.nptr, T.nptr)
E.nptr := mknode( '-', E1.nptr, T.nptr)
E.nptr := T.nptr
T.nptr := E.nptr
T.nptr := mkleaf( id, id.entry )
T.nptr := mkleaf( num, num.val )
The figure below illustrates a syntax tree and a parse tree
drawn with dotted lines for the expression: a - 4 + c
E.nptr
E.nptr
E
-
T.nptr
id
id
T.nptr
+
T.nptr
num
id
+
id
a
num 4
c
Download