1 / 27

Computing Follow(A) : All Non-Terminals

Computing Follow(A) : All Non-Terminals. 1. Place $ in Follow(S), where S is the start symbol and $ signals end of input 2. If there is a production A B, then everything in First() is in Follow(B) except for .

Download Presentation

Computing Follow(A) : All Non-Terminals

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Computing Follow(A) : All Non-Terminals 1. Place $ in Follow(S), where S is the start symbol and $ signals end of input 2. If there is a production A B, then everything in First() is in Follow(B) except for . 3. If A B is a production, or A B and    (First() contains  ), then everything in Follow(A) is in Follow(B) (Whatever followed A must follow B, since nothing follows B from the production rule) * We’ll calculate Follow for two grammars.

  2. The Algorithm for Follow – pseudocode 1. Initialize Follow(X) for all non-terminals X to empty set. Place $ in Follow(S), where S is the start NT. 2. Repeat the following step until no modifications are made to any Follow-set For any production X  X1 X2 … Xm For j=1 to m, if Xjis a non-terminal then: Follow(Xj)=Follow(Xj)(First(Xj+1,…,Xm)-{}); If First(Xj+1,…,Xm) contains  or Xj+1,…,Xm=  then Follow(Xj)=Follow(Xj) Follow(X);

  3. Computing Follow : 1st Example Recall: S  i E t SS’ | a S’  eS |  E  b First(S) = { i, a } First(S’) = { e, } First(E) = { b }

  4. Computing Follow : 1st Example Recall: S  i E t SS’ | a S’  eS |  E  b First(S) = { i, a } First(S’) = { e, } First(E) = { b } Follow(S) – Contains $, since S is start symbol Since S  i E t SS’ , put in First(S’) – not  Since S’  , Put in Follow(S) Since S’  eS, put in Follow(S’) So…. Follow(S) = { e, $ } Follow(S’) = Follow(S) HOW? Follow(E) = { t } *

  5. Example 2 E  TE’ E’  + TE’ |  T  FT’ T’  * FT’ |  F  ( E ) | id Compute Follow for:

  6. Example 2 E  TE’ E’  + TE’ |  T  FT’ T’  * FT’ |  F  ( E ) | id Compute Follow for: Follow E $ ) E’ $ ) T + $ ) T’ + $ ) F + * $ ) First E ( id E’ + T ( id T’ * F ( id

  7. Constructing Parsing Table • Algorithm: • Table has one row per non-terminal / one column per terminal (incl. $ ) • Repeat Steps 2 & 3 for each rule A • Terminal a in First()? Add A to M[A, a ] • 3.1  in First()? Add A  to M[A, b ] for all terminals b in Follow(A). • 3.2  in First() and $ in Follow(A)? Add A  to M[A, $ ] • 4. All undefined entries are errors.

  8. Constructing Parsing Table – Example 1 S  i E t SS’ | a S’  eS |  E  b First(S) = { i, a } First(S’) = { e, } First(E) = { b } Follow(S) = { e,$ } Follow(S’) = { e,$ } Follow(E) = { t }

  9. Constructing Parsing Table – Example 1 S  i E t SS’ | a S’  eS |  E  b First(S) = { i, a } First(S’) = { e, } First(E) = { b } Follow(S) = { e,$ } Follow(S’) = { e,$ } Follow(E) = { t } S  i E t SS’ S  a E  b First(i E t SS’)={i}First(a) = {a} First(b) = {b} S’  eS S   First(eS) = {e} First() = {} Follow(S’) = { e, $ } Non-terminal INPUT SYMBOL a b e i t $ S S a S iEtSS’ S’ S’  S’ eS S  E E b

  10. Constructing Parsing Table – Example 2 E  TE’ E’  + TE’ |  T  FT’ T’  * FT’ |  F  ( E ) | id First(E,F,T) = { (, id } First(E’) = { +, } First(T’) = { *,  } Follow(E,E’) = { ), $} Follow(F) = { *,+,), $ } Follow(T,T’) = { +,) , $}

  11. Constructing Parsing Table – Example 2 E  TE’ E’  + TE’ |  T  FT’ T’  * FT’ |  F  ( E ) | id First(E,F,T) = { (, id } First(E’) = { +, } First(T’) = { *,  } Follow(E,E’) = { ), $} Follow(F) = { *,+,), $ } Follow(T,T’) = { +,) , $} Expression Example: E  TE’ : First(TE’) = First(T) = { (, id } M[E, ( ] : E  TE’ M[E, id ] : E  TE’ (by rule 2) E’  +TE’ : First(+TE’) = + : M[E’, +] : E’  +TE’ (by rule 3) E’   :  in First( ) T’   :  in First( ) by rule 2 M[E’, )] : E’  (3.1) M[T’, +] : T’  (3.1) M[E’, $] : E’  (3.2) M[T’, )] : T’  (3.1) (Due to Follow(E’) M[T’, $] : T’  (3.2)

  12. LL(1) Grammars • L : Scan input from Left to Right • L : Construct a Leftmost Derivation • 1 : Use “1” input symbol as lookahead in conjunction with stack to decide on the parsing action • LL(1) grammars == they have no multiply-defined entries in the parsing table. • Properties of LL(1) grammars: • Grammar can’t be ambiguous or left recursive • Grammar is LL(1) when A  • 1.  &  do not derive strings starting with the same terminal a • 2. Either  or  can derive , but not both. Note: It may not be possible for a grammar to be manipulated into an LL(1) grammar

  13. Error Recovery Input Predictive Parsing Program Stack a + b $ Output Parsing Table M[A,a] X Y Z $ When Do Errors Occur? Recall Predictive Parser Function: • If X is a terminal and it doesn’t match input. • If M[ X, Input ] is empty – No allowable actions • Consider two recovery techniques: • A. Panic Mode • B. Phrase-level Recovery

  14. Panic-Mode Recovery • Assume a non-terminal on the top of the stack. • Idea: skip symbols on the input until a token in a selected set of synchronizing tokens is found. • The choice for a synchronizing set is important. • some ideas: • define the synchronizing set of A to be FOLLOW(A). then skip input until a token in FOLLOW(A) appears and then pop A from the stack. Resume parsing... • add symbols of FIRST(A) into synchronizing set. In this case we skip input and once we find a token in FIRST(A) we resume parsing from A. • Productions that lead to  if available might be used. • If a terminal appears on top of the stack and does not match to the input == pop it and and continue parsing (issuing an error message saying that the terminal was inserted).

  15. Panic Mode Recovery, II • General Approach: Modify the empty cells of the Parsing Table. • if M[A,a] = {empty} and a belongs to Follow(A) then we set M[A,a] = “synch” • Error-recovery Strategy : • If A=top-of-the-stack and a=current-input, • If A is NT and M[A,a] = {empty} then skip a from the input. • If A is NT and M[A,a] = {synch} then pop A. • If A is a terminal and A!=a then pop token (essentially inserting it).

  16. Revised Parsing Table / Example INPUT SYMBOL Non-terminal id + * ( ) $ E ETE’ ETE’ E’ E’+TE’ E’ E’ T TFT’ TFT’ T’ T’ T’*FT’ T’ T’ F Fid F(E) Skip input symbol From Follow sets. Pop top of stack NT “synch” action

  17. Revised Parsing Table / Example(2) STACK INPUT Remark $E $E $E’T $E’T’F $E’T’id $E’T’ $E’T’F* $E’T’F $E’T’ $E’ $E’T+ $E’T $E’T’F $E’T’id $E’T’ $E’ $ + id * + id$ id * + id$ id * + id$ id * + id$ id * + id$ * + id$ * + id$ + id$ + id$ + id$ + id$ id$ id$ id$ $ $ $ error, skip + Possible Error Msg: “Misplaced + I am skipping it” error, M[F,+] = synch F has been popped Possible Error Msg: “Missing Term”

  18. Writing Error Messages • Keep input counter(s) • Recall: every non-terminal symbolizes an abstract language construct. • Examples of Error-messages for our usual grammar • E = means expression. • top-of-stack is E, input is +“Error at location i, expressions cannot start with a ‘+’” or “error at location i, invalid expression” • Similarly for E, * • E’= expression ending. • Top-of-stack is E’, input is * or id“Error: expression starting at j is badly formed at location i” • Requires: every time you pop an ‘E’ remember the location

  19. Writing Error-Messages, II • Messages for Synch Errors. • Top-of-stack is F input is + • “error at location i, expected summation/multiplication term missing” • Top-of-stack is E input is ) • “error at location i, expected expression missing”

  20. Writing Error Messages, III • When the top-of-the stack is a terminal that does not match… • E.g. top-of-stack is id and the input is + • “error at location i: identifier expected” • Top-of-stack is ) and the input is terminal other than ) • Every time you match an ‘(‘push the location of ‘(‘ to a “left parenthesis” stack. • this can also be done with the symbol stack. • When the mismatch is discovered look at the left parenthesis stack to recover the location of the parenthesis. • “error at location i: left parenthesis at location m has no closing right parenthesis” • E.g. consider ( id * + (id id) $

  21. Incorporating Error-Messages to the Table • Empty parsing table entries can now fill with the appropriate error-reporting techniques.

  22. Phrase-Level Recovery • Fill in blanks entries of parsing table with error handling routines that do not only report errors but may also: • change/ insert / delete / symbols into the stack and / or input stream • + issue error message • Problems: • Modifying stack has to be done with care, so as to not create possibility of derivations that aren’t in language • infinite loops must be avoided • Essentially extends panic mode to have more complete error handling

  23. How Would You Implement TD Parser INPUT SYMBOL Non-terminal id + * ( ) $ E ETE’ ETE’ synch synch E’ E’+TE’ E’ E’ T TFT’ synch TFT’ synch synch T’ T’ T’*FT’ T’ T’ F Fid synch synch F(E) synch synch • Stack – Easy to handle. Write ADT to manipulate its contents • Input Stream – Responsibility of lexical analyzer • Key Issue – How is parsing table implemented ? One approach: Assign unique IDS All rules have unique IDs Also for blanks which handle errors Ditto for synch actions

  24. Revised Parsing Table: INPUT SYMBOL Non-terminal id + * ( ) $ E 1 18 19 1 9 10 E’ 20 2 21 22 3 3 T 4 11 23 4 12 13 T’ 24 6 5 25 6 6 F 8 14 15 7 16 17 1 ETE’ 2 E’+TE’ 3 E’ 4 TFT’ 5 T’*FT’ 6 T’ 7 F(E) 8 Fid 9 – 17 : Sync Actions 18 – 25 : Error Handlers

  25. Revised Parsing Table: (2) • Each # ( or set of #s) corresponds to a procedure that: • Uses Stack ADT • Gets Tokens • Prints Error Messages • Prints Diagnostic Messages • Handles Errors

  26. How is Parser Constructed ? One large CASE statement: state = M[ top(s), current_token ] switch (state) { case 1: proc_E_TE’( ) ; break ; … case 8: proc_F_id( ) ; break ; case 9: proc_sync_9( ) ; break ; … case 17: proc_sync_17( ) ; break ; case 18: … case 25: } Combine  put in another switch Some sync actions may be same Some error handlers may be similar Procs to handle errors

  27. Final Comments – Top-Down Parsing • So far, • We’ve examined grammars and language theory and its relationship to parsing • Key concepts: Rewriting grammar into an acceptable form • Examined Top-Down parsing: • Brute Force : Transition diagrams & recursion • Elegant : Table driven • We’ve identified its shortcomings: • Not all grammars can be made LL(1) ! • Bottom-Up Parsing - Future

More Related