Compiler Design
105601Module 2: Syntax Analysis (Parser)
Q1a. Which of the following is the most powerful parser? (i) SLR (ii) LALR (iii) Canonical LR (iv) Operator precedence20232m
Module 2: Syntax Analysis (Parser)
View this question on its own page →Which of the following is the most powerful parser?
(i) SLR
(ii) LALR
(iii) Canonical LR
(iv) Operator precedenceWorked SolutionAnswer: (iii) Canonical LR
Explanation
Parsers can be ordered by the size of the grammar class they can handle (their power):
- Operator-precedence parsing: only works on operator grammars (no , no two adjacent nonterminals) — the least general.
- SLR(1): uses the LR(0) items but decides reduce actions using the broad set of the left-hand nonterminal, ignoring the specific context of each item → weaker.
- LALR(1): merges LR(1) items that share the same core (same item, different lookahead). More powerful than SLR(1).
- Canonical LR / LR(1): keeps every lookahead separate, producing the most states and therefore accepting the largest set of grammars among the given options.
Hence the most powerful parser is:
Order of power (weakest → strongest):
Operator-precedence < SLR(1) < LALR(1) < Canonical LR(1)Q1b. A top down parser generates (i) Rightmost derivation (ii) Rightmost derivation in reverse (iii) Leftmost derivation (iv) Left most derivation in reverse20232m
Module 2: Syntax Analysis (Parser)
View this question on its own page →A top down parser generates
(i) Rightmost derivation
(ii) Rightmost derivation in reverse
(iii) Leftmost derivation
(iv) Left most derivation in reverseWorked SolutionAnswer: (iii) Leftmost derivation
Explanation
A top-down parser starts from the start symbol (root) and tries to derive the input string by expanding nonterminals in leftmost order — i.e. it always expands the leftmost nonterminal first.
- Leftmost derivation: each step replaces the leftmost nonterminal — this is exactly what a top-down (recursive-descent / predictive / LL) parser constructs.
- Rightmost derivation: each step replaces the rightmost nonterminal — not what a top-down parser does.
- Rightmost derivation in reverse / handle pruning: that is the basis of bottom-up parsing (LR parsers), not top-down.
Therefore a top-down parser generates a
Q1e. Handle pruning forms the basis of........ (i) Bottom up parsing (ii) Top down parsing (iii) Predictive parsing (iv) Recursive descent parsing20232m
Module 2: Syntax Analysis (Parser)
View this question on its own page →Handle pruning forms the basis of........
(i) Bottom up parsing
(ii) Top down parsing
(iii) Predictive parsing
(iv) Recursive descent parsingWorked SolutionAnswer: (i) Bottom-up parsing
Explanation
- A handle is a substring of a (right) sentential form that matches the right-hand side of a production, and whose reduction brings us one step closer to the start symbol when reduced.
- Handle pruning is the process of repeatedly finding the handles (finding the rightmost such substring during a rightmost reduction) and reducing them — from the input string up to the start symbol.
- This is precisely how a bottom-up parser (shift-reduce / LR parser) works: it repeatedly reduces handles until the entire input has been reduced to the start symbol.
Top-down parsing, predictive parsing, and recursive-descent parsing all work top-down (expanding the root) and do not prune handles.
Q1f. Left factoring guarantees (i) Not occurring of backtracking (ii) Cycle free parse tree (iii) Error free target code (iv) Correct LL(1) parsing table20232m
Module 2: Syntax Analysis (Parser)
View this question on its own page →Left factoring guarantees
(i) Not occurring of backtracking
(ii) Cycle free parse tree
(iii) Error free target code
(iv) Correct LL(1) parsing tableWorked SolutionAnswer: (i) Not occurring of backtracking
Explanation
- Left factoring is a grammar transformation that factors out the common prefix of two or more production alternatives.
- It is used to remove uncertainty about which alternative to choose when a common prefix could lead to two different nonterminal, which otherwise forces the parser to backtrack while building a predictive (LL) parser.
How it works:
In an LL(1) (predictive top-down) parser the decision is made by looking at the first token; factoring out a common prefix ensures the choice is deterministic, so backtracking never occurs.
Hence left factoring guarantees:
Q1g. Consider a grammar A \to a S_1 | a S_2. The left factored grammar produced from the grammar is (i) A \to a A', A' \to S_1 | S_2 (ii) A' \to a A, A \to a S_1 | a S_2 (iii) A \to a A', A' \to S_1 | S_2, S_1 \to S_1, S_2 (iv) None of these20232m
Module 2: Syntax Analysis (Parser)
View this question on its own page →Consider a grammar . The left factored grammar produced from the grammar is
(i)
(ii)
(iii)
(iv) None of theseWorked SolutionAnswer: (i)
Step 1 — left factoring
Given grammar:
The two alternatives share the common prefix
a. We factor it out into a new nonterminal :This is the standard left-factored (CFG) form that removes backtracking uncertainty, because after reading
athe parser chooses between and by looking at the next input, not by backtracking.Hence the correct answer is:
Q1j. For a grammar G, shift reduce (S-R) conflicts are present in LALR(1) parser, if and only if (i) The LAR (1) parser for G has S.R conflicts (ii) The LR(0) parser for G has S.R conflicts (iii) The SLR(1) parser for G has S.R conflicts (iv) The SLR(0) parser for G has S.R conflicts20232m
Module 2: Syntax Analysis (Parser)
View this question on its own page →For a grammar G, shift reduce (S-R) conflicts are present in LALR(1) parser, if and only if
(i) The LAR (1) parser for G has S.R conflicts
(ii) The LR(0) parser for G has S.R conflicts
(iii) The SLR(1) parser for G has S.R conflicts
(iv) The SLR(0) parser for G has S.R conflictsWorked SolutionAnswer: (i) The LR(1) parser for G has S–R conflicts
Explanation — LALR vs LR relationship
- LALR(1) parsers are built by merging the states of a canonical LR(1) parser that share the same core (same items, different lookaheads).
- Merging states can create a reduce–reduce (R–R) conflict (two different reduce actions that were separated by lookahead now share a cell).
- However, state-merging cannot create a new shift–reduce (S–R) conflict. Intuitively, a shift action exists on a terminal in a state only if is in that state's core in the LR(1) automaton too. So if the LALR(1) table has an S–R conflict, the same conflict must have already been present in the LR(1) table.
Therefore the correct statement is the one in option (i) — the LR(1) parser for has S–R conflicts (with
LAR(1)in the paper being a typo forLR(1)).Q3a. What are the advantages of LALR parsing over SLR and CLR methods?20235m
Module 2: Syntax Analysis (Parser)
View this question on its own page →What are the advantages of LALR parsing over SLR and CLR methods?
Worked SolutionAdvantages of LALR(1) parsing over SLR(1) and canonical LR (CLR)
Method Number of states Power Slots management SLR(1) fewest weakest (uses FOLLOW) smallest LALR(1) same as SLR between SLR and CLR larger Canonical LR (CLR/CLR(1)) the most strongest largest Advantages of LALR over SLR:
- LALR(1) accepts a larger grammar class than SLR(1): SLR reduces using , which may cause spurious reduce–reduce and shift–reduce conflicts, because it ignores which attribute context produced the follow. LALR uses the precise lookahead symbols from the LR(1) items (merged by core), so fewer conflicts arise. Many grammars that are not SLR are LALR.
- It is still simple: LALR(1) lookaheads are "compatible" — no shift–reduce conflict is introduced by merging states.
Advantages of LALR over canonical LR (CLR):
- Fewer states — In practice LALR(1) has roughly the same number of states as SLR(1), whereas a canonical LR(1) parser can have a very large state space (up to exponential in the grammar size). This makes LALR tables much more compact and memory-efficient.
- Faster table construction — merging reduces the number of states to process.
- It is the method of choice in practice: LALR(1) is used in tools like YACC / Bison because it is strong enough for almost all practical grammars yet keeps the table small — the "sweet spot" between SLR (too weak) and CLR (too many states).
Trade-off: CLR may parse a slightly larger class, but its cost (huge state) is not justified in most cases. So LALR(1) is the best power/size ratio.
Q3b. Write the algorithm to compute FIRST and FOLLOW for a given grammar.20235m
Module 2: Syntax Analysis (Parser)
View this question on its own page →Write the algorithm to compute FIRST and FOLLOW for a given grammar.
Worked SolutionAlgorithm to compute FIRST and FOLLOW
Notation: = nonterminal/terminal; = strings of grammar symbols; = empty string;
$= end marker.FIRST
Compute = set of terminals that can start any string derivable from (plus if the whole can derive ).
Rules (for individual symbol):
- If is a terminal, then .
- If is production i.e. , add to .
- If is a nonterminal and , then:
- Put \textbackslash}{\epsilon} into .
- If derives , also put , and so on.
- If all can derive , then put into .
- Order: For each production, apply until no more additions; repeat the whole loop until no change.
For a string :
; if , add , etc.; if all derive , add to .2. Compute FOLLOW(X) for every nonterminal X
Rule to find the set of terminals that can appear immediately to the right of in some sentential form.
- If is the start symbol, place `\mathrm{FOLLOW}(X)$.
- For a production : everything in except goes into .
- If there is a production or where (i.e. is nullable), then everything in gets added to .
- Repeat these steps until no further additions occur.
(Terminals/symbol
)that are not nonterminals have no FOLLOW.)These First/Follow results are then used to build the predictive (LL(1)) parsing table: for , put the production into
M[A][a]for eachain ; if nullable, put it intoM[A][b]for eachbin .Q3c. What is shift-reduce conflict?20234m
Module 2: Syntax Analysis (Parser)
View this question on its own page →What is shift-reduce conflict?
Worked SolutionWhat is a shift–reduce conflict?
A shift–reduce conflict (S–R conflict) is a parsing-table conflict in an LR-family bottom-up parser: in one state (looking at one input symbol), the parser has both a valid shift action and a valid reduce action.
Why it happens: When constructing the parsing table, a single cell ends up with two entries: one saying "shift a (push onto the stack / go to next state)" and the other saying "reduce using production ". Since the parser cannot decide deterministically, the grammar is not LR with the given method (and the table entry is ambiguous).
Example grammar with S–R conflict: classic ambiguous grammar
produces S–R conflict in LR(0)/SLR(1)/LALR(1) because, e.g. after parsingE + E .with input+or*, the parser doesn't know whether to shift the operator (deferring) or reduceE+E.Remedies:
- Add precedence/associativity (
%left,%right,%precin YACC) — e.g. make*bind tighter than+. - Refactor the grammar to an unambiguous form (e.g. with separate
term/factorlevels). - Use a more powerful parsing method (canonical LR can resolve conflicts that SLR can't) — but a true ambiguity cannot be removed by switching methods.
Reduction internal form: in LR table notation, a cell with both
sandractions is marked as a conflict, and the grammar is rejected by the parser generator (unless a rule like "shift wins on S–R conflict" is chosen YACC's default: prefer shift).- Add precedence/associativity (
Q4b. Find the FIRST an FOLLOW form the following production: S \to aBDh B \to cC C \to bC | \epsilon D \to EF E \to g | \epsilon F \to f | \epsilon20237m
Module 2: Syntax Analysis (Parser)
View this question on its own page →Find the FIRST an FOLLOW form the following production:
Worked SolutionFirst and Follow for the given grammar
Grammar:
Step 1 — FIRST sets
Compute allowed terminals that begin derivations (plus if nullable).
- (from and )
- : . FIRST(E)= → take ; since E nullable, take FIRST(F)= → ; since both nullable, include .
- (from ). (B is not nullable since is a terminal.)
- : → starts with terminal
a.
Step 2 — FOLLOW sets
The follow of a nonterminal is the set of terminals that can appear immediately to the right of in some sentential form.
: S is the start symbol → ${$}$.
: from , after comes , so we add . Also is nullable, so we add $\mathrm{FOLLOW}(S) = {$}$.
: from (C at the end), so .
: from , after comes terminal
h.: from , after comes , so add . Since is nullable, also add .
: from (F at the end), so .
Final answer:
- Install PocketlyBudget App•POCKETLY
Pocketly on Android
Log daily food, travel, and hostel expenses instantly. Set monthly spending limits and see where your money goes without complex spreadsheets.
Q5a. Construct the predictive parsing table for the following grammars: S \to AaAb | BbBa A \to \epsilon B \to \epsilon20237m
Module 2: Syntax Analysis (Parser)
View this question on its own page →Construct the predictive parsing table for the following grammars:
Worked SolutionPredictive (LL(1)) parsing table
Grammar:
Step 1 — FIRST and FOLLOW
, .
For : because , the first of the right-hand string is
a. For : the first isb. Hence:FOLLOW:
- is start → $\mathrm{FOLLOW}(S) = {$ }$.
- From : the first is followed by
a, the second byb. - From : first followed by
b, second bya.
Step 2 — build table
For each production , put into for every ; if , also put it into for every .
- For : → entry .
- For : → .
- For : place under → , .
- For : → , .
Predictive parsing table (blank cells = error, no production):
Nonterminal ab$— — — Verification: Every cell has at most one entry, so the grammar is LL(1) — no conflicts. This is the classic example of an LL(1) grammar with that resolves the choice using lookahead.
Q6a. What is handle? Consider the grammar: E \to E + E | E * E | id Find the handles of the right sentential forms of the reduction for the string id + id * id.20235m
Module 2: Syntax Analysis (Parser)
View this question on its own page →What is handle? Consider the grammar:
Find the handles of the right sentential forms of the reduction for the string .Worked SolutionHandle; reduction of
id + id * idwith grammarWhat is a handle?
A handle of a (right) sentential form is a substring that matches the right-hand side of some production, and whose reduction to the left-hand-side nonterminal is a step in a rightmost (reverse) derivation — that is, the rightmost handle that, when reduced, produces a valid step toward the start symbol.
In shift–reduce parsing we repeatedly prune handles: shift symbols onto the stack until the top stack symbols match a production RHS, then reduce (replace the handle by its nonterminal).
Find the handles for
id + id * idGrammar: . The (unique, rightmost) reduction sequence:
Stack (top shown last) Input Action Handle reduced id+ id * idshift id— E+ id * idreduce id → Ehandle idE +id * idshift +— E + id* idshift id— E + E* idreduce handle id(2nd)E + E *idshift *— E + E * id(empty) shift — E + E * Ereduce handle id(3rd)E + Ereduce E*E → Ehandle E*EEreduce E+E → Ehandle E+EHandles (in reduction order), with the actual substrings:
id(first id on the left)id(the middleid)id(theidafter*)E * E(the redexE*E→ E)E + E(the redexE+E→ E)
Written against the original string, the reduction is a reverse of the rightmost derivation:
The seeds/handlesreduced, going left-to-right on the string: the *ids**, thenEE, thenE + E`.Q6b. When a grammar is called ambiguous? Is there any technique to remove ambiguity? Justify whether the grammar is ambiguous or not? A \to AA | (A) | a20234m
Module 2: Syntax Analysis (Parser)
View this question on its own page →When a grammar is called ambiguous? Is there any technique to remove ambiguity? Justify whether the grammar is ambiguous or not?
Worked SolutionAmbiguous grammar; ambiguity removal; is ambiguous?
1. When is a grammar called ambiguous?
A grammar is called ambiguous when there exists at least one string in its language that has two or more distinct parse trees (equivalently, two different leftmost or two different rightmost derivations).
2. Techniques to remove ambiguity
- Grammar rewriting (precedence/associativity): restructure the grammar with separate levels, e.g.
expr → expr + term | term,term → term * factor | factor, so that operators bind with the intended precedence and associativity. - Parser-tool directives: in YACC/Bison, use precedence declarations
%left/%right/%nonassocto resolve conflicts (e.g.%left '+',%left '*'). - Explicit structure: for left-associative operators use left recursion; for the dangling-else problem use separate matched/unmatched statement nonterminals.
- Caveat: removing ambiguity from an arbitrary grammar is undecidable in general, but for practical expression grammars these techniques work.
3. Justify whether is ambiguous
Yes — this grammar is ambiguous.
The string
aaahas two distinct parse trees:- Tree 1 (grouping as
a (a a)): rootA → A A, leftA → a, rightA → A Awith childrena a:
A / \ a A / \ a a- Tree 2 (grouping as
(a a) a): rootA → A A, leftA → A Awith childrena a, rightA → a:
A / \ A a / \ a aBoth trees derive the same string
aaawith different structure ⇒ the grammar is ambiguous. The root cause is the production — two adjacent occurrences of the same nonterminal admit two groupings of any consecutive run ofa's.A fix for this grammar: make the concatenation left- or right-associative explicitly, e.g. , or add a priority marker — but more importantly, grammar is inherently ambiguous, so a parser generator such as YACC would report a conflict for it. In practice prepend associativity info (
%left) or rewrite to an unambiguous grammar such as withcata real operator.- Grammar rewriting (precedence/associativity): restructure the grammar with separate levels, e.g.
Q6c. Discuss about operator precedence parser.20235m
Module 2: Syntax Analysis (Parser)
View this question on its own page →Discuss about operator precedence parser.
Worked SolutionOperator-Precedence Parser
1. What it is
An operator-precedence (OP) parser is a bottom-up shift–reduce parser whose shift/reduce decision is based only on a precedence relation table between terminal symbols (operators) — not on a full LR state machine.
2. Operator grammar preconditions
The grammar must be an operator grammar:
- no -production,
- no two adjacent nonterminals on any right-hand side.
3. Precedence relations
Between terminals
aandb:- — a has lower precedence than b (→ shift b)
- — equal precedence (→ shift)
- — a has higher precedence than b (→ reduce)
Computed from the grammar using the FIRST/LAST terminal sets:
- if and then ;
- if then ;
- if and then .
This yields the operator-precedence matrix for all terminal pairs.
4. Algorithm (stack with
):- Compare precedence of the input symbol with the relevant top-of-stack terminal.
- If top next, or top next → shift the next token.
- If top next → a handle boundary has been found: scan back until the first preceding relation; the substring between them is the handle → reduce it to its nonterminal. No state/lookahead table needed.
- Accept when the stack holds exactly the start symbol with no input left.
5. Example —
id + id * idwith precedence* > +stack: $ id + id * id shift id, shift +, shift id when `*` (input) and top `id` reduce id→E... then top `*` vs input `+`: since `*` ⋗ `+`, reduce E*E before E+ → matches the expected "multiply before add" behaviour.6. Advantages & disadvantages
Advantages:
- very fast (simple matrix lookup), small table,
- easy to implement (no GOTO states).
Disadvantages:
- works only for operator grammars (no adjacent nonterminals, no ),
- handle detection is purely local — it ignores surrounding context, so many real languages need LR/LALR instead,
- usually used in small/expression-oriented compilers or inside calculator-style evaluators.
Example precedence table (
*binds tighter than+):op +*+*Rule: shift on / , reduce on — which reproduces standard arithmetic precedence.
Q7b. Consider the following grammar: E \to E + T | T T \to T * F | F F \to td Draw a SLR state transition diagram for the above grammar. Also draw the SLR parse table.20237m
Module 2: Syntax Analysis (Parser)
View this question on its own page →Consider the following grammar:
Draw a SLR state transition diagram for the above grammar. Also draw the SLR parse table.Worked SolutionSLR parse for the grammar , ,
(The paper spells the token
td; we treat it as the identifier tokenid.)Augment with .
Productions numbering:
LR(0) canonical collection (states –):
- :
- : ,
- : ,
- :
- :
- : , , ,
- : ,
- : ,
- :
GOTO transitions: ;
; ; ; ; .(This is the state-transition diagram; every state is a node and every label above is an edge.)
FOLLOW sets:
- $\mathrm{FOLLOW}(E)={+, $}E\to E+T$.
- $\mathrm{FOLLOW}(T)={+,,$}$ (E→E+T ⇒ FOLLOW(E), T→TF ⇒
*). - $\mathrm{FOLLOW}(F)={+,*,$}$.
SLR parsing table (ACTION + GOTO):
State id + * $ E T F 0 s4 1 2 3 1 s5 acc 2 r2 s6 r2 3 r4 r4 r4 4 r5 r5 r5 5 s4 7 3 6 s4 8 7 r1 s6 r1 8 r3 r3 r3 s n= shift and go to state n;r k= reduce by production (list above);acc= accept.- Uses FOLLOW: r4/r5 in states 3/4 for
+,*,$(in FOLLOW(T)/FOLLOW(F)) etc.
No cell has two actions → the grammar is SLR(1) (a conflict-free table), and
id + id * idis accepted.Q8a. Consider the following grammar: S \to CC C \to cC | d Find the LR(1) set of items.20235m
Module 2: Syntax Analysis (Parser)
View this question on its own page →Consider the following grammar:
Find the LR(1) set of items.Worked SolutionLR(1) sets of items for ,
Augmented grammar: .
Items are written where
ais the lookahead terminal.Closure hint: from $[S\to \cdot CC,\ $]CC\to\cdots\mathrm{FIRST}(C$)={c,d}C{c,d}$.
Canonical LR(1) collection:
- : $[S'\to\cdot S,$],\ [S\to\cdot CC,$],\ [C\to\cdot cC,\ c/d],\ [C\to\cdot d,\ c/d]$
- = goto: $[S'\to S\cdot,$]$
- = goto: $[S\to C\cdot C,$],\ [C\to\cdot cC,$],\ [C\to\cdot d,$]$
- = goto:
- = goto:
- = goto: $[S\to CC\cdot,$]$
- = goto: $[C\to c\cdot C,$],\ [C\to\cdot cC,$],\ [C\to\cdot d,$]$
- = goto: $[C\to d\cdot,$]$
- = goto:
- = goto: $[C\to cC\cdot,$]$
GOTO function:
- goto= ; goto=; goto=; goto=
- goto=; goto=; goto=
- goto=; goto=; goto=
- goto=; goto=; goto=
So the canonical LR(1) machine has 10 states (–).
Reduce actions: : on ; : on $$I_8C\to cC{c,d}I_9C\to cC
; : onI_1`.Bonus — LALR(1): merging states with equal cores (, , ) gives the 7-state LALR(1) automaton, free of conflicts for this grammar.