Syntax-Directed Translation Two approaches are distinguished 1. A syntax-directed definition (SDD) associates a semantic rule with each grammar production, the rule states how attributes are calculated conceptually, (and for SDTs too) each node may have multiple attributes – perhaps a struct/record/dictionary is used to group many attributes attributes may be concerned e.g. with data type, numeric value, symbol identification, code fragment, memory address, machine register choice 2. A syntax-directed translation scheme (SDT) uses semantic actions embedded anywhere in the bodies (right hand sides) of productions actions may perform arbitrary computations, such as appending output they are carried out in left-to-right order during parsing. http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction 1 Compare/Contrast SDD & SDT • SDDs have a declarative flavour the grammar writer specifies what calculations have to be done the order of evaluation is unspecified – it must be fixed by the parser (or parser generator) the grammar is more readable • SDTs have a more procedural flavour the grammar writer specifies both – the calculations that have to be done – at what time they must be done the grammar is often more efficiently parsable http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction 2 Synthesized and Inherited Attributes • For a grammar symbol X and its attribute a, use notation “X.a” • Each attribute X.x at a parse tree node for symbol X may be synthesized, meaning that its value is obtained – from attributes of child nodes in the parse tree, – or from the lexical analyzer, – or from other attributes of the same node in the parse tree inherited, meaning that its value is obtained – from the parent node in the parse tree, – or from sibling nodes in the parse tree – v. useful when there is mismatch between grammar for parsing, and “abstract syntax” for translation http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction 3 Restricted classes of grammars • The most general – least restrictive – kind of syntax-directed translation involves building a parse tree explicitly, then “walking” it carrying out the actions in the productions. • Two special cases allow actions to be carried out during parsing, with no explicit parse tree having to be built L-attributed translations, grammars (‘L’ for left-to-right) – inherited attributes are allowed provided they can be calculated in left-toright fashion S-attributed translations, grammars (‘S’ for Synthesized) – only synthesized attributes are allowed – easy for a bottom-up parser to handle • The term “attribute grammar” means a grammar with attributes but its rules or actions may not have side effects http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction 4 Syntax-Directed Definitions (SDDs) • A SDD is a context-free grammar, plus attributes, and rules attached to the productions of the grammar stating how attributes are computed • Desk calculator’s Arithmetic Expression example: – all attributes in this example are synthesized – val and lexval attribute names are purposely different – subscripts distinguish occurrences of the same grammar symbol – practical rules may also have side-effects (such as printing, manipulating a symbol table) L E E T T F F ::= E \n ::= E1 + T ::= T ::= T1 * F ::= F ::= ( E ) ::= digit http://csiweb.ucd.ie/staff/acater/comp30330.html L.val = 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 Compiler Construction 5 SDD applied to “9+3*5\n” L E E T T F F ::= E \n ::= E1 + T ::= T ::= T1 * F ::= F ::= ( E ) ::= digit L.val = 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 L.val=24 \n E.val=24 + E.val=9 T.val=15 T.val=3 T.val=9 * F.val=5 This is an annotated parse tree Note that no complete parse tree need actually be constructed. F.val=9 digit.lexval=9 http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction 6 SDD applied to “9+3*5\n” L E E T T F F ::= E \n ::= E1 + T ::= T ::= T1 * F ::= F ::= ( E ) ::= digit L.val = 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 L.val=24 \n E.val=24 + E.val=9 T.val=15 T.val=3 T.val=9 * F.val=5 This is an annotated parse tree Note that no complete parse tree need actually be constructed. F.val=9 digit.lexval=9 http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction 7 Evaluation order • Values of synthesized attributes may be calculated in any order • For a S-attributed SDD, any bottom-up order suffices • Where inherited attributes are allowed, order of evaluation is important it is possible to write rules for which no order of evaluation is possible circularity – NP-hard to detect if a set of rules could give rise to circularity In a L-attributed SDD, dependencies always go left-to-right, so no circularity is possible • A “Dependency Graph” depicts the flow of information between attributes in a particular parse tree • A “topological sort” of this graph produces a possible sequential order of evaluation – if there is one, if the graph is not cyclic http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction 8 Usefulness of inherited attributes • There can be tension between the design of a grammar for parsing purposes, and its use in syntax-directed translation elimination of left recursion, to allow top-down parsing covering syntactic sugar constructs – mismatch of surface & abstract syntax The C syntax int[2][3] reads as “an array of two arrays of three integers” array array 2 3 int http://csiweb.ucd.ie/staff/acater/comp30330.html T ::= B C B := int B := float C := [ num ] C1 C := e T.t=C.t; C.b=B.t B.t=‘integer’ B.t=‘float’ C.t=array(num.val, C1.t); C1b=C.b) C.t=C.b Compiler Construction 9 Utilising SDDs • SDDs can strike a balance between side-effect-free “attribute grammars” where any order of evaluation of rule elements is permitted consistent with dependency graph translation schemes whose actions may contain arbitrary side-effects but must be evaluated in strict left-to-right order • This balance may be achieved in either of two ways permit only incidental side-effects which do not have any impact upon the ordering of evaluation of rule elements somehow constrain the order of evaluation, effectively adding edges to the dependency graph, so that significant side-effects may be allowed – eg desk calculator: printing info; compiler: add type info to symbol table • It is common to use SDD to produce an actual parse tree, which may be used as an intermediate representation for a tree-walking translator http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction 10 Building a parse tree using a SDD E := E1 + T E := E1 – T E := T T := ( E ) T := id T := num E.node= new Node(‘+’, E1.node, T.node) E.node= new Node(‘-’, E1.node, T.node) E.node= T.node T.node= E.node T.node= new Leaf(‘ident’, id.entrynumber) T.node= new Leaf(‘number’, num.lexval) fred – george * 13 => ident 1 * ident 2 http://csiweb.ucd.ie/staff/acater/comp30330.html number 13 Compiler Construction 11