LR(1) Languages An Introduction Professor Yihjia Tsai Tamkang University.

51
LR(1) Languages An Introduction Professor Yihjia Tsai Tamkang University
  • date post

    21-Dec-2015
  • Category

    Documents

  • view

    223
  • download

    0

Transcript of LR(1) Languages An Introduction Professor Yihjia Tsai Tamkang University.

LR(1) LanguagesAn Introduction

Professor Yihjia TsaiTamkang University

2

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 First(A) and t Follow(), then use a production A where First()

• We’ll see First and Follow sets again . . .

3

Bottom-Up Parsing

• Bottom-up parsing is more general than top-down parsing– And just as efficient– Builds on ideas in top-down parsing

• Bottom-up is the preferred method in practice

• Concepts today, algorithms next time

4

An Introductory Example

• Bottom-up parsers don’t need left-factored grammars

• Hence we can revert to the “natural” grammar for our example:

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

• Consider the string: int * int + int

5

The Idea

Bottom-up parsing reduces a string to the start symbol by inverting

productions:

int * int + int T int

int * T + int T int * T

T + int T int

T + T E T

T + E E T + E

E

6

Terminology

• DerivationSequence starting with the start symbol S and proceeding

through a sequence of derivation steps• Derivation step

A non-terminal on the left side of a derivation is replacedby the right hand side of a production rule in the next stepof the derivation

A if

A is a production, and, are arbitrary strings of grammar symbols

• Sentential FormAny derivation step

• SentenceSentential form with no non-terminals

7

• Grammar EE + E | E * E | ( E ) | - E | id• Simple derivatiozn E - E• Derivation of -(id+id) E -E -(E) -(E+E) -(id+E) -(id+id)

E -(id+id) derives it1 2 … n or simply

Select a nonterminal to replace and an alternative at each step of a derivation

Derivation example

8

Leftmost Derivation

• The derivationE -E -(E) -(E+E) -(id+E) -(id+id)

is leftmost which we designate as E lm -E lm -(E) lm

-(E+E) lm -(id+E) lm -(id+id)

• A sentential form is a derivation step.• A leftmost derivation step is a left

sentential form, for example:

• (Denoted *lm for typographical

convenience)

lm

9

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 most of the time

10

Rightmost Derivation

• The rightmost non-terminal is replaced in the derivation process in each step.

• Also referred to as Canonical Derivation

• Right sentential form: a sentential form produced via a rightmost derivation– If S *, then is a sentential form of the

CFG– If S *

rm, then is a right sentential form

11

Right Sentential Form

Grammar: S aABeA Abc | bB d

• Reduce abbcde to S by four stepsabbcdeaAbcdeaAdeaABeS

Why not chose

d here?

12

TEST YOURSELF #1

• Question: find the rightmost derivation of the string int * int + int

13

Observation

• Read the productions found by bottom-up parse in reverse (i.e., from bottom to top)

• This is a rightmost derivation!int * int + int T int

int * T + int T int * T

T + int T int

T + T E T

T + E E T + E

E

14

Important Fact #1

Important Fact #1 about bottom-up parsing:

A bottom-up parser traces a rightmost derivation in reverse

15

A Bottom-up Parse

int * int + int

int * T + int

T + int

T + T

T + E

E

E

T E

+ int

*int

T

int

T

16

A Bottom-up Parse in Detail (1)

+ int

*int int

int * int + int

17

A Bottom-up Parse in Detail (2)

int * int + int

int * T + int

+ int

*int int

T

18

A Bottom-up Parse in Detail (3)

int * int + int

int * T + int

T + intT

+ int

*int int

T

19

A Bottom-up Parse in Detail (4)

int * int + int

int * T + int

T + int

T + T

T

+ int

*int

T

int

T

20

A Bottom-up Parse in Detail (5)

int * int + int

int * T + int

T + int

T + T

T + E

T E

+ int

*int

T

int

T

21

A Bottom-up Parse in Detail (6)

int * int + int

int * T + int

T + int

T + T

T + E

E

E

T E

+ int

*int

T

int

T

22

A Trivial Bottom-Up Parsing Algorithm

Let I = input stringrepeat

pick a non-empty substring of Iwhere X is a production

if no such , backtrackreplace one by X in I

until I = “S” (the start symbol) or all possibilities are exhausted

23

Questions

• Does this algorithm terminate?

• How fast is the algorithm?

• Does the algorithm handle all cases?

• How do we choose the substring to reduce at each step?

24

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

Why? Because X is a step in a right-most derivation

25

Notation

• Idea: Split string into two substrings– Right substring is as yet unexamined by

parsing (a string of terminals)– Left substring has terminals and non-terminals

• The dividing point is marked by a |– The | is not part of the string

• Initially, all input is unexamined |x1x2 . . . xn

26

Shift-Reduce Parsing

Bottom-up parsing uses only two kinds of actions:

Shift

Reduce

27

Shift

• Shift: Move | one place to the right– Shifts a terminal to the left string

ABC|xyz ABCx|yz

28

Reduce

• Apply an inverse production at the right end of the left string– If A xy is a production, then

Cbxy|ijk CbA|ijk

29

The Example with Reductions Only

int * int | + int reduce T int

int * T | + int reduce T int * T

T + int | reduce T int

T + T | reduce E T

T + E | reduce E T + E

E |

30

The Example with Shift-Reduce Parsing

|int * int + int shift

int | * int + int shift

int * | int + int shift

int * int | + int reduce T int

int * T | + int reduce T int * T

T | + int shift

T + | int shift

T + int | reduce T int

T + T | reduce E T

T + E | reduce E T + E

E |

31

A Shift-Reduce Parse in Detail (1)

+ int

*int int

|int * int + int

32

A Shift-Reduce Parse in Detail (2)

+ int

*int int

|int * int + int

int | * int + int

33

A Shift-Reduce Parse in Detail (3)

+ int

*int int

|int * int + int

int | * int + int

int * | int + int

34

A Shift-Reduce Parse in Detail (4)

+ int

*int int

|int * int + int

int | * int + int

int * | int + int

int * int | + int

35

A Shift-Reduce Parse in Detail (5)

+ int

*int int

T

|int * int + int

int | * int + int

int * | int + int

int * int | + int

int * T | + int

36

A Shift-Reduce Parse in Detail (6)

T

+ int

*int int

T

|int * int + int

int | * int + int

int * | int + int

int * int | + int

int * T | + int

T | + int

37

A Shift-Reduce Parse in Detail (7)

T

+ int

*int int

T

|int * int + int

int | * int + int

int * | int + int

int * int | + int

int * T | + int

T | + int

T + | int

38

A Shift-Reduce Parse in Detail (8)

T

+ int

*int int

T

|int * int + int

int | * int + int

int * | int + int

int * int | + int

int * T | + int

T | + int

T + | int

T + int |

39

A Shift-Reduce Parse in Detail (9)

T

+ int

*int

T

int

T

|int * int + int

int | * int + int

int * | int + int

int * int | + int

int * T | + int

T | + int

T + | int

T + int |

T + T |

40

A Shift-Reduce Parse in Detail (10)

T E

+ int

*int

T

int

T

|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 |

41

A Shift-Reduce Parse in Detail (11)

E

T E

+ int

*int

T

int

T

|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 |

42

The Stack

• Left string can be implemented by a stack– Top of the stack is the |

• Shift pushes a terminal on the stack

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

43

Key Issue (will be resolved by algorithms)

• 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: No way to reduce to

the start symbol E

44

Conflicts

• Generic shift-reduce strategy:– If there is a handle on top of the stack, reduce– Otherwise, shift

• But what if there is a choice?– If it is legal to shift or reduce, there is a

shift-reduce conflict– If it is legal to reduce by two different

productions, there is a reduce-reduce conflict

45

Source of Conflicts

• Ambiguous grammars always cause conflicts

• But beware, so do many non-ambiguous grammars

46

Conflict Example

Consider everybody's favorite ambiguous grammar:

E E + E

| E * E

| (E)

| int

47

One Shift-Reduce Parse

|int * int + int shift

. . . . . .

E * E | + int reduce E E * E

E | + int shift

E + | int shift

E + int| reduce E int

E + E | reduce E E + E

E |

48

Another Shift-Reduce Parse

|int * int + int shift

. . . . . .

E * E | + int shift

E * E + | int shift

E * E + int | reduce E int

E * E + E| reduce E E + E

E * E | reduce E E * E

E |

49

Example Notes

• In the second step E * E | + int we can either shift or reduce by E E * E

• Choice determines associativity of + and *

• As noted previously, grammar can be rewritten to enforce precedence

• Precedence declarations are an alternative

50

Precedence Declarations Revisited

• Precedence declarations cause shift-reduce parsers to resolve conflicts in certain ways

• Declaring “* has greater precedence than +” causes parser to reduce at E * E | + int

• More precisely, precedence declaration is used to resolve conflict between reducing a * and shifting a +

51

References

• Aho, A.V., R. Sethi, and J.D. Ullman, Compilers Principles, Techniques and Tools, Addison-Wesley, 1988. ISBN 0-201-10088-6. Chapters 2/3