Compilers. Bottom-up Parsing. (original slides by Sam

Similar documents
Bottom-Up Parsing. Lecture 11-12

In One Slide. Outline. LR Parsing. Table Construction

Bottom-Up Parsing. Lecture 11-12

LR Parsing LALR Parser Generators

COMP 181. Prelude. Prelude. Summary of parsing. A Hierarchy of Grammar Classes. More power? Syntax-directed translation. Analysis

LR Parsing LALR Parser Generators

LR Parsing. Table Construction

Conflicts in LR Parsing and More LR Parsing Types

Lecture 7: Deterministic Bottom-Up Parsing

Lecture 8: Deterministic Bottom-Up Parsing

Context-free grammars

Bottom-up parsing. Bottom-Up Parsing. Recall. Goal: For a grammar G, withstartsymbols, any string α such that S α is called a sentential form

Compiler Construction: Parsing

Lecture 14: Parser Conflicts, Using Ambiguity, Error Recovery. Last modified: Mon Feb 23 10:05: CS164: Lecture #14 1

A left-sentential form is a sentential form that occurs in the leftmost derivation of some sentence.

S Y N T A X A N A L Y S I S LR

Principles of Programming Languages

LR Parsing. Leftmost and Rightmost Derivations. Compiler Design CSE 504. Derivations for id + id: T id = id+id. 1 Shift-Reduce Parsing.

LR Parsing Techniques

Simple LR (SLR) LR(0) Drawbacks LR(1) SLR Parse. LR(1) Start State and Reduce. LR(1) Items 10/3/2012

3. Syntax Analysis. Andrea Polini. Formal Languages and Compilers Master in Computer Science University of Camerino

EDAN65: Compilers, Lecture 06 A LR parsing. Görel Hedin Revised:

Bottom-Up Parsing II (Different types of Shift-Reduce Conflicts) Lecture 10. Prof. Aiken (Modified by Professor Vijay Ganesh.

Formal Languages and Compilers Lecture VII Part 4: Syntactic A

SLR parsers. LR(0) items

CSE P 501 Compilers. LR Parsing Hal Perkins Spring UW CSE P 501 Spring 2018 D-1

MIT Parse Table Construction. Martin Rinard Laboratory for Computer Science Massachusetts Institute of Technology

Bottom up parsing. The sentential forms happen to be a right most derivation in the reverse order. S a A B e a A d e. a A d e a A B e S.

More Bottom-Up Parsing

UNIT III & IV. Bottom up parsing

Monday, September 13, Parsers

Fall Compiler Principles Lecture 4: Parsing part 3. Roman Manevich Ben-Gurion University of the Negev

Compiler Construction 2016/2017 Syntax Analysis

CSE 401 Compilers. LR Parsing Hal Perkins Autumn /10/ Hal Perkins & UW CSE D-1

PART 3 - SYNTAX ANALYSIS. F. Wotawa TU Graz) Compiler Construction Summer term / 309

Formal Languages and Compilers Lecture VII Part 3: Syntactic A

Fall Compiler Principles Lecture 5: Parsing part 4. Roman Manevich Ben-Gurion University

Wednesday, August 31, Parsers

Lexical and Syntax Analysis. Bottom-Up Parsing

Parsing Wrapup. Roadmap (Where are we?) Last lecture Shift-reduce parser LR(1) parsing. This lecture LR(1) parsing

Bottom-Up Parsing II. Lecture 8

Lecture Bottom-Up Parsing

Wednesday, September 9, 15. Parsers

Parsers. What is a parser. Languages. Agenda. Terminology. Languages. A parser has two jobs:

Parsers. Xiaokang Qiu Purdue University. August 31, 2018 ECE 468

Review: Shift-Reduce Parsing. Bottom-up parsing uses two actions: Bottom-Up Parsing II. Shift ABC xyz ABCx yz. Lecture 8. Reduce Cbxy ijk CbA ijk

UNIT-III BOTTOM-UP PARSING

CS 2210 Sample Midterm. 1. Determine if each of the following claims is true (T) or false (F).

Bottom Up Parsing. Shift and Reduce. Sentential Form. Handle. Parse Tree. Bottom Up Parsing 9/26/2012. Also known as Shift-Reduce parsing

Compiler Design 1. Bottom-UP Parsing. Goutam Biswas. Lect 6

shift-reduce parsing

How do LL(1) Parsers Build Syntax Trees?

Syntax Analyzer --- Parser

CS 4120 Introduction to Compilers

Table-driven using an explicit stack (no recursion!). Stack can be viewed as containing both terminals and non-terminals.

Syntax Analysis. Amitabha Sanyal. ( as) Department of Computer Science and Engineering, Indian Institute of Technology, Bombay

Let us construct the LR(1) items for the grammar given below to construct the LALR parsing table.

Parser Generation. Bottom-Up Parsing. Constructing LR Parser. LR Parsing. Construct parse tree bottom-up --- from leaves to the root

Concepts Introduced in Chapter 4

Parsing III. CS434 Lecture 8 Spring 2005 Department of Computer Science University of Alabama Joel Jones

LR(0) Parsing Summary. LR(0) Parsing Table. LR(0) Limitations. A Non-LR(0) Grammar. LR(0) Parsing Table CS412/CS413

Example CFG. Lectures 16 & 17 Bottom-Up Parsing. LL(1) Predictor Table Review. Stacks in LR Parsing 1. Sʹ " S. 2. S " AyB. 3. A " ab. 4.

MODULE 14 SLR PARSER LR(0) ITEMS

LR Parsing Techniques

Compilers. Yannis Smaragdakis, U. Athens (original slides by Sam

Parsing. Roadmap. > Context-free grammars > Derivations and precedence > Top-down parsing > Left-recursion > Look-ahead > Table-driven parsing

Bottom up parsing. General idea LR(0) SLR LR(1) LALR To best exploit JavaCUP, should understand the theoretical basis (LR parsing);

LR Parsing, Part 2. Constructing Parse Tables. An NFA Recognizing Viable Prefixes. Computing the Closure. GOTO Function and DFA States

Principle of Compilers Lecture IV Part 4: Syntactic Analysis. Alessandro Artale

Review of CFGs and Parsing II Bottom-up Parsers. Lecture 5. Review slides 1

3. Parsing. Oscar Nierstrasz

Parsing. Handle, viable prefix, items, closures, goto s LR(k): SLR(1), LR(1), LALR(1)

Lecture Notes on Bottom-Up LR Parsing

Downloaded from Page 1. LR Parsing

Lecture Notes on Bottom-Up LR Parsing

CS415 Compilers. Syntax Analysis. These slides are based on slides copyrighted by Keith Cooper, Ken Kennedy & Linda Torczon at Rice University

Top-Down Parsing and Intro to Bottom-Up Parsing. Lecture 7

CS 406/534 Compiler Construction Parsing Part I

LALR Parsing. What Yacc and most compilers employ.


LR Parsing - The Items

4. Lexical and Syntax Analysis

LALR stands for look ahead left right. It is a technique for deciding when reductions have to be made in shift/reduce parsing. Often, it can make the

Top-Down Parsing and Intro to Bottom-Up Parsing. Lecture 7

COP4020 Programming Languages. Syntax Prof. Robert van Engelen

4. Lexical and Syntax Analysis

Compilation 2013 Parser Generators, Conflict Management, and ML-Yacc

Introduction to Parsing. Comp 412

Syntax Analysis: Context-free Grammars, Pushdown Automata and Parsing Part - 4. Y.N. Srikant

LR Parsers. Aditi Raste, CCOEW

CS143 Handout 20 Summer 2011 July 15 th, 2011 CS143 Practice Midterm and Solution

Syntactic Analysis. Top-Down Parsing

Bottom-up Parser. Jungsik Choi

G53CMP: Lecture 4. Syntactic Analysis: Parser Generators. Henrik Nilsson. University of Nottingham, UK. G53CMP: Lecture 4 p.1/32

VIVA QUESTIONS WITH ANSWERS

Computer Science 160 Translation of Programming Languages

Parsing Algorithms. Parsing: continued. Top Down Parsing. Predictive Parser. David Notkin Autumn 2008

Configuration Sets for CSX- Lite. Parser Action Table

Compilation 2012 Context-Free Languages Parsers and Scanners. Jan Midtgaard Michael I. Schwartzbach Aarhus University

Lecture Notes on Shift-Reduce Parsing

Transcription:

Compilers Bottom-up Parsing Yannis Smaragdakis U Athens Yannis Smaragdakis, U. Athens (original slides by Sam Guyer@Tufts)

Bottom-Up Parsing More general than top-down parsing And just as efficient Builds on ideas in top-down parsing Preferred method in many instances Specific algorithm: LR parsing L means that tokens are read left to right R means that it constructs a rightmost derivation Donald Knuth (1965) "On the Translation of Languages from Left to Right" 2

The Idea An LR parser reduces a string to the start symbol by inverting productions: str = input string of terminals repeat Identify β in str such hthat ta β is a production (i.e., str = αβγ) Replace β by A in str (i.e., str becomes α A γ) until str = G 3

A simple example LR parsers: Can handle left-recursion Don t need left factoring Consider the following grammar: E E + ( E ) int Is this grammar LL(1) (as shown)? 4

A Bottom-up Parse in Detail (1) int + (int) + (int) int + ( int ) + ( int ) 5

A Bottom-up Parse in Detail (2) int + (int) + (int) E + (int) + (int) E int + ( int ) + ( int ) 6

A Bottom-up Parse in Detail (3) int + (int) + (int) E + (int) + (int) E + (E) + (int) E int + E ( int ) + ( int ) 7

A Bottom-up Parse in Detail (4) int + (int) + (int) E + (int) + (int) E + (E) + (int) E + (int) E E int + E ( int ) + ( int ) 8

A Bottom-up Parse in Detail (5) int + (int) + (int) E + (int) + (int) E + (E) + (int) E + (int) E + (E) E E E E int + ( int ) + ( int ) 9

A Bottom-up Parse in Detail (6) int + (int) + (int) E + (int) + (int) E + (E) + (int) E + (int) E + (E) E E E E E E int + ( int ) + ( int ) 10

Another example Start with input stream Leaves of parse tree Build up towards goal symbol Called reducing Construct the reverse derivation Rule Sentential form - abbcde 3 aabcde 2 aade 4 aabe 1 G # Production rule 1 G a A B e 2 A A b c 3 b 4 B d G A A B a b b c d e 11

Easy? Choosing a reduction: Not good enough to simply find production right-hand sides and reduce Example: Rule Sentential form - abbcde 3 aabcde 2 aaacde? now what? # Production rule 1 G a A B e 2 A A b c 3 b 4 B d aaacde is not part of any A A sentential form a b b c d e 12

Key problems How do we make this work? How do we know we won t get stuck? How do we find the next reduction? Also: how do we find it efficiently? i? Key: We are constructing the right-most derivation Grammar is unambiguous Unique right-most derivation for every string Unique production applied at each forward step Unique correct reduction at each backward step 13

Right-most derivation Rule - 1 3 6 1 2 5 3 Sentential form Rule expr - expr op expr 1 expr op <id,y> 3 expr * <id,y> 6 expr op expr * <id,y> 1 expr op <num,2> * <id,y> 2 expr - <num,2> * <id,y> 5 <id,x> - <num,2> * <id,y> 3 Sentential form expr expr op expr expr op <id,y> expr * <id,y> expr op expr * <id,y> expr op <num,2> * <id,y> expr - <num,2> * <id,y> <id,x> - <num,2> * <id,y> Forward derivation: Always expand right-most non-terminal Reverse derivation (parse): Correct reduction always occurs immediately to the left of some point in a left-to-right reading of the tokens 14

LR parsing State of the parser: α γ α is a stack of terminals and non-terminals γ is string of unexamined terminals # Production rule 1 E E + ( E ) 2 int Two operations: Shift read next terminal, push on stack E + ( int ) E + ( int ) Reduce pop RHS symbols off stack, push LHS E + ( E + ( E ) ) E + ( E ) 15

Example 1. int + ( int ) + ( int ) Nothing on stack, get next token Stack 16

Example 1. int + ( int ) + ( int ) Nothing on stack, get next token 2. int + ( int ) + ( int ) Shift: push int Top of stack matches E int Stack int 17

Example 1. int + ( int ) + ( int ) Nothing on stack, get next token 2. int + ( int ) + ( int ) Shift: push int 3. int + ( int ) + ( int ) Reduce: pop int Top of stack matches E int Stack int 18

Example 1. int + ( int ) + ( int ) Nothing on stack, get next token 2. int + ( int ) + ( int ) Shift: push int 3. int + ( int ) + ( int ) Reduce: pop int, push E Top of stack matches E int Stack E int 19

Example 1. int + ( int ) + ( int ) Nothing on stack, get next token 2. int + ( int ) + ( int ) Shift: push int 3. int + ( int ) + ( int ) Reduce: pop int, push E 4. int + ( int ) + ( int ) Shift: push + 5. int + ( int ) + ( int ) Shift: push ( 6. int + (int ) + ( int ) Shift: push int Top of stack matches E int Stack E + ( int 20

Example 1. int + ( int ) + ( int ) Nothing on stack, get next token 2. int + ( int ) + ( int ) Shift: push int 3. int + ( int ) + ( int ) Reduce: pop int, push E 4. int + ( int ) + ( int ) Shift: push + 5. int + ( int ) + ( int ) Shift: push ( 6. int + ( int ) + ( int ) Shift: push int 7. int + ( int ) + ( int ) Reduce: pop int, push E Stack E + ( E 21

Example 1. int + ( int ) + ( int ) Nothing on stack, get next token 2. int + ( int ) + ( int ) Shift: push int 3. int + ( int ) + ( int ) Reduce: pop int, push E 4. int + ( int ) + ( int ) Shift: push + 5. int + ( int ) + ( int ) Shift: push ( 6. int + ( int ) + ( int ) Shift: push int 7. int + ( int ) + ( int ) Reduce: pop int, push E 8. int + ( int ) + ( int ) Shift: push ) Top of stack matches E --> E + ( E ) Stack E + ( E ) 22

Example 1. int + ( int ) + ( int ) Nothing on stack, get next token 2. int + ( int ) + ( int ) Shift: push int 3. int + ( int ) + ( int ) Reduce: pop int, push E 4. int + ( int ) + ( int ) Shift: push + 5. int + ( int ) + ( int ) Shift: push ( 6. int + ( int ) + ( int ) Shift: push int 7. int + ( int ) + ( int ) Reduce: pop int, push E 8. int + ( int ) + ( int ) Shift: push ) 9. int + ( int ) + ( int ) Reduce: pop p x 5, push E Stack E 23

Example. 9. int + ( int ) + ( int ) Reduce: pop x 5, push E 10. int + ( int ) + ( int ) Shift: push + 11. int + ( int ) + ( int ) Shift: push ( 12. int + ( int ) + ( int ) Shift: push int Stack E + ( int 24

Example. 9. int + ( int ) + ( int ) Reduce: pop x 5, push E 10. int + ( int ) + ( int ) Shift: push + 11. int + ( int ) + ( int ) Shift: push ( 12. int + ( int ) + ( int ) Shift: push int 13. int + ( int ) + ( int ) Reduce: pop int, push E 14. int + ( int ) + ( int ) Shift: push ) Stack E + ( E ) 25

Example. 9. int + ( int ) + ( int ) Reduce: pop x 5, push E 10. int + ( int ) + ( int ) Shift: push + 11. int + ( int ) + ( int ) Shift: push ( 12. int + ( int ) + ( int ) Shift: push int 13. int + ( int ) + ( int ) Reduce: pop int, push E 14. int + ( int ) + ( int ) Shift: push ) 15. int + ( int ) + ( int ) Reduce: pop x 5, push E DONE! Stack E 26

Key problems (1) Will this work? How do we know that shifting and reducing using a stack is sufficient to compute the reverse derivation? (2) How do we know when to shift and reduce? Can we efficiently match top symbols on the stack against productions? Right-hand sides of productions may have parts in common Will shifting a token move us closer to a reduction? Are we making progress? How do we know when an error occurs? 27

Why does it work? Right-most derivation G γ 1 γ 2 γ 3 γ 4 γ 5 input Consider last step: G γ 5 a b c B x y z input a b c q r s x y z To reverse this step: Production: B q r s Read input until q, r, s on top of stack Reduce q, r, s to B 28

Right-most derivation Could there be an alternative reduction? γ 5 G a b c B x y z a b c q r s x y z and B q r s G γ 5 a D r s x y z a b c q r s x y z No D b c q Two right-most derivations for the same string I.e., the grammar would be ambiguous 29

Reductions a b c B x y z Where is the next reduction? Includes B: γ 4 γ 5 a b F y z Later in the input stream: γ 5 a b c B x y z γ 4 abcbh z γ 5 abcbxyz Could it be earlier? γ 4 a J B x y z γ 5 a b c B x y z No this is not the right-most derivation! 30

Implications Cases: γ 4 a b F y z a b c B H z γ 5 a b c B x y z a b c B x y z Parsing state: t Input: b Stack: a b c q r s x y z a b c Key: next reduction must consume top of stack Possibly after shifting some terminal symbols How does this help? Can consume terminal symbols in order Never need to search inside id the stack only stack B We can perform LR parsing using operations 31

LR parsing repeat if top symbols on stack match β for some A β Reduce: found an A Pop those symbols off Push A on stack else Get next token from scanner if token is useful Shift: still working on something Push on stack else error until stack contains goal and no more input 32

Key problems (2) How do we know when to shift or reduce? Shifts Default behavior: shift when there s no reduction Still need to handle errors Reductions Good news: At any given step, reduction is unique Matching production occurs at top of stack Problem: How to efficiently find the right production 33

Identifying reductions Where is the next reduction? Includes B: γ 4 a b F y z γ 5 a b c B x y z γ 5 a b c B x y z Later in the input stream: γ 4 a b c B H z γ 5 a b c B x y z What is on the stack? Sequence of terminals and non-terminals All applicable reductions, except last, already applied Called a viable prefix 34

Identifying reductions Do viable prefixes have any special properties? Key: viable prefixes are a regular language Idea: a DFA that recognizes viable prefixes Input: stack contents t (a mix of terminals, non-terminals) Each state represents either A right sentential form labeled with the reduction to apply A viable prefix labeled with tokens to expect next 35

Shift/reduce DFA Using the DFA At each parsing step run DFA on stack contents Examine the resulting state X and the token t immediately following in the input stream If X has an outgoing edge labeled t, then shift if X is labeled A β on t,, then reduce Example: # Production rule 1 E E + ( E ) 2 int First, we ll look at how to use such a DFA 36

E int 0 1 + ( 2 3 4 accept on $ 7 ) E E + (E) on $, + 8 + + 6 E ( E 5 10 11 ) E int on $, + int 9 E int on ), + int E E+(E) on ), + Example I int + (int) + (int)$ 37

E int 0 1 + ( 2 3 4 accept on $ 7 ) E E + (E) on $, + 8 + + 6 E ( E 5 10 11 ) E int on $, + int 9 E int on ), + int E E+(E) on ), + Example I int + (int) + (int)$ shift int I + (int) + (int)$ 38

E int 0 1 + ( 2 3 4 accept on $ 7 ) E E + (E) on $, + 8 + + 6 E ( E 5 10 11 ) E int on $, + int 9 E int on ), + int E E+(E) on ), + Example I int + (int) + (int)$ shift int I + (int) + (int)$ E --> int E I + (int) + (int)$ shift(x3) E + (int I ) + (int)$ E --> int E + (E I ) + (int)$ shift E + (E) I + (int)$ 39

E int 0 1 + ( 2 3 4 accept on $ 7 ) E E + (E) on $, + 8 + + 6 E ( E 5 10 11 ) E int on $, + int 9 E int on ), + int E E+(E) on ), + Example I int + (int) + (int)$ shift int I + (int) + (int)$ E --> int E I + (int) + (int)$ shift(x3) E + (int I ) + (int)$ E --> int E + (E I ) + (int)$ shift E + (E) I + (int)$e --> E+(E) E I +(int)$shift (x3) E + (int I )$ E --> int E + (E I )$ shift E + (E) I $ E --> E+(E) E I $ accept 40

Improvements Each DFA state represents stack contents At each step, we rerun the DFA to compute the new state Can we avoid this? Two actions: Idea: Shift: Push a new token Reduce: Pop some symbols off, push a new symbol For each symbol on the stack, remember the DFA state that represents the contents up to that point Push a new token = go forward in DFA Pop a sequence of symbols = unwind DFA to previous state 41

E int 0 1 + ( 2 3 4 accept on $ 7 ) E E + (E) on $, + 6 E 5 + 8 ( + E 10 ) 11 E int on $, + int 9 E int on ), + int E E+(E) on ), + Example I int + (int) + (int)$ shift int I + (int) + (int)$ E --> int E I + (int) + (int)$ shift(x3) At state 2 go forward in DFA 2-->3-->4-->5 E+(int I ) + (int)$ E --> int Back up to state 4 Go forward with E 4-->6 42

Algorithm components Stack String of the form : sym 1, state 1... sym n, state n sym i : grammar symbol (left part of string) state t i : DFA state t Intuitively: represents what we ve seen so far state k is the final state of the DFA on sym 1 sym k And, captures what we re looking for next Represent as two tables: action whether to shift, reduce, accept, error goto next state 43

E int 0 1 + ( 2 3 4 accept on $ 7 ) E E + (E) on $, + 6 E 5 + 8 ( + E 10 ) 11 E int on $, + int 9 E int on ), + int E E+(E) on ), + Example push < _,0> I int + (int) + (int)$ shift push <int,1> int I + (int) + (int)$ E --> int pop <int, 1> push <E, goto(0, E)=2> E I + (int) + (int)$ shift(x3) push <+,3>, <(,4>, <int,5> E + (int I ) + (int)$ E --> int pop <int,5> push <E, goto(4, E) = 6> etc. 44

Tables Action Given state and the next token, action[s i,a] = Shift s, where s is the next state on edge a Reduce by a grammar production A β Accept Error Goto Given a state and a grammar symbol, goto[s i,x] = After reducing an X production Unwind to state t ending with X (to keep going) 45

Algorithm Top of stack is handle A β push s0 on stack token = scanner.next_token() next token() repeat s = state at top of stack if action[s, token] = reduce A β then pop β pairs (X i, s m ) off the stack s = top of stack push A on stack push goto[s, A] on stack else if action[s, token] = shift s then push token on stack push s on stack token = scanner.next_token() next token() else if action(s, token) = accept then return true else error() Work Shift each token Pop each token Errors Input exhausted Error entry in table 46

Representing the DFA Combined table: ( 3 4 E 6 ) 7 int 5 E E + (E) on $, + E int on ), + action(state, token) goto int + ( ) $ E 3 s4 4 s5 g6 5 r E-->int r E-->int 6 s8 s7 7 r E-->E+(E) r E-->E+(E) 47

How is the DFA Constructed? What s on the stack? Viable prefix a piece of a sentential form E + ( E + ( int E + ( E + ( Idea: we re part-way through some production Problem: Productions can share pieces DFA state represents the set of candidate productions Represents all the productions we could be working on Notation: LR(1) item shows where we are and what we need dto see 48

LR Items An LR(1) item is a pair: [ A α β, a ] A αβ is a production a is a terminal (the lookahead terminal) LR(1) means 1 lookahead terminal [A α β, a] describes a context of the parser WearetryingtofindanA to an A followed by an a, and We have seen an α We need to see a string derived from β a 49

LR Items In context containing [ E E + ( E ), + ] If ( is next then we can a shift to context containing [ E E + ( E ), + ] In context t containing i [ E E + ( E ), + ] We can reduce with E E + ( E ) But only if a + follows 50

LR Items Consider the item E E + ( E ), + We expect a string derived from E ) + There are two productions for E E int and E E + ( E) We extend the context with two more items: Each DFA state: E int, ) E E + ( E ), ) The set of items that represent all the possible productions we could be working on called the closure of the set of items 51

Closure operation Observation: At A α Bβ we expect to see Bβ next Means if B γ is a production, then we could see a γ Algorithm: closure(items) = repeat for each [A α Bβ, a] in Items for each production B γ add [B γ,?] to Items until Items is unchanged What is the lookahead? 52

Closure operation Algorithm: closure(items) = repeat for each [A α Bβ, a] in Items for each production B γ for each b FIRST(βa) add [B γ, b] to Items until Items is unchanged 53

Building the DFA part 1 Starting context = closure({s E, $}) S E, $ E E+(E), $ E int, i t $ E E+(E), + E int, + Abbreviated: S E, $ E E+(E), $/+ E int, $/+ 54

Building the DFA part 2 DFA states Each DFA state is a closed set of LR(1) items Start state: closure({s E, $}) Reductions Label each item [ A αβ, x ] with Reduce with A αβon lookahead x What about transitions? 55

DFA transitions Idea: If the parser was in state [A α Xβ] and then recognized an instance of X, then the new state is [A αx β] Note: X could be a terminal or non-terminal Algorithm: Given a set of items I (DFA stats) t and a symbol X transition(i, X) = J = {} for each [A α Xβ, b] I add [A αx β, b] to J return closure(j) 56

DFA construction Data structure: T set of states t (each state t is a set of items) X E edges of the form I J where I, J T and X is a terminal or non-terminal Algorithm: T = {closure({s Y, $}, E = {} repeat for each state I in T for each item [A α Xβ, b] I let J = transition(i, X) T = T + J E = E + { I J } until E and T no longer change 57

2 Example DFA S E,,$ E E+(E), $/+ E int, $/+ accept on $ 0 int E + S E, $ E E +(E), $/+ E 1 E int, $/+ E E+ (E), $/+ E int on $, + E E+( E), $/+ 4 E E+(E), )/+ E int, )/+ ( 3 6 E E+(E ), $/+ E E +(E), )/+ and so on int 5 E int,, )/+ E int on ), + 58

To form into tables Two tables action(i, token) goto(i, symbol) Layout: One row for each state each I in T One column for each symbol Entries: For each edge I J X If X is a terminal, add shift J at position (I, X) in action if X is a non-terminal, add goto J at position (I, X) goto For each state [ A αβ, x ] in I Add reduce n at position (I, x) in action (where n is rhs ) 59

Issues with LR parsers What happens if a state contains: [ X α aβ, b ] and [ Y γ, a ] Then on input a we could either Shift into state [ X αa β, b ], or Reduce with Y γ This is called a shift-reduce conflict Typically due to ambiguity Like what? 60

Shift/Reduce conflicts Classic example: the dangling else S if E then S if E then S else S OTHER Will have DFA state t containing i [S if E then S, else] [S if E then S else S, x] Practical solutions: Painful: modify grammar to reflect the precedence of else Many LR parsers default to shift Often have a precedence declaration 61

Another example Consider the ambiguous grammar E E + E E*E i E E int Part of the DFA: [E E * E, +] [E E + E, +] E [E E * E, +] [E E + E, +] We have a shift/reduce on input + What do we want to happen? Consider: x * y + z We need to reduce (* binds more tightly than +) Default action is shift 62

Precedence Declare relative precedence Explicitly resolve conflict Tell parser: we prefer the action involving * over + [E E * E, +] [E E + E, +] E [E E * E, +] [E E + E, +] In practice: Parser generators support a precedence declaration for operators What is the alternative? 63

More Still a problem? [E E + E, +] E [E E + E, +] [E E+E E, +] [E E +E E, +] Shift/reduce conflict on + Do we care? Maybe: we want left associativity parse: a+b+c as ((a+b)+c) Which rule should we choose? Also handled by a declaration + is left-associative 64

Other problems If a DFA state contains both [ X α, a ] and [ Y β, a ] What s the problem here? Two reductions to choose from when next token is a This is called a reduce/reduce conflict Usually a serious ambiguity in the grammar Must be fixed in order to generate parser Think about relationship between α and β 65

Reduce/Reduce conflicts Example: a sequence of identifiers S ε id id S There are two parse trees for the string id S id S id S id How does this confuse the parser? 66

Reduce/Reduce conflicts Consider the DFA states: [S id, $] [G S, $] [S id S, $] id [S, $] [S, $] [S id, $] [S id, $] [S id S, $] [S id S, $] Reduce/reduce conflict on input $ G S id G S id S id Fix: rewrite the grammar: S ε id S 67

Practical issues We use an LR parser generator Question: how many DFA states are there? Does it matter? What does that affect? Parsing time is the same Table size: occupies memory Even simple languages have 1000s of states Most LR parser generators don t construct the DFA as described 68

LR(1) Parsing tables But many states are similar, e.g. 1 E int,, $/+ E int on $, + and 5 E int, )/+ E int on ), + How can we exploit this? Same reduction, different lookahead tokens Idea: merge the states 1 E int,$ $/+/) E int on $, +, ) 69

The core of a set of LR Items When can states be merged? Def: the core of a set of LR items is: Just the production parts of the items Without the lookahead terminals Example: the core of is { [X α β, b], [Y γ δ, d] } { X α β, Y γ δ } 70

Merging states Consider for example the LR(1) states { [X α, a], [Y β, c] } { [X α, b], [Y β, d] } They have the same core and can be merged Resulting state is: { [X α, a/b], [Y β, c/d] } These are called LALR(1) states Stands for LookAhead LR Typically 10X fewer LALR(1) states than LR(1) Does this state do the same thing? 71

The LALR(1) DFA Algorithm: repeat Choose two states with same core Merge the states by combining the items Point edges from predecessors to new state New state points to all the previous successors until all states have distinct core A D B C A C BE E F D F 72

Conversion LR(1) to LALR(1). E int 0 1 + ( 2 3 4 accept on $ 7 ) E E + (E) on $, + E 6 5 + 8 ( + E 10 ) 11 E int on $, + int 9 E int on ), + int E E + (E) on ), + E accept on $ int 0 1,5 int ( 2 + 3,8 4,9 7,11 ) E E + (E) on $, +, ) + 6,10 E int on $, +, ) E 73

LALR states Consider the LR(1) states: { [X α, a], [Y β, b] } { [X α, b], [Y β, a] } And the merged LALR(1) state { [X α,, a/b], [Y β,, a/b] } What s wrong with this? Introduces a new reduce-reduce conflict In practice such cases are rare 74

LALR vs. LR Parsing LALR is an efficiency hack on LR languages Any reasonable programming language has a LALR(1) grammar Languages that are not LALR(1) are weird, unnatural languages LALR(1) has become a standard for programming languages and for parser generators 75

Another variation Lookahead symbol How is it computed in LR, LALR parser? In closure operation for each [A α Bβ, a] in Items for each production B γ for each b FIRST(βa) add [B γ, b] to Items Based on context of use Simplify this process: What symbol (set of symbols) could I use for [B γ,?] FOLLOW(B) Called SLR (Simple LR) parser 76

More power? So far: LALR and SLR: reduce size of tables Also reduce space of languages What tifi want tto expand the space of languages? What could I do at a reduce/reduce conflict? Try both reductions! GLR parsing At a choice: split the stack, explore both possibilities If one doesn t work out, kill it Run-time proportional to amount of ambiguity Must design the stack data structure very carefully 77

General algorithms Parsers for full class of context-free grammars Mostly used in linguistics constructive proof of decidability CYK (1965) Bottom-up dynamic programming algorithm O(n 3 ) Earley s algorithm (1970) Top-down dynamic programming algorithm Developed the notation for partial production Worst-case O(n 3 ) running time But, O(n 2 ) even for unambiguous grammars GLR Worse-case O(n 3 ), but O(n) for unambiguous grammars 78

LR parsing Input: Stack: s m X m a 1 a 2 a i a n $ LR Parsing Engine Scanner s m-1 X m-1 X Compiler construction s 0 Parser Action Goto Generator Grammar LR tables 79

Real world parsers Real generated code lex, flex, yacc, bison Interaction between lexer and parser C typedef problem Merging g two languages Debugging Diagnosing reduce/reduce conflicts How to step through an LR parser 80

Parser generators Example: JavaCUP LALR(1) parser generator Input: grammar specification Output: Java classes Generic engine Action/goto tables Separate scanner specification Similar tools: SableCC yacc and bison generate C/C++ parsers JavaCC: similar, but generates LL(1) parser 81

JavaCUP example Simple expression grammar Operations over numbers only // Import generic engine code import java_cup.runtime.*; /* Preliminaries to set up and use the scanner. */ init with {: scanner.init(); :}; scan with {: return scanner.next_token(); :}; Note: interface to scanner One issue: how to agree on names of the tokens 82

Example Define terminals and non-terminals Indicate operator precedence /* Terminals (tokens returned by the scanner). */ terminal SEMI, PLUS, MINUS, TIMES, DIVIDE, MOD; terminal UMINUS, LPAREN, RPAREN; terminal Integer NUMBER; /* Non terminals */ non terminal expr_list, expr_part; non terminal Integer expr, term, factor; /* Precedences */ precedence left PLUS, MINUS; precedence left TIMES, DIVIDE, MOD; 83

Example Grammar rules expr_list ::= expr_list expr_part expr_part ; expr_part ::= expr SEMI ; expr ::= expr PLUS expr expr MINUS expr expr TIMES expr expr DIVIDE expr expr MOD expr LPAREN expr RPAREN NUMBER ; 84

Summary of parsing Parsing A solid foundation: context-free grammars A simple parser: LL(1) A more powerful parser: LR(1) An efficiency hack: LALR(1) LALR(1) parser generators 85

A Hierarchy of Grammar Classes From Andrew Appel, Modern Compiler Implementation in Java 86