Anda di halaman 1dari 12

# Outline

Introduction to Bottom-Up Parsing Lecture Notes by Profs. Alex Aiken and George Necula (UCB)

The strategy: shift-reduce parsing A key concept: handles Ambiguity and precedence declarations

L12BUP

L12BUP

## Predictive Parsing Summary

First and Follow sets are used to construct predictive tables For non-terminal A and input t, use a production A where t First() For non-terminal A and input t, if t Follow() and

## Bottom-Up Parsing Bottom-up parsing is more general than topdown parsing.

Dont need left-factored grammars. Left recursion fine. Just as efficient. Builds on ideas in top-down parsing.

First()

## Bottom-up parsing is the preferred method in practice.

Automatic parser generators: YACC, Bison,

L12BUP

An Introductory Example

The Idea Bottom-up parsing reduces a string to the start symbol by inverting productions:
int * int + int int * T + int T + int T+T T+E E

## Revert to the natural grammar for our example:

ET+E|T T int * T | int | (E)

## int * int + int

L12BUP

L12BUP

Observation Read the sequence of productions in reverse (from bottom to top) This is a rightmost derivation!
int * int + int int * T + int T + int T+T T+E E

Important Fact #1

L12BUP 7

## A bottom-up parser traces a rightmost derivation in reverse. LR-parser

L12BUP

A Bottom-up Parse
int * int + int int * T + int T + int T+T T+E E

int
L12BUP

int

int
10

L12BUP

## A Bottom-up Parse in Detail (2)

int * int + int int * T + int

## A Bottom-up Parse in Detail (3)

int * int + int int * T + int T + int

T T

T int

int

int

int
L12BUP

int

int
12

## A Bottom-up Parse in Detail (4)

int * int + int int * T + int T + int T+T

int * int + int

13

T T int * int +

E T int
14

L12BUP

L12BUP

## A Bottom-up Parse in Detail (6)

int * int + int int * T + int T + int T+T T+E E

A Trivial Bottom-Up Parsing Algorithm E Let I = input string repeat pick a non-empty substring of I where X is a production if no such , backtrack replace one by X in I until I = S (the start symbol) or all possibilities are exhausted

T T int * int +

E T int
15

L12BUP

Questions Does this algorithm terminate? How fast is the algorithm? Does the algorithm deal with all cases? How do we choose the substring to reduce at each step?

## Where Do Reductions Happen Important Fact #1 has an interesting consequence:

Let be a step of a bottom-up parse. Assume the next reduction is by X . Then is a string of terminals.

L12BUP

18

## Notation Idea: Split string into two substrings.

Right substring is as yet unexamined by parser (hence is a string of terminals). Left substring has terminals and non-terminals.

Shift-Reduce Parsing
Bottom-up parsing uses only two kinds of actions:

## Shift: Move | one place to the right.

Shifts a terminal to the left string

ABC|xyz ABCx|yz

## The dividing point is marked by a |

The | is not part of the string.

Reduce: Apply an inverse production at the right end of the left string.
If A xy is a production, then

|x1x2 . . . xn

Cbxy|ijk CbA|ijk
L12BUP 20

## The Example with Shift-Reduce Parsing

|int * int + int shift shift shift reduce reduce shift shift reduce reduce int | * int + int int * | int + int int * int | + int int * T | + int T | + int T + | int T + int | T+T| T+E| E|

T int T int * T

T int ET

reduce E T + E
22

L12BUP

21

|int * int + int

## A Shift-Reduce Parse in Detail (2)

|int * int + int int | * int + int

int

int

int

int

L12BUP

int

int
24

## A Shift-Reduce Parse in Detail (3)

|int * int + int int | * int + int int * | int + int

## A Shift-Reduce Parse in Detail (4)

|int * int + int int | * int + int int * | int + int int * int | + int

int

int

int

int
L12BUP

int

int
26

## A Shift-Reduce Parse in Detail (5)

|int * int + int int | * int + int int * | int + int int * int | + int int * T | + int

## A Shift-Reduce Parse in Detail (6)

|int * int + int int | * int + int int * | int + int int * int | + int int * T | + int T | + int

T T

T int

int

int

int
L12BUP

int

int
28

## A Shift-Reduce Parse in Detail (7)

|int * int + int int | * int + int int * | int + int int * int | + int int * T | + int T | + int T + | int

## A Shift-Reduce Parse in Detail (8)

|int * int + int int | * int + int int * | int + int int * int | + int int * T | + int T | + int T + | int T + int |

T T int * int +

29

30

int

L12BUP

L12BUP

## A Shift-Reduce Parse in Detail (9)

|int * int + int int | * int + int int * | int + int int * int | + int int * T | + int T | + int T + | int T + int | T+T|

## A Shift-Reduce Parse in Detail (10)

|int * int + int int | * int + int int * | int + int int * int | + int int * T | + int T | + int T + | int T + int | T+T|
31

T T int
L12BUP

T T int
L12BUP

E T + int

32

T + int

int

T+E|

int

## A Shift-Reduce Parse in Detail (11)

|int * int + int int | * int + int int * | int + int int * int | + int int * T | + int T | + int T + | int T + int | T+T| T+E| E|

## The Stack Left string can be implemented by a stack

Top of the stack is the |

E T T int
L12BUP

E T + int

33

Shift pushes a terminal on the stack. Reduce pops 0 or more symbols off the stack (production rhs) and pushes a non-terminal on the stack (production lhs).

int

Shift-Reduce Parser
Parser Action

## Key Issue How do we decide when to shift or reduce?

Consider step int | * int + int We could reduce by T int giving T | * int + int A fatal mistake: Because there is no way to reduce to the start symbol E.
ET+E|T T int * T | int | (E)

stack

Stack

## Parser Engine Current Symbol

Handles Intuition: Want to reduce only if the result can still be reduced to the start symbol. Assume a rightmost derivation: S =>* X Then is a handle of .

Handles (Cont.) A handle is a string that can be reduced, and that also allows further reductions back to the start symbol. We only want to reduce at handles. Note: We have said what a handle is, not how to find handles.

L12BUP

## Important Fact #2 Important Fact #2 about bottom-up parsing:

Why? Informal induction on # of reduce moves: True initially, stack is empty Immediately after reducing a handle
right-most non-terminal on top of the stack. next handle must be to right of right-most nonterminal, because this is a right-most derivation. Sequence of shift moves reaches next handle.

In shift-reduce parsing, handles appear only at the top of the stack, never inside.

L12BUP

39

L12BUP

40

Summary of Handles In shift-reduce parsing, handles always appear at the top of the stack. Handles are never to the left of the rightmost non-terminal.
Therefore, shift-reduce moves are sufficient; the | need never move left.

## Conflicts Generic shift-reduce strategy:

If there is a handle on top of the stack, reduce Otherwise, shift

## Bottom-up parsing algorithms are based on recognizing handles.

If it is legal to shift or reduce, there is a shiftreduce conflict. If it is legal to reduce by two different productions, there is a reduce-reduce conflict.
L12BUP 42

Source of Conflicts Ambiguous grammars always cause conflicts. But beware, so do many non-ambiguous grammars. Consider our favorite ambiguous grammar:
E | | |

## One Shift-Reduce Parse

|int * int + int ... E * E | + int E | + int E + | int E + int| E+E| E| shift ... reduce E E * E shift shift reduce E int reduce E E + E

43

L12BUP

44

## Another Shift-Reduce Parse

|int * int + int ... E * E | + int E * E + | int E * E + int | E * E + E| E*E| E| shift ... shift shift reduce E int reduce E E + E reduce E E * E

Example Notes In the second step E * E | + int, we can either shift or reduce by E E * E. Choice determines associativity and precedence of + and *. As noted previously, grammar can be rewritten to enforce precedence. Precedence declarations are an alternative.