1 / 10

SDTs used to implement SDDs

SDTs used to implement SDDs. A non-cyclic SDD (having definitions of attributes) can always be implemented by a SDT (having actions that assign values to attributes) by arranging that the parser first builds a tree, ignoring the actions of the SDT

fairly
Télécharger la présentation

SDTs used to implement SDDs

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. SDTs used to implement SDDs • A non-cyclic SDD (having definitions of attributes) can always be implemented by a SDT (having actions that assign values to attributes) by arranging that • the parser first builds a tree, ignoring the actions of the SDT • the tree is then walked, executing the actions of the SDT • Two interesting cases where SDDs may be implemented by SDTs whose actions can be executed during parsing, in 1 pass, without a parse tree being constructed • S-attributed SDD and parsing is LR (deterministic bottom-up) • this is the simplest case • all actions can be grouped at the end of a production • result is a “postfix SDT” • L-attributed SDD and parsing can be LL (deterministic top-down) • if a grammar can be parsed LL, it can also be parsed LR http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction

  2. Postfix SDTs • If grammar can be parsed deterministically bottom-up, & all attributes “synthetic” • Then all actions of a production can be executed along with the parser’s reduce step • They can all be grouped at the end of the production, forming a postfix to it e.g. Postfix SDT for very-simple desk calculator L ::= E \n E ::= E1 + T E ::= T T ::= T1 * F T ::= F F ::= ( E ) F ::= digit { 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 } all attributes are synthetic, all actions occur at end of production and from the parser’s point of view they are part of the production, the grammar is LR(1). http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction

  3. Implemention issues with postfix SDTs • Attributes can be stored in records/structs/dictionaries on the symbol stack, alongside LR parser states on the state stack. • Furthermore the grammar symbol itself need not be kept on the symbol stack • If some attribute values have unbounded size – e.g. for strings or code lists – it is best to store fixed-size pointers in the stack structures, and store the actual values elsewhere • When a parser reduce occur – say for T ::= T1 * F – the stack records containing needed values (T1’s for T1.val, F’s for F.val) will be at known offsets (-1, 0) relative to the top of stack. The result can be left on top of the stack after reduce step. • With single productions, e.g. T ::= F, no change to the topmost stack entry is necessary since the item at the top must stay at the top. (but top state will usually change) http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction

  4. Parser stack manipulations made explicit L ::= E \n E ::= E1 + T E ::= T T ::= T1 * F T ::= F F ::= ( E ) F ::= digit { print (stack[top-1].val; top=top-1; } { stack[top-2].val=stack[top-2].val+stack[top].val; top=top-2; } { } stack[top-2].val=stack[top-2].val*stack[top].val; top=top-2; } { } { stack[top-2].val=stack[top-1].val; top=top-2; } { } // if we may assume that val and lexval attributes // occupy the same locations in a struct effect is to place 9 into the existing E element’s .val and make top point to it T: T.val=3 * E: E.val=6 top … … … … … … … http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction

  5. SDTs with actions inside productions - 1 • Where SDD is not S-attributed (it may be L-attributed or worse) then no postfix SDT can be constructed: actions inside productions will be necessary productions have the form X ::= a {a} b where b is not e • If such a SDT cannot be handled during parsing – because it is worse than L-attributed while still being acyclic – then • parse, ignoring actions, and producing an explicit parse tree • then, knowing what productions have been used to parse, add extra child nodes for the particular actions within those productions • perform preorder traversal of tree, executing the actions X X a a b b {a} http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction

  6. SDTs with actions inside productions - 2 • If such a SDT can be handled during parsing, then • if parsing bottom-up, treat the action like a non-terminal: • invent a unique marker non-terminal for each action • such a non-terminal has one empty production • perform the action when that non-terminal is on the top of the stack • if parsing top-down • perform the action just before processing the next grammar symbol • checking the next terminal, if b begins with a terminal • expanding the next non-terminal, if b begins with a non-terminal X ::= a M39b M39 ::= e http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction

  7. Eliminating left recursion from SDTs • Grammars, and hence SDTs, cannot be used for top-down parsing if left recursive • Treat actions like terminals, since order of terminals is preserved by left recursion elimination • (although if any production begins with an action, the grammar with SDT will not be possible to parse deterministically either top-down or even bottom-up, and it will then be necessary to walk a tree) • General idea of left recursion elimination (without actions) is to replace left recursion by right recursion involving a new non-terminal capable of generating e A ::= A a | b A ::= b R R ::= a R | e • With actions {a} and {b} in SDD, similar transformation requires care A ::= A a {a} | b {b} A ::= b {?1} R {?2} R ::= a {?3} R {?4} | e {?5} http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction

  8. … the right-recursive version should achieve same result Example left-recursive original SDT with only one S-attribute ‘q’ A ::= A1 b { A.q=f(A1.q, b.q);} | c { A.q=g(c);} A For sample input ‘cbb’, flow of information is always upwards A.q=f(f(g(c),b.q),b.q) A b A.q=f(g(c),b.q) A b After eliminating left recursion, the shape of the parse tree will be radically different, but the end result calculated for topmost A.q should be the same A.q=g(c) c http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction

  9. … needing inherited attributes A A A.q=R.s R.i=g(c) A.q=f(f(g(c),b.q),b.q) A b A.q=f(g(c),b.q) c R R.s=R1.s R1.i=f(g(c),b.q) A b A.q=g(c) b R R.s=R1.s R1.i=f(f(g(c),b.q),b.q) with left recursive grammar c b R R.s=R.i Only at this point can it be known that the correct result is f(f(g(c),b.q),b.q) e http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction

  10. … and appropriate evaluation order • Getting the actions done in the right order and with the right information available requires use of inherited attributes • values of inherited attributes must be calculated immediately before the right-recursive use of the non-terminal R • Getting the result(s) back to the top node involves a new synthesized attribute(s) • values of synthesized attributes may be calculated right at the ends of productions, just as with postfix SDTs A ::= c {R.i=g(c)} R {A.q=R.s} R ::= b {R1.i=f(R.i, b.q)} R {R.s=R1.s} R ::= e {R.s=R.i} http://csiweb.ucd.ie/staff/acater/comp30330.html Compiler Construction

More Related