Botttom Up Parsing
Botttom Up Parsing
(Lecturer,CSE)
Parsing Techniques
“Shift-Reduce” Parsing
Reduce a string to the start symbol of the grammar.
At every step a particular sub-string is matched (in left-to-
right fashion) to the right side of some production and then
it is substituted by the non-terminal in the left hand side of
the production.
Consider: Reverse
abbcde order
S aABe
aAbcde
A Abc | b
aAde
Bd
aABe
S
Rightmost Derivation:
S aABe aAde aAbcde abbcde
Handles
Consider:
S aABe
A Abc | b
Bd
It follows that:
S aABe is a handle of aABe in location 1.
B d is a handle of aAde in location 3.
A Abc is a handle of aAbcde in location 2.
A b is a handle of abbcde in location 2.
Handle Pruning
Two problems:
locate a handle and
decide which production to use (if there are more than two
candidate productions).
$E + E * id $ Reduce by E id
$E + E * E $ Reduce by E E * E
$E + E $ Reduce by E E + E
$E $ Accept
Shift-reduce Parsing
Viable prefixes:
The set of prefixes of a right sentential form that can appear on the
stack of a Shift-Reduce parser is called Viable prefixes.
Conflicts
“shift/reduce” or “reduce/reduce”
Example:
stmt if expr then stmt
We can’t tell
| if expr then stmt else stmt
whether it is a
handle | other (any other statement)
Stack Input
if … then stmt else … Shift/ Reduce Conflict
More Conflicts
stmt id ( parameter-list )
stmt expr := expr
parameter-list parameter-list , parameter | parameter
parameter id
expr-list expr-list , expr | expr
expr id | id ( expr-list )
Consider the string A(I,J)
Corresponding token stream is id(id, id)
After three shifts:
How the symbol third from the top of stack determines the reduction to be made,
even though it is not involved in the reduction. Shift-reduce parsing can utilize
information far down in the stack to guide the parse.
Operator-Precedence Parser
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:
EAB EEOE EE+E |
Aa Eid E*E |
Bb | id O+|*|/ E/E
* <. >
.
>
.
>
.
1. Scan the string from left end until the first .> is encountered.
2. Then scan backwards (to the left) over any =· until a <. is
encountered.
3. The handle contains everything to left of the first .> and to
the right of the <. is encountered.
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 { /* SHIFT */
push b onto the stack;
advance p to the next input symbol;
}
else if ( a .> b ) then /* REDUCE */
repeat pop stack
until ( the top of stack terminal is related by <. to the terminal most
recently popped );
else error();
}
Operator-Precedence Parsing Algorithm -- Example
* <. >
.
>
.
>
.
3. For all operators , <. id, id .> , <. (, (<. , .> ), ) .> , .> $, and
$ <.
4. Also, let
(=·) $ <. ( id .> ) ) .> $
( <. ( $ <. id id .> $ ) .> )
( <. id
Operator-Precedence Relations
+ - * / ^ id ( ) $
+ .
> .
> <. <. <. <. <. .
> .
>
- .
> .
> <. <. <. <. <. .
> .
>
* .
> .
> .
> .
> <. <. <. .
> .
>
/ .
> .
> .
> .
> <. <. <. .
> .
>
^ .
> .
> .
> .
> <. <. <. .
> .
>
id .
> .
> .
> .
> .
> .
> .
>
( <. <. <. <. <. <. <. =·
) .
> .
> .
> .
> .
> >
.
>
.
The best approach to solve this problem, let the lexical analyzer
handle this problem.
The lexical analyzer will return two different tokens for the unary
minus and the binary minus.
The lexical analyzer will need a lookhead to distinguish the
binary minus from the unary minus.
Then, we make
<. unary-minus for any operator
Precedence Functions
Method:
1. Create symbols fa and gb for each a that is a terminal or $.
2. Partition the created symbols into as many groups as possible, in
such a way that if a =. b, then fa and gb are in the same group.
3. Create a directed graph whose nodes are the groups found in (2).
For any a and b, if a <.b , place an edge from the group of gb to the
group of fa. Of a .> b, place an edge from the group of fa to that of
gb.
4. If the graph constructed in (3) has a cycle, then no precedence
functions exist. If there are no cycle, let f(a) be the length of the
longest path beginning at the group of fa; let g(a) be the length of
the longest path beginning at the group of ga.
Example
+ * Id $
f 2 4 4 0
gid fid
g 1 3 5 0
f* g*
g+ f+
f$ g$
Disadvantages of 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
Error Recovery in 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.