200 likes | 399 Views
Grammar design: Associativity. Plus and minus are left associative , parse trees should grow to the left L ::= L + number | L - number | number If parse tree grows to the right it is farther from the abstract syntax R ::= number + R | number - R | number
E N D
Grammar design: Associativity • Plus and minus are left associative, parse trees should grow to the left L ::= L + number | L - number | number • If parse tree grows to the right it is farther from the abstract syntax R ::= number + R | number - R | number • However, right associatively is appropriate for right-associative operators such as assignment and exponentiation
BNF for Arithmetic Exp • Expression with precedence (only) S F - S | F + S | F F T * F | T / F | T T (S) | number • 2 * 3 – 5 * 6 – 7 -17 6 23 30 7 The answer should be –31, but this gives -17
BNF for Arithmetic Exp • Associativity taken into account S S - F | S + F | F F F * T | F / T | T T (S) | number • Derivation of 2 * 3 – 5 * 6 – 7 S S – F by SS-FS – F – F by SS-FF – F – F by SFF * T– F – F by FF*TT * T– S – F by FT2 * T– S – F by Tnumber2 * 3– S – F by Tnumber2 * 3– F – F by SF2 * 3– F * T – T by FF*T2 * 3– T*T – T by FT2 * 3– 5*T – T by Tnumber2 * 3– 5 *6 – T by Tnumber2 * 3– 5 *6 – 7 by Tnumber NOTE:Colors updated,but rule usagewas correct asoriginally shownin class. See usage on theright column Gives “correct” answer, and as a leftmost derivation: “leftmost nonterminal is replaced at each step”
Grammar Design -- Precedence • Conventional arithmetic such as a * b + c * d + e • Grammar: A ::= E := A | E[right associative & recursive] E ::= E + T | E - T | T[left associative & recursive] T ::= T * F | T / F | F F ::= number | name | ( E ) • In a top-down parse, expand E first; this expands into T, which places higher precedence operators *and / closer to the the number, name or parenthesized expression. Viewed bottom-up, the * and/ are recognized first and hence have larger precedence • Pblm – topdown cannot parse left recursion
Derivation • Start with the unique distinguished symbol • DerivationSequence of strings where a non-terminal on is replaced by a production rule in the next step of the derivation • Top-down selects a rule where the left side matches a non-terminal of the sentential form. It replaces the non-terminal with the rule’s right side. This is generation • Bottom-up selects a rule where the right side matches a non-terminal of the sentential form, or a string that includes a non-terminal. It replaces the matched string with the rule’s left side. This is reduction • Sentential FormAny step in the derivation • SentenceSentential form with no non-terminals
Leftmost Derivation • A derivation in which only the leftmost non-terminal in any sentential form is replaced at each step. • Unique derivation for a string for a non ambiguous grammar • For an ambiguous grammar thee may be multiple productions that can replace the non-terminal, thus giving multiple derivations (and resulting parse trees)
Rightmost Derivation • The rightmost non-terminal is replaced in the derivation process in each step. • Also referred to as Canonical Derivation
Parse Tree • Abstracts out the information of the derivation process. • Usually the parse tree is the same, even if the derivations for a string are different.
Ambiguity • Characteristic of grammar • If a grammar has two parse trees or two derivations for a particular string in the language it represents, then ambiguous • If all grammars for a particular language are ambiguous then the language is called Inherently Ambiguous
Ambiguous Grammars • Has more than one leftmost derivation. • Has more than one parse tree. • S S + S | S - S | a | b
Left Recursive • A grammar is left recursive if there is a derivation as follows: A (+) A<string> • Some parsing methods cannot handle these grammars (top-down parsing methods)
Immediate Left Recursiveness A A <alpha> | <beta> A <beta> B B <alpha> B | null A A<alpha1> | ….| A<alpha_m> | <beta1> | …..| <beta_n> Replace the leading nonterminals A <beta1>B | …| <beta_n>B B <alpha1>B |…| <alpha_m>B | null
Left Recursion • “A grammar is left recursive if it has a nonterminal A such that there is a derivation A A for some string ” • Topdown parsers cannot handle immediate left recursion since they do not see a leftmost nonterminal until the recursion is complete • Fortunately, can rewrite the left recursive form to begin with leading nonterminals • Left recursion can be replaced with non-left-recursive productions. A A | becomes two productions A A’andA’A’| (page 176)
Eliminating Left Recursion (Alg.) • Order the non-terminals from A1 to An • Next, replaced productions for ( i=1; i<=n; I++ ) { for (j=1; j<=i-1; j++) { replaceA_i A_j <gamma> withproductionsA_i <delta_1> <gamma> | … | <delta k> <gamma> where A_j <delta_1> | <delta_2> | … <delta_k> are the A_j productions • Then, remove immediate left recursion among A_i productions
Left Factoring • Modifying the grammar in order to be able to expand a non-terminal without non-determinism.
Left Factoring a Grammar • For all A, find the longest common prefix <alpha> common to more than one of its rhs • Replace A<a><b1>| … |<a><bn>| <c> A <a>B | <c> B <b1> | ….. | <bn> • S iEtS | iEtSeS | a , E b S iEtSS’ | a S’ eS | null, E b
Classic if-then-else problem • Grammar S::= if E then S S::= if E then S1 else S2 • How to parse this? if E1 then if E2 then S1 else S2 if E1 then if E2 then S1 else S2 <---------S---------> if E1 then if E2 then S1 else S2 <-----S1-----> <S2>
Left Factoring • The ambiguity of the if/then/else is shown as figures 4.5 and 4.6 in the Compilers text by Aho, Sethi and Ullman • They analyze the difficulty and find it is due to left recursion • “A grammar is left recursive if it has a nonterminal A such that there is a derivation A A for some string ” • Left recursion can be replaced with non-left-recursive productions. A A | becomes two productions A A’andA’A’| (page 176)