0% found this document useful (0 votes)
75 views

Ch3 SyntaxAnalysispdf 2024 01 01 08 48 28

This document provides an overview of parsing and parser classification. It discusses context-free grammars and how they are used to specify programming language syntax. Parse trees are described as visual representations of a program's syntactic structure. Issues like ambiguous grammars and left recursion are covered, along with transformations to eliminate them. Top-down and bottom-up parsing approaches are introduced at a high level. The role of a parser to validate syntax and detect errors is also mentioned.

Uploaded by

nagabe8303
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
75 views

Ch3 SyntaxAnalysispdf 2024 01 01 08 48 28

This document provides an overview of parsing and parser classification. It discusses context-free grammars and how they are used to specify programming language syntax. Parse trees are described as visual representations of a program's syntactic structure. Issues like ambiguous grammars and left recursion are covered, along with transformations to eliminate them. Top-down and bottom-up parsing approaches are introduced at a high level. The role of a parser to validate syntax and detect errors is also mentioned.

Uploaded by

nagabe8303
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 134

01CE0601 – Compiler Design

Unit - 3
Parsing

Prof. Rituraj Jain


Department of Information Technology
Outline

Why Context Free Grammar

Role of parser

Parse tree

Ambiguous grammar

Parser Classification

Top-down parsing

Bottom-up parsing
Why Context Free Grammar (CFG)

Syntax of the Programming Language constructs describe by CFG: WHY ?

1. Specification is Easy to understand

2. From certain classes of grammar we can automatically construct an efficient parser

3. Syntactic Ambiguities can be identified

4. Useful for translation of source program into correct object code

5. New construct can be added very easily to the existing implementation.


CFGs

A CFG is a quadruple (N, T, R, S) where


• N is the set of non-terminal symbols
• T is the set of terminal symbols
• S N is the starting symbol
• R  N(NT)* is a set of rules
Example: The grammar of nested parentheses
G = (N, T, R, S) where
• N = {S}
• T ={ (, ) }
• R ={ S→ (S) , S→SS, S→ }
Derivations

• The language described by a CFG is the set of strings that can be


derived from the start symbol using the rules of the grammar.
• At each step, we choose a non-terminal to replace.

S (S) (SS) ((S)S) (( )S) (( )(S)) (( )((S))) (( )(( )))

derivation sentential form

This example demonstrates a leftmost derivation : one where we always


expand the leftmost non-terminal in the sentential form.
Why Context Free Grammar

Role of parser

Parse tree

Ambiguous grammar

Parser Classification

Top-down parsing

Bottom-up parsing
The Role of Parser
The Role of Parser

In our compiler model, the parser obtains a string of tokens from the
lexical analyser and verifies that the string of token names can be
generated by the grammar for the source language.

It reports any syntax errors in the program. It also recovers from


commonly occurring errors so that it can continue processing its input.
Why Context Free Grammar

Role of parser

Parse tree

Ambiguous grammar, Left Recursion, Left Factoring

Top-down parsing

Bottom-up parsing
Parse Tree

• A parse tree is a visual representation of the syntactic structure of a piece of


source code, as produced by a parser. It shows the hierarchy of the elements
in the code and the relationships between them.
• In parsing, the string is derived using the start symbol. The root of the parse
tree is that start symbol.
• It is the graphical representation of symbol that can be terminals or non-
terminals.
Parse Tree

• Parse tree follows the precedence of operators. The deepest sub-tree traversed
first. So, the operator in the parent node has less precedence over the operator in
the sub-tree.
• A parse tree has a unique leftmost and a unique rightmost derivation (however,
we cannot tell which one was used by looking at the tree)
Parse Tree v/s Syntax Tree
3*4+5

3*4+5

Syntax Parse Tree


Tree
Why Context Free Grammar

Role of parser

Parse tree

Ambiguous grammar

Parser Classification

Top-down parsing

Bottom-up parsing
Ambiguous grammar

A CFG is
ambiguous if one
or more terminal
strings have
multiple leftmost
derivations from
the start symbol.
Ambiguous grammar

A CFG is ambiguous
if one or more
terminal strings have
multiple leftmost
derivations from the
start symbol.
Left Recursion in Grammar

In leftmost derivation by scanning the input from left to right, grammars


of the form A → A x may cause endless recursion.

Such grammars are called left-recursive and they must be transformed


if we want to use a top-down parser.
Left Recursion in Grammar

• A grammar is left recursive if for a non-terminal A, there is a

derivation

• There are three types of left recursion:

• direct (A → A x)

• indirect (A → B C, B → A )

• hidden (A → B A, B → )
Left Recursion in Grammar

To eliminate direct left recursion replace

A → A1 | A2 | ... | Am | 1 | 2 | ... | n

with

A → 1B | 2B | ... | nB

B → 1B | 2B | ... | mB | 


Left Recursion in Grammar

How about this:


S→E There is direct recursion: E→E+T
E → E+T There is indirect recursion: T→E -T, E→T
E→T
T → E-T Algorithm for eliminating indirect recursion
T → id
List the nonterminals in some order A1, A2, ...,An
for i=1 to n
for j=1 to i-1
if there is a production Ai→Aj,
replace Aj with its rhs
eliminate any direct left recursion on Ai
Left Recursion in Grammar
ordering: S, E, T, F i=S i=E i=E
S→E S→E S→E
S→E
E → E+T E → E+T E → TE'
E → E+T
E→T E→T E'→+TE'|
E→T
T → E-T T → E-T T → E-T
T → E-T
T→F T→F T→F
T→F
F → E*F F → E*F F → E*F
F → E*F
F → id F → id F → id
F → id
NO RECURSION DIRECT LEFT AFTER REMOVING
RECURSION LEFT RECURSION
FROM E
Left Recursion in Grammar
ordering: S, E, T, F
i=T i=T
i=T , j = E
S→E S→E
S→E E → TE'
E → TE' E → TE'
E'→+TE'| E'→+TE'|
E'→+TE'| T → TE'-T
T → E-T T → FT'
T→F T' → E'-TT'|
T→F F → E*F
F → E*F F → E*F
F → id F → id
F → id AFTER REMOVING LEFT
DIRECT LEFT
INDIRECT LEFT RECURSION RECURSION FROM T
RECURSION
Left Recursion in Grammar
ordering: S, E, T, F
i=F, j=E i=F, j=T i=F
AFTER REMOVING LEFT
RECURSION FROM F
S→E S→E S→E
E → TE' E → TE' E → TE' S → E
E'→+TE'| E'→+TE'| E'→+TE'| E → TE'
T → FT' T → FT' T → FT' E'→+TE'|
T' → E'-TT'| T' → E'-TT'| T' → E'-TT'| T → FT'
F → E*F F → TE'*F F → FT'E'*F T' → E'-TT'|
F → id F → id F → id F → idF'
INDIRECT LEFT INDIRECT LEFT DIRECT LEFT F' → T'E'*FF'|
RECURSION RECURSION RECURSION
Left Factor Grammar

• If RHS of more than one production starts with the same symbol, then such
a grammar is called as Grammar With Common Prefixes.
A → αβ1 / αβ2 / αβ3 (Grammar with common prefixes)
• This kind of grammar creates a problematic situation for Top down parsers.
• Parsers can not decide which production must be chosen to parse the string
in hand.

• To remove this confusion, we use left factoring.


Left Factor Grammar

• To remove this confusion, we use left factoring.

• The grammar obtained after the process of left factoring is called as Left

Factored Grammar.

A → αA’
A → αβ1 | αβ2 | αβ3 | …… | αβn
A’ → β1 | β2 | β3 | …… | βn
Left Factor Grammar

Examples
S → aS’
S → aX | aY | aZ
S’ → X | Y | Z

S → iEtSS’ | a
S → iEtS | iEtSeS | a
S’ → eS | ∈
E→b E→b
Left Factor Grammar

Examples

A → aA’
A → aA’
A → aAB | aBc | aAc A’ → AD | Bc
A’ → AB | Bc | Ac
D→B|c

Again, this is a grammar


with common prefixes.
Left Factor Grammar

Examples

S → bSSaaS | bSSaSb | bSb | a S → bSS' | a


S’ → SaaS | SaSb | b

Again, this is a grammar S → bSS' | a


with common prefixes. S’ → SaA | b
A → aS | Sb
Why Context Free Grammar

Role of parser

Parse tree

Ambiguous grammar

Parser Classification

Top-down parsing

Bottom-up parsing
Parser Classification
Why Context Free Grammar

Role of parser

Parse tree

Ambiguous grammar

Parser Classification

Top-down parsing

Bottom-up parsing
Top Down Parser
Top-down parser is the parser which generates parse tree for the given input
string with the help of grammar productions by expanding the non-terminals i.e. it
starts from the start symbol and ends on the terminals. It works as following:

Start with the root or start symbol.

Grow the tree downwards by expanding productions at the lower levels of the
tree.

Select a nonterminal and extend it by adding children corresponding to the


right side of some production for the nonterminal.

Repeat till, Lower fringe consists only terminals and the input is consumed
Top-down parsing basically finds a leftmost derivation for an input string.
Top down parser with backtracking

Brute Force Approach

Backtracking parsers are a type of top-down parser that can handle non-
deterministic grammar.

When a parsing decision leads to a dead end, the parser can backtrack and try
another alternative.

Backtracking parsers are not as efficient as other top-down parsers because they
can potentially explore many parsing paths.
Top down parser with backtracking

For an input string: read, a top-down parser, will behave


like this:
Top down parser with backtracking

Limitations

Backtracking looks very simple and easy to implement but choosing a

different alternative causes lot of problems which are given below −

• Undoing semantic actions requires a lot of overhead.

• Entries made in the symbol table during parsing have to be

removed while backtracking.


Recursive Descent Parser

Top-down parsing can be viewed as an attempt to find a leftmost derivation for an


input string.

Back Up is not allowed, less general, better than brute force approach

It can also viewed as an attempt to construct a parse tree for the input string from
the root and creating the nodes of the parse tree in preorder.

Write a routine to recognize each LHS (non-terminal)

This produces a parser with mutually recursive routines.


Recursive Descent Parser

▪ A sequence of production application realized in a sequence of function calls.


▪ Function written for each nonterminals.
▪ Return true/false depending on weather it recognizes a substring which is an
expansion of that nonterminal.
▪ Example:
<term> ::= <factor> <multiply_operator> <term> or T → F*T

public boolean term()


{ Recursive rule for
if (!factor()) return false; <term>
if (!multiplyOperator()) return true;
if (!term()) error("No term after '*' or '/' ");
return true;
}
Recursive Descent Parser

• They are exceptionally simple


Advantages • They can be constructed from recognizers simply
by doing some extra work specifically, building a
parse tree

• not very faster


• It is difficult to provide really good error messages
Disadvantages
• They cannot do parses that require arbitrarily long
lookaheads
Recursive Descent Parser

Main challenges:
1. back-tracking is messy, difficult and inefficient (solution: use input
“lookahead” to help make the right choice)
2. more alternatives --- even if we use one lookahead input char, there are still
more than 1 rules to choose --- A -> ab | a (solution: rewrite the grammar by
left-factoring)
3. left-recursion might cause infinite loop
what is the procedure for E -> E + E ?
(solution: rewrite the grammar by eliminating left-recursions)
4. error handling --- errors detected “far away” from actual source.
Predictive Parser
• Special case of Recursive descent parser is called Predictive parser.
• eliminating left recursion from it, and left factoring the resulting
grammar, we can obtain a grammar that can be parsed by a recursive
descent parser that needs no backtracking i.e. Predictive parser.
stmt → if expr then stmt else stmt
| while expr do stmt
| begin stmt_list end
• The keywords if, while and begin tell us which alternative is the only
one that could possibly succeed if we are to find a statement.
Predictive Parser

◼ Can we avoid the backtracking?

◼ Given A →  |  the parser should be able to choose between  and


◼ How?
◼ What if we do some "preprocessing" to answer the question: Given

a non-terminal A and lookahead t, which (if any) production of


A is guaranteed to start with a t ?
Predictive Parser…FIRST

◼ If we have two productions: A→ , we want a distinct way of choosing the


correct one.
◼ If  is any string of grammar symbols, FIRST() is the set of terminals that
begin the strings derived from . If  then  is also in FIRST().
◼ Define:
◼ for G, x  FIRST() iff  * x
◼ If FIRST() and FIRST() contain no common symbols, we will know whether
we should choose A→ or A→ by looking at the lookahead symbol.
Predictive Parser…FIRST
If X is Grammar Symbol, then First (X) will be −

• If X is a terminal symbol, then FIRST(X) = {X}


• If X → ε, then FIRST(X) = {ε}
• If X is non-terminal and X → a α, then FIRST (X) = {a}
• If X → Y1, Y2, Y3, then FIRST (X) will be
(a) If Y1 is terminal, then FIRST (X) = FIRST (Y1, Y2, Y3) = {Y1}
(b) If Y1 is Non-terminal and if Y1 does not derive to an empty string
i.e., If FIRST (Y1) does not contain ε then,
FIRST (X) = FIRST (Y1, Y2, Y3) = FIRST(Y1)
(c) If FIRST (Y1) contains ε, then
FIRST (X) = FIRST (Y1, Y2, Y3) = FIRST(Y1) − {ε} ∪ FIRST(Y2, Y3)
• Similarly FIRST (Y2, Y3) = FIRST (Y2), if FIRST (Y2) does not contain ε. If FIRST (Y2) contain ε,
then FIRST (Y2, Y3) = FIRST (Y2) − {ε} ∪ FIRST (Y3)
Predictive Parser…FIRST

Before calculating the first and follow

functions, eliminate Left Recursion from

the grammar, if present.


Predictive Parser…FIRST

Calculate the first for the given grammar:


S → aBDh
B → cC First(S) = { a }

C → bC / ε First(B) = { c }

D → EF First(C) = { b , ε }

E→g/ε First(D) = { First(E) – ε} ∪ First(F) = { g , f , ε }

F→f/ε First(E) = { g , ε }
First(F) = { f , ε }
Predictive Parser…FIRST
• The given grammar is left recursive.
Calculate the first for the • So, we first remove left recursion from the given
grammar.
given grammar:
After eliminating left recursion, we get the
S→A
following grammar-
A → aB / Ad S→A
B→b A → aBA’

C→g A’ → dA’ / ε
B→b
C→g
Predictive Parser…FIRST

Calculate the first for the given grammar:


S→A
A → aBA’
First(S) = First(A) = { a }
A’ → dA’ / ε
First(A) = { a }
B→b
First(A’) = { d , ε }
C→g
First(B) = { b }
First(C) = { g }
Predictive Parser…FIRST

Calculate the first for the given grammar:

S → (L) / a

L → SL’

L’ → ,SL’ / ε First(S) = { ( , a }

First(L) = First(S) = { ( , a }

First(L’) = { , , ∈ }
Predictive Parser…FOLLOW

◼ What if we have a "candidate" production A→ where =

or *?

◼ We could expand if we knew that there is some sentential

form where the current input symbol appears after A.

◼ Define:

◼ for A is Non-terminal, x  FOLLOW(A) iff  S *Ax


Predictive Parser…FOLLOW

Rules to find FOLLOW

◼ If S is the start symbol, FOLLOW (S) ={$}

◼ If production is of form A → α B β and FIRST (β) does not contain ε then,


FOLLOW (B) = {FIRST (β)}

◼ If production is of form A → αB or A → α B β where FIRST (β) contains ε (i. e. ,


β ⇒* ε), then

FOLLOW (B) = FIRST (β) − {ε} ∪ FOLLOW (A)

∵ when β derives ε, then terminal after A will follow B.


Predictive Parser…FIRST & FOLLOW
Calculate the follow for First(S) = { a }
First(B) = { c }
the given grammar: First(C) = { b , ε }
S → aBDh First(D) = { First(E) – ε} ∪ First(F) = { g , f , ε }
First(E) = { g , ε }
B → cC First(F) = { f , ε }
C → bC / ε
Follow(S) = { $ }
D → EF Follow(B) = { First(D) – ε } ∪ First(h) = { g , f , h }
E→g/ε Follow(C) = Follow(B) = { g , f , h }
Follow(D) = First(h) = { h }
F→f/ε
Follow(E) = { First(F) – ε} ∪ Follow(D) = { f , h }
Follow(F) = Follow(D) = { h }
Predictive Parser…FIRST & FOLLOW
• The given grammar is left recursive.
Calculate the follow for the • So, we first remove left recursion from the given
grammar.
given grammar:
After eliminating left recursion, we get the
S→A
following grammar-
A → aB / Ad S→A
B→b A → aBA’

C→g A’ → dA’ / ε
B→b
C→g
Predictive Parser…FIRST & FOLLOW
Calculate the follow for the
given grammar: Follow(S) = { $ }
S→A
A → aBA’ Follow(A) = Follow(S) = { $ }
A’ → dA’ / ε
B→b Follow(A’) = Follow(A) = { $ }
C→g
Follow(B) = { First(A’) – ε } ∪
First(S) = First(A) = { a }
First(A) = { a } Follow(A) = { d , $ }
First(A’) = { d , ε }
First(B) = { b } Follow(C) = NA
First(C) = { g }
Predictive Parser…FIRST & FOLLOW
Calculate the follow for First(S) = { ( , a }
the given grammar: First(L) = First(S) = { ( , a }
S → (L) / a First(L’) = { , , ∈ }
L → SL’
L’ → ,SL’ / ε

Follow(S) = { $ } ∪ { First(L’) – ε } ∪ Follow(L) ∪ Follow(L’) = { $ , , , ) }

Follow(L) = { ) }

Follow(L’) = Follow(L) = { ) }
Predictive Parser…Exercise FIRST - FOLLOW
Q.1
S → aAbc | BCf A→C|ε
B → Cd | c C → df | ε

Q.2
S → qABC A → a | bbD B→a|ε
C→b|ε D→c|ε

Q.3
A→B|C B→n|i
C → (D) D → DA | A
Predictive Parser…Non Recursive

INPUT a + b $

STACK X Predictive Parsing OUTPUT


Y Program
Z
$ ◼ Armed with
◼ FIRST
◼ FOLLOW
Parsing Table
◼ we can build a parser where
M[A,a] no backtracking is required!
Predictive Parser…Non Recursive

Parsing Table M[A,a]

◼ For each production A→ do:

◼ For each terminal a  FIRST() add A→ to entry M[A,a]

◼ If   FIRST(), add A→ to entry M[A,b] for each terminal


b  FOLLOW(A).

◼ If   FIRST() and $  FOLLOW(A), add A→ to M[A,$]

◼ Use table and stack to simulate recursion.


Predictive Parser…Non Recursive

E→TE' FIRST(E) = FIRST(T) = FIRST(F) = {(, id}


E'→+TE'| FIRST(E') = {+, }
T→FT' FIRST(T') = {*, }
T'→*FT'| FOLLOW(E) = FOLLOW(E') = {$, )}
F→(E) FOLLOW(T) = FOLLOW(T') = {+, $, )}
F→id FOLLOW(F) = {*, +, $, )}
Predictive Parser…Non Recursive
Parsing Table
+ * ( ) id $
E E→TE' E→TE'
E’ E'→+TE' E'→ E'→
T T→FT' T→FT'
T’ T'→ T'→*FT' T'→ T'→
F F→(E) F→id
+ MATCH
* MATCH
( MATCH
) MATCH
id MATCH
$ ACCEPT
Predictive Parser…LL(1) Parser
Parse the input id*id using the parse table
and a stack
Step Stack Input Action
1 $E id*id$
2 $E'T id*id$ E→TE'
3 $E'T'F id*id$ T→FT'
4 $E'T'id id*id$ F→id
5 $E'T' *id$ match id
6 $E'T'F* *id$ T'→*FT'
7 $E'T'F id$ match *
8 $E'T'id id$ F→id
9 $E'T' $ match id
10 $E‘ $ T'→
11 $ $ E'→
accept
Predictive Parser…LL(1) Parser

◼ Our parser scans the input Left-to-right, generates a Leftmost

derivation and uses 1 symbol of lookahead.


◼ It is called an LL(1) parser.

◼ If you can build a parsing table with no multiply-defined entries, then

the grammar is LL(1).


◼ Ambiguous grammars are never LL(1)

◼ Non-ambiguous grammars are not necessarily LL(1)


Predictive Parser…LL(1) Grammar
To check any GRAMMAR is LL(1) or not
◼ No ambiguous or left recursive grammar can be LL(1).
◼ Grammar G is LL(1) iff whenever A→ |  are two distinct productions of G
and:
➢ For no terminal a, both  and  derive strings beginning with a.
FIRST()  FIRST() = 
➢ At most one of  and  can derive the empty string.
➢ If *  , the  does not derive any string beginning with a terminal in
FOLLOW(A).
FIRST( )  FOLLOW(A)= 
Predictive Parser…LL(1) Parser

Steps to construct LL(1)

Parse the input


Compute first Construct
Remove left string with the
and follow of predictive
recursion. help of parsing
non terminal. parsing table.
table
Predictive Parser…LL(1) Parser

Error detection in LL(1) parsing


◼ An error is detected whenever an empty table slot is encountered.
◼ We would like our parser to be able to recover from an error and
continue parsing.
◼ Phase-level recovery
◼ We associate each empty slot with an error handling procedure.
◼ Panic mode recovery
◼ Modify the stack and/or the input string to try and reach state from
which we can continue.
Why Context Free Grammar

Role of parser

Parse tree

Ambiguous grammar

Parser Classification

Top-down parsing

Bottom-up parsing
Bottom Up Parsing

◼ Also known as Shift-reduce parsing

◼ Attempts to construct a parse tree for an input string beginning at

the leaves (bottom) and working up towards the root (top).


◼ “Reducing” a string w to the start symbol of a grammar.

◼ At each step, decide on some substring that matches the RHS of some

production
➢ Replace this string by the LHS (called reduction).
◼ If the substring is chosen correctly at each step, it is the trace of a

rightmost derivation in reverse.


Bottom Up Parsing…Handles

◼ Handle:- A handle of a string is a substring of the string that matches

the right side of a production, and we can reduce such string by a non
terminal on left hand side production.
◼ Handle Pruning:- The process of discovering a handle and reducing it

to appropriate left hand side non terminal is known as handle pruning.


Bottom Up Parsing
◼ Grammar:
S → aABe
A → Abc | b
B→d

◼ Reduction:
◼ Bottom-up parsing produces a
abbcde A→b
aAbcde A → Abc rightmost derivation…
aAde B→d …in reverse
aABe S → aABe
S
Bottom Up Parsing
Derivation

E→E+T/T n+n*n
T→T*F/F F+n*n F→n
F→(E)/n T+n*n T→F
E+n*n E→T
E+F*n F→n ◼ rightmost derivation…
E+T*n T→F
n+n*n E+T*F F→n
E+T T→T*F
E E→E+T
Bottom Up Parsing
It has following operations:
1. Shift:- Moving of the symbols from input buffer onto the stack, this action is

called shift.
2. Reduce:- If the handle appears on the top of the stack then reduction of it by

appropriate rule is done. That means R.H.S of the rule is popped of and L.H.S
is pushed in. This action is called Reduce action.
3. Accept:- If the stack contains start symbol only and input buffer is empty at

the same time then that action is called accept.


4. Error:- A situation in which parser cannot either shift or reduce the symbol, it

cannot even perform the accept action is called as error


Bottom Up Parsing

Stack Input Next Action E→E+T/T


T→T*F/F
$ n+n*n$ S
$ n +n*n$ R F→n F→(E)/n
$ F +n*n$ R T→F
$ T +n*n$ R E→T n+n*n
$ E +n*n$ S F+n*n F→n
$ E+ n*n$ S T+n*n T→F
$ E+ n *n$ R F→n E+n*n E→T
$ E+ F *n$ R T→F E+F*n F→n
$ E+ T *n$ S E+T*n T→F
$ E+ T* n$ S E+T*F F→n
$ E+ T*n $ R F→n E+T T→T*F
$ E+ T*F $ R T→T*F E E→E+T
$ E+ T $ R E→E+T
$ E $
Bottom Up Parsing… Operator Precedence Parsing
◼ Operator grammar
◼ small, but an important class of grammars
◼ we may have an efficient operator precedence parser (a shift-reduce parser)
for an operator grammar.
◼ In an operator grammar, no production rule can have:
◼  at the right side
◼ two adjacent non-terminals at the right side.
◼ Ex: E→AB E→EOE E→E+E |
A→a E→id E→ E*E |
B→b O→+|*|/ E→ E/E | id

not operator not operator Operator


grammar grammar grammar
Bottom Up Parsing… Operator Precedence Parsing

Precedence Relation
◼ Here we define three precedence relations between certain pairs of
terminals.

a <. b b has higher precedence than a


a =· b b has same precedence as a
a .> b b has lower precedence than a

◼ The determination of correct precedence relations between terminals are


based on the traditional notions of associativity and precedence of
operators. (Unary minus causes a problem).
Bottom Up Parsing… Operator Precedence Parsing
How to Create Operator-Precedence Relations
◼ We use associativity and precedence relations among operators.
1. If operator 1 has higher precedence than operator  2, then 1 .> 2 and 2 <. 1
2. If operator  1 and operator  2 have equal precedence,
they are left-associative then 1 .> 2 and 2 .> 1
they are right-associative then 1 <. 2 and 2 <. 1
3. For all operators 
 <. id , id .>  ,  <. ( , ( <.  ,  .> ) , ) .>  ,  .> $ , and $ <. 
1. Also, let
( =· ) $ <. ( $ <. id
( <. ( id .> $ ) .> $
( <. id id .> ) ) .> )
Bottom Up Parsing… Operator Precedence Parsing

How To Find The Handles


◼ The intention of the precedence relations is to find the handle of a right-
sentential form,
<. with marking the left end,
=· appearing in the interior of the handle, and
.> marking the right hand.

◼ In our input string $a1a2...an$, we insert the precedence relation between


the pairs of terminals.
Bottom Up Parsing… Operator Precedence Parsing

E → E + E | E - E | E * E | E / E | E ^ E | ( E ) | - E | id

The partial operator-precedence id + * $


id .> .> .>
table for this grammar
+ <. .> <. .>

* <. .> .> .>

$ <. <. <.


◼ Then the input string id + id * id with the precedence relations inserted will be:
$ <. id .> + <. id .> * <. id .> $
Bottom Up Parsing… Operator Precedence Parsing
1. Scan the string from left end until the first .> is encountered. id + * $
2. Then scan backwards (to the left) over any =· until a <. is id .> .> .>
encountered.
+ <. .> <. .>
3. The handle contains everything to left of the first .> and to the
* <. .> .> .>
right of the <. is encountered.
$ <. <. <.

$ <. id .> + <. id .> * <. id .> $ E → id $ id + id * id $


$ <. E + <. id .> * <. id .> $ E → id $ E + id * id $
$ <. E + <. E * <. id .> $ E → id $ E + E * id $
$ <. E + <. E * E .> $ E→E*E $E+ E*E$
$ <. E + E .> $ E→E+E $E+E$
$$ $E$
Bottom Up Parsing… Operator Precedence Parsing Algorithm
The input string is w$, the initial stack is $ and a table holds precedence relations between
certain terminals
Algorithm:
set p to point to the first symbol of w$ ;
repeat forever
if ( $ is on top of the stack and p points to $ ) then return
else {
let a be the topmost terminal symbol on the stack and let b be the symbol pointed to by p;
if ( a <. b or a =· b ) then
{ push b onto the stack; /* SHIFT */
advance p to the next input symbol;
}
else if ( a .> b ) then
repeat pop stack /* REDUCE */
until ( the top of stack terminal is related by <. to the terminal most recently
popped );
else error();
}
Bottom Up Parsing… Operator Precedence Parsing Example
stack input action
$ id+id*id$ $ <. id shift
$id +id*id$ id .> + reduce E → id id + * $
$ +id*id$ shift
id .> .> .>
$+ id*id$ shift
$+id *id$ id .> * reduce E → id
$+ *id$ shift + <. .> <. .>

$+* id$ shift * <. .> .> .>


$+*id $ id .> $ reduce E → id
$+* $ * .> $ reduce E → E*E $ <. <. <.
$+ $ + .> $ reduce E → E+E
$ $ accept
Bottom Up Parsing… Operator Precedence Parsing
Precedence Functions
g

id + * $ b
id .> .> .>
The table can be encoded by two precedence
+ <. .> <. .>
functions f and g that map terminal symbols to
f
* <. .> .> .>
integers.
$ <. <. <. For symbols a and b.
whenever a <. b f(a) < g(b) => fa  gb
whenever a =· b f(a) = g(b)
a
whenever a .> b f(a) > g(b) => fa → gb
Bottom Up Parsing… Operator Precedence Parsing
Precedence Functions For any a and b, if a <.b
id + * $
gid fid id .> .> .> , place an edge from the

+ <. .> <. .> group of gb to the


group of fa. Of a .> b,
f* g*
* <. .> .> .>
place an edge from the
$ <. <. <.
group of fa to that of gb.
g+ f+ + * id $
f 2 4 4 0
f$ g$ g 1 3 5 0
Bottom Up Parsing… Operator Precedence Parsing

◼ Disadvantages:
◼ It cannot handle the unary minus (the lexical analyzer should handle the
unary minus).
◼ Small class of grammars.
◼ Difficult to decide which language is recognized by the grammar.

◼ Advantages:
◼ simple
◼ powerful enough for expressions in programming languages
Bottom Up Parsing… Operator Precedence Parsing

Error Cases:
1. No relation holds between the terminal on the top of stack and the next
input symbol.
2. A handle is found (reduction step), but there is no production with this
handle as a right side

Error Recovery:
1. Each empty entry is filled with a pointer to an error routine.
2. Decides the popped handle “looks like” which right hand side. And tries
to recover from that situation.
Bottom Up Parsing… LR(k) Parser
L: left-to-right scanning of the input
R: constructing a rightmost derivation in reverse
k: the number of input symbols of lookahead that are used in making parsing
decisions. (default value is 1)
Bottom Up Parsing… LR(k) Parser

• The structure of LR parser consists of


input buffer for storing the input
string, a stack for storing the
grammar symbols, output and a
parsing table comprised of two parts,
namely actions and goto.
• There is one parsing program which
is actually driving program and reads
the input symbol one at a time from
the input buffer.
Bottom Up Parsing… LR(k) Parser

• The driving program works Possible Actions are


on following line. i. si means shift state i.
1. It initializes the stack with ii. rj means reduce by production rule j.
start symbol and invokes
scanner (lexical analyzer) iii. Accept means Successful parsing is done.
to get next token. iv. Error indicates syntactical error.
2. It determines sj the state
currently on the top of the
stack and ai the current
input symbol.
3. It consults the parsing
table for the action {sj, ai}
which can have one of the
values.
Bottom Up Parsing… LR(k) Parser

Action Table Entries


❖ The Action Table Entries Parser consults the Parsing table (Action
specifies the actions of the Entries) for the action {sj, ai} which can have
parser (e.g., shift or reduce), one of the values.
for the given parse state and i. si means shift state i.
the next token ii. rj means reduce by production rule j.
✓ Rows are State Names iii. Accept means Successful parsing is done.
✓ Columns are Terminals iv. Error indicates syntactical error.
Bottom Up Parsing… LR(k) Parser
Action Table Entries
If Action [Sm, ai] = Shift S
✓ Where S is a State, then the Parser pushes ai and S on to the Stack.
❖If Action [Sm, ai] = Reduce A → β,
✓ Then ai and Sm are replaced by A
✓ if S was the state appearing below ai in the Stack, then GOTO[S, A] is consulted
and the GOTO[S, A] entry (state) pushed onto the stack.
If Action [Sm, ai] = Accept,
✓ Parsing is completed
❖If Action [Sm, ai] = Error,
✓ The Parser discovered an Error.
Bottom Up Parsing… LR(k) Parser

GOTO Table Entries


❖ The GOTO table entries specifies which state to put on top of the stack after a reduce
✓ Rows are State Names;
✓ Columns are Non-Terminals
❖ The GOTO Table is important to find out the next state after every reduction.
❖ The GOTO Table is indexed by a state of the parser and a Non Terminal (Grammar
Symbol) ex : GOTO[S, A]
❖ The GOTO Table simply indicates what the next state of the parser if it has recognized
a certain Non Terminal
Bottom Up Parsing… LR(0) Parser

❖ The LR Parser is a Shift-reduce Parser that makes use of a Deterministic Finite

Automata, recognizing the Set Of All Viable Prefixes by reading the stack from

Bottom To Top.

❖ if a Finite-State Machine that recognizes viable prefixes of the right sentential

forms is constructed, it can be used to guide the handle selection in the Shift-reduce

Parser.

❖ 0 lookahead symbol
Bottom Up Parsing… LR(0) Parser

Augmented Grammar

❖ If G is a Grammar with Start Symbol S, the Augmented Grammar G’ is G

with a New Start Symbol S`, and New Production S` →S$.

❖ The Purpose of the Augmented Grammar is to indicate to the parser when it

should stop parsing and announce acceptance of the input


Bottom Up Parsing… LR(0) Parser
LR(0) Items (Parser States)
◼ A shift-reduce parser is always looking for the next handle
◼ An LR(0) Item of a Grammar G is a Production of G with a Dot ( ) at some position of the
right side.
◼ Production A → XYZ yields the four items
➢ A → .XYZ (We hope to see a string derivable from XYZ next on the input.)
➢ A → X.YZ ( After seeing a string derivable from X, we expect to see a string
derivable from YZ on the input.)
➢ A → XY.Z
➢ A → XYZ.
◼ The production A→ ε generates only one item, A→ •.
◼ Each of this item is a Viable prefixes
Bottom Up Parsing… LR(0) Parser
LR(0) Items (Parser States)
◼ We require Augmented Grammar and two Function
➢ Closure Operation

➢ GOTO Function

◼ Augmented Grammar for a grammar G(starting symbol S) is G’, start with a new
starting symbol S’, with S’ → S
◼ Closure Item : An Item created by the closure operation on a state.
◼ Complete Item : An Item where the Item Dot is at the end of the RHS.
Bottom Up Parsing… LR(0) Parser
LR(0) Items (Parser States) …Closure Operation

◼ If I is a set of items for a grammar G, then closure(I) is the set of items


constructed form I by two rules:
1. All elements of I are in closure(I)

2. If A → α • B β is in closure(I) and B →γ is a production in G, then B → • γ

is in closure(I)
3. Repeat until no new items are generated
Bottom Up Parsing… LR(0) Parser
LR(0) Items (Parser States) …Closure Operation

Augmented
Grammar

0: E’ → E
1: E→E+T
2: E→T
3: T→T*F
4: T→F
5: F→(E)
6: F → id
Bottom Up Parsing… LR(0) Parser
LR(0) Items (Parser States) …GOTO Function

◼ GOTO(I,X) : I is a set of items (States) and X is a grammar symbol


Bottom Up Parsing… LR(0) Parser
LR(0) Items (Parser States) …GOTO Function

◼ GOTO(I,X) : I is a set of items (States) and X is a grammar symbol

0: E’ → E
1: E→E+T
2: E→T
3: T→T*F
4: T→F
5: F→(E)
6: F → id
Bottom Up Parsing… LR(0) Parser
LR(0) Items (Parser States) …GOTO Function

◼ GOTO(I,X) : I is a set of items (States) and X is a grammar symbol

0: E’ → E
1: E→E+T
2: E→T
3: T→T*F
4: T→F
5: F→(E)
6: F → id
Bottom Up Parsing… LR(0) Parser
LR(0) Items (Parser States) …Example
A very simple grammar: I1: GOTO(I0, S)
S’ → S
S → aSb | ab I1: S’ → S.
I0: S’ → .S
S → .aSb I3: GOTO(I2, S)
Closure(S)
S → .ab
I3: S → aS.b
I2: GOTO(I0, a)
I2: GOTO(I0, a) I4: GOTO(I2, b)

I2: S → a.Sb I4: S → ab.


S → a.b
S → .aSb I5: GOTO(I3, b)
Closure(S)
S → .ab I5: S → aSb.
I2: GOTO(I2, a)
Bottom Up Parsing… LR(0) Parser
LR(0) Items (Parser States) …Example
Bottom Up Parsing… LR(0) Parser
Construction of LR(0) Parsing Table

Compute the action function entries:


-- If [A → α•a β]  Ii and goto(Ii ,a) = Ij then set action[i , a]=shift j (a is
terminal)
-- If [A→α•]  Ii then set action[i , a] = reduce A → α for all terminals
-- If [S ’→S•] is in Ii then set action[i , $] = accept
-- all undefined entries are error entries (i.e. blank)
Compute the GOTO (next) state entries:
-- If goto(Ii , A) = Ij then set goto[i , A] = j
all undefined entries are error entries (i.e. blank)
Bottom Up Parsing… LR(0) Parser
Construction of LR(0) Parsing Table
Ex: E’ → E
E→E+T|T
T→T*F|F
F → ( E ) | id
id

id
Bottom Up Parsing… LR(0) Parser
LR(0) Items (Parser States) …Example I6: E → E + . T
T→.T*F
Ex: E’ → E I2: E → T. T→.F
E→E+T|T T → T. * F F→.(E)
T→T*F|F F → . id
I3: T → F.
F → ( E ) | id
I7: T → T * . F
I4: F → (. E) F→.(E)
I0: E’ → . E E→.E+T F → . id
E→.E+T E→.T
E→.T T→.T*F I8: F → ( E .)
T→.T*F T→.F E→E.+T
T→.F F→.(E)
F→.(E) F → . id I9: E → E + T.
F → . id T→T.*F

I1: E’ → E . I5: F → id . I10: T → T * F .


E→E.+T
I11: F → ( E).
Bottom Up Parsing… LR(0) Parser
LR(0) Parser…Conflicts
“shift/reduce” or “reduce/reduce”
Example:
We can’t tell whether it is
I1: E’ → E .
a handle E→E.+T

Stack Input
if … then stmt else … Shift/ Reduce Conflict
Bottom Up Parsing… LR(0) Parser
LR(0) Parser…Conflicts
“shift/reduce” or “reduce/reduce”
Example: stmt → if expr then stmt
We can’t tell whether it is | if expr then stmt else stmt
a handle
| other (any other statement)

Stack Input
if … then stmt else … Shift/ Reduce Conflict
Bottom Up Parsing… LR(0) Parser
Draw backs of LR(0) Parser

❖ LR(0) Parsers are too weak to be of practical use

❖ LR(0) accepts only small class of LR(0) grammar because if conflicts occurs.

Shift/ Reduce Conflict Reduce / Reduce Conflict

❖ The Fundamental Limitation of LR(0) is that no look-ahead tokens are used.


Bottom Up Parsing… SLR(1) Parser
• SLR(1) Parser is used for accepting the certain grammar which is not
accepted by LR(0) parser
• SLR(1) Parser stands for Simple LR(1).
• The difference in SLR(1) Parser with LR(0) Parser comes in Assigning Table
Actions
• SLR(1) Parsers are going to use one token of lookahead to eliminate the
conflicts.
• The Simple Improvement that SLR(1) makes on the basic LR(0) parser is to
reduce only if the next input token is a member of the Follow Set of the
nonterminal being reduced.
Bottom Up Parsing… SLR(1) Parser

• SLR(1) parser will perform a reduce action for configuration B→a• if the

lookahead symbol is in the set Follow(B)

• A Grammar is an SLR(1) grammar if there is no conflict in the grammar.

• Clearly SLR(1) is a proper superset of LR(0)

SLR(1)
LR(0)
Bottom Up Parsing… SLR(1) Parser

SLR(1) (“simple LR”) Parsing


Table 0: E’→E
Uses input lookahead in 1: E → E + T
addition to the LR(0) table to 2: E → T
3: T → T * F
determine parsing actions

4: T → F
5: F → ( E )
6: F → id
Bottom Up Parsing… SLR(1) Parser
GOTO (E) I1: E’ → E . s0 s1
I0: E’ → . E
E→E.+T
E→.E+T I2: E → T.
T → T. * F s0 s2
E→.T
T→.T*F I3: T → F.
s0 s3
I4: F → (. E)
T→.F E→.E+T
E→.T s0 s4
F→.(E) T→.T*F
T→.F
F → . id F→.(E)
F → . id
I5: F → id . s0 s5

STATE ACTION GOTO


id + * ( ) $ E T F
0 S5 S4 1 2 3
Bottom Up Parsing… SLR(1) Parser
If [S’→S •] is in Ii then 0: E’ → E
I1: E’ → E . 1: E → E + T
set action[i,$] = accept 2: E → T
E→E.+T 3: T → T * F
4: T → F
I6: E → E + . T 5: F → ( E )
T→.T*F 6: F → id
T→.F s1 s6
F→.(E)
F → . id

STATE ACTION GOTO


id + * ( ) $ E T F
0 S5 S4 1 2 3
1 S6 ACCEPT
Bottom Up Parsing… SLR(1) Parser
REDUCE ITEM
so looking at follow set FOLLOW( E ) = { +, ), $}
I2: E → T.
If [A→α•]  Ii then set action[i ,a] =
T → T. * F reduce A → α for all a  FOLLOW(A)
(apply only if A ≠ S ’)
I7: T → T * . F
F→.(E)
s2 s7
F → . id

STATE ACTION GOTO 0: E’ → E


1: E → E + T
id + * ( ) $ E T F 2: E → T
3: T → T * F
0 S5 S4 1 2 3 4: T → F
5: F → ( E )
1 S6 ACCEPT 6: F → id

2 R2 S7 R2 R2
Bottom Up Parsing… SLR(1) Parser

0: E’ → E
1: E → E + T
2: E → T
3: T → T * F
4: T → F
5: F → ( E )
6: F → id
Bottom Up Parsing… SLR(1) Parser
Stack Input Action
0: E’ → E
1: E → E + T $0 n*n+n$ Shift 5
2: E → T $0n5 *n+n$ Reduce 6
3: T → T * F
4: T → F $0F3 *n+n$ Reduce 4
5: F → ( E ) $0T2 *n+n$ Shift 7
6: F → id
$0T2*7 n+n$ Shift 5
$0T2*7n5 +n$ Reduce 6
$ 0 T 2 * 7 F 10 +n$ Reduce 3
$0T2 +n$ Reduce 2
$0E1 +n$ Shift 6
$0E1+6 n$ Shift 5
$0E1+6n5 $ Reduce 6
$0E1+6F3 $ Reduce 4
$0E1+6T9 $ Reduce 1
$0E1 $ ACCEPT
Bottom Up Parsing… SLR(1) Parsing Conflicts

◼ If a state contains inconsistent items, then the grammar is not LR(0)

◼ E → E + T·, T → T· * F both are in same state

◼ SHIFT/REDUCE conflict

◼ E → E + E· | E * E· both are in same state

◼ REDUCE/REDUCE conflict

◼ Most “real” grammars are not LR(0)


Bottom Up Parsing… SLR(1) Parsing Conflicts
• Every SLR grammar is unambiguous, but not every unambiguous
grammar is SLR
• Consider for example the unambiguous grammar
S →L=R|R L → * R | id R →L
Bottom Up Parsing… SLR(1) Parsing Conflicts

S →L=R|R L → * R | id R →L
S6
read state:
lookup the state I2 next symbol is =

∩ intersection operation
I2: R5
reduce state:
S → L•=R FOLLOW ( R ) ={ =, $ }

R → L•
Result is { = }
so SHIFT/REDUCE conflict is here
Bottom Up Parsing… SLR(1) Parsing Conflicts
Ex.1 S → CC Ex.3 S → xAy | xBy | xAz
C → cC A → aS | q
C→d B→q

Ex.2 S → AaAb
Ex.4 S → aSbS | bSaS | ε
S → BbBa
A→ε
B→ε
Bottom Up Parsing…CLR(1) and LALR(1)

◼ LR(1) (“canonical LR - CLR”)

◼ Incorporates input lookahead into LR items (LR(1) items)

◼ LALR(1) (“lookahead LR”)

◼ Uses more compact LR(1) items


Bottom Up Parsing…Canonical LR(1) Parsing

S →L=R|R L → * R | id R →L

❖ Reduce state so L can be reduce into R


I 2:
❖ But there is no Right sentential form that begins R = … in
S → L•=R
the grammar
R → L•
❖ So it is not a valid reduce operation for the parsing
❖ How this type of information is added with parsing method
❖ Concept of LR(1) item set (i.e. item set with one lookahead
symbol)
Bottom Up Parsing…Canonical LR(1) Parsing

LR(1) Items
• LR(1) item = LR(0) item + lookahead

LR(0) item: LR(1) item:


[A → α•β] [A → α•β, a]
• An LR(1) item [A → α•β, a] contains a lookahead terminal a, meaning α
already on top of the stack, expect to see βa
• For items of the form [A → α•, a] the lookahead a is used to reduce A → α
only if the next input is a
• For items of the form [A → α•β, a] with β ≠ ε the lookahead has no effect
Bottom Up Parsing…Canonical LR(1) Parsing

The Closure Operation for LR(1) Items


1. Start with closure(I) = I D
2. If [A → α•Bβ, a]  closure(I) then for each
S e
production B → γ in the grammar and each terminal

b  FIRST(βa), add the item [B → •γ, b] to I if it is not a A d


already in I
b
3. Repeat 2 until no new items can be added
Bottom Up Parsing…Canonical LR(1) Parsing

The GOTO Operation for LR(1) Items

1. For each item [A → α•Xβ, a]  I, add the set of items

closure({[A → αX•β, a]}) to goto(I,X) if not already there

2. Repeat step 1 until no more items can be added to goto(I,X)


Bottom Up Parsing…Canonical LR(1) Parsing
Ex: GOTO(I0, c) = I3 GOTO(I2, d) = I7
S’ → S LR(1)
I3: C → c . C, c/d I7: C → d . , $
S→CC Items C → . c C, c/d
C→cC/d C → .d, c/d
GOTO(I3, C) = I8
I8: C → c C . , c/d
I0 : S’→ . S, $ GOTO(I0, d) = I4
S → . C C, $ GOTO(I3, c) = I3
I4: C → d . , c/d
C → . c C, c/d GOTO(I3, d) = I4
C → . d, c/d
GOTO(I2, C) = I5
GOTO(I0, S) = I1 GOTO(I6, C) = I9
I5: S → C C . , $
I9: C → c C . , $
I1: S’ → S . , $
GOTO(I2, c) = I6 GOTO(I6, c) = I6
GOTO(I0, C) = I2
I6: C → c . C, $ GOTO(I6, d) = I7
I2: S → C . C, $ C → . c C, $
C → . c C, $ C → .d, $
C → . d, $
Bottom Up Parsing…Canonical LR(1) Parsing
S→L=R|R
L → * R | id
R→L
Bottom Up Parsing…Canonical LR(1) Parsing
Constructing Canonical LR(1) Parsing Tables

Compute the Action entries

-- If [A → •a, b]  Ii and goto(Ii ,a) = Ij then set action[i,a] = shift j

-- If [A → •, a]  Ii then set action[i,a] = reduce A →  (apply only if A  S’)

-- If [S’ → S•, $] is in Ii then set action[i,$] = accept

-- all undefined entries are error entries (i.e. blank)

Compute the Goto entries

-- If goto(Ii,A) = Ij then set goto[i,A] = j


Bottom Up Parsing…Canonical LR(1) Parsing
Constructing Canonical LR(1) Parsing Tables

Ex:
S’ → S
S→CC
C→cC/d
Bottom Up Parsing…LALR(1) Parsing

Look Ahead L(1) Parsing Tables

• LALR(1) parsing (Look-Ahead LR) combines LR(1) states to reduce table size

• Space savings over LR(k)

• Less powerful than LR(1) / CLR(1)

• Combine 2 states if they have the same core items and compatible goto functions

• If cannot combine 2 states, then grammar is not LALR(1) but still LR(1).
Bottom Up Parsing…LALR(1) Parsing
Ex: I0 : S’→ . S, $ GOTO(I0, S) = I1
S → . C C, $ GOTO(I0, C) = I2
S’ → S C → . c C, c/d GOTO(I0, c) = I3
S→CC C → . d, c/d GOTO(I0, d) = I4
C→cC/d
I1: S’ → S . , $
I6: C → c . C, $ GOTO(I6, C) = I9
C → . c C, $ GOTO(I6, c) = I6
I2: S → C . C, $ GOTO(I2, C) = I5 C → .d, $ GOTO(I6, d) = I7
C → . c C, $ GOTO(I2, c) = I6
C → . d, $ GOTO(I2, d) = I7
I7: C → d . , $
I3: C → c . C, c/d GOTO(I3, C) = I8
C → . c C, c/d GOTO(I3, c) = I3
I8: C → c C . , c/d
C → .d, c/d GOTO(I3, d) = I4

I9: C → c C . , $
I4: C → d . , c/d
I5: S → C C . , $
Bottom Up Parsing…LALR(1) Parsing
I0 : S’→ . S, $
Ex: S → . C C, $
C → . c C, c/d
S’ → S I47: C → d . , c/d / $
C → . d, c/d
S→CC
C→cC/d I1: S’ → S . , $ I5: S → C C . , $

I2: S → C . C, $
C → . c C, $ I89: C → c C . , c/d / $
C → . d, $

I36: C → c . C, c/d / $
C → . c C, c/d / $
C → .d, c/d / $
Bottom Up Parsing…LALR(1) Parsing
Ex:
S’ → S
S→CC
C→cC/d
Bottom Up Parsing…Error Recovery
❑ Panic mode
➢ Pop until state with a goto on a nonterminal A is found, (where A
represents a major programming construct), push A
➢ Discard input symbols until one is found in the FOLLOW set of A
❑ Phrase-level recovery
➢ Implement error routines for every error entry in table
❑ Error productions
➢ Pop until state has error production, then shift on stack
➢ Discard input until symbol is encountered that allows parsing to continue
LL(1) V/S LR(1)

You might also like