Compiler design Error recovery in top-down predictive parsing

Slides:



Advertisements
Similar presentations
Error Handling A compiler should: detect errors locate errors recover from errors Errors may occur in any of the three main analysis phases of compiling:
Advertisements

A question from last class: construct the predictive parsing table for this grammar: S->i E t S e S | i E t S | a E -> B.
Joey Paquet, 2000, 2002, 2008, Lecture 7 Bottom-Up Parsing II.
Lecture # 7 Chapter 4: Syntax Analysis. What is the job of Syntax Analysis? Syntax Analysis is also called Parsing or Hierarchical Analysis. A Parser.
Parsing III (Eliminating left recursion, recursive descent parsing)
ISBN Chapter 4 Lexical and Syntax Analysis The Parsing Problem Recursive-Descent Parsing.
1 Predictive parsing Recall the main idea of top-down parsing: Start at the root, grow towards leaves Pick a production and try to match input May need.
9/27/2006Prof. Hilfinger, Lecture 141 Parsing Odds and Ends Lecture 14 (P. N. Hilfinger, plus slides adapted from R. Bodik)
CSC3315 (Spring 2009)1 CSC 3315 Lexical and Syntax Analysis Hamid Harroud School of Science and Engineering, Akhawayn University
ERROR HANDLING Lecture on 27/08/2013 PPT: 11CS10037 SAHIL ARORA.
Top-Down Parsing - recursive descent - predictive parsing
Lexical Analysis Hira Waseem Lecture
Profs. Necula CS 164 Lecture Top-Down Parsing ICOM 4036 Lecture 5.
SYNTAX ANALYSIS & ERROR RECOVERY By: Sarthak Swaroop.
Lesson 5 CDT301 – Compiler Theory, Spring 2011 Teacher: Linus Källberg.
Joey Paquet, 2000, Lecture 5 Error Recovery Techniques in Top-Down Predictive Syntactic Analysis.
1 Problems with Top Down Parsing  Left Recursion in CFG May Cause Parser to Loop Forever.  Indeed:  In the production A  A  we write the program procedure.
COP4020 Programming Languages Parsing Prof. Xin Yuan.
Chapter 4 Top-Down Parsing Recursive-Descent Gang S. Liu College of Computer Science & Technology Harbin Engineering University.
More Parsing CPSC 388 Ellen Walker Hiram College.
Top-down Parsing Recursive Descent & LL(1) Comp 412 Copyright 2010, Keith D. Cooper & Linda Torczon, all rights reserved. Students enrolled in Comp 412.
Top-Down Parsing CS 671 January 29, CS 671 – Spring Where Are We? Source code: if (b==0) a = “Hi”; Token Stream: if (b == 0) a = “Hi”; Abstract.
1 Nonrecursive Predictive Parsing  It is possible to build a nonrecursive predictive parser  This is done by maintaining an explicit stack.
Top-down Parsing. 2 Parsing Techniques Top-down parsers (LL(1), recursive descent) Start at the root of the parse tree and grow toward leaves Pick a production.
Top-Down Parsing.
1 Topic #4: Syntactic Analysis (Parsing) CSC 338 – Compiler Design and implementation Dr. Mohamed Ben Othman ( )
Chapter 2 (part) + Chapter 4: Syntax Analysis S. M. Farhad 1.
Joey Paquet, 2000, 2002, 2008, 2012, Lecture 5 Error Recovery Techniques in Top-Down Predictive Syntactic Analysis.
COMP 3438 – Part II-Lecture 6 Syntax Analysis III Dr. Zili Shao Department of Computing The Hong Kong Polytechnic Univ.
Compilers: Bottom-up/6 1 Compiler Structures Objective – –describe bottom-up (LR) parsing using shift- reduce and parse tables – –explain how LR.
Syntax Analysis Or Parsing. A.K.A. Syntax Analysis –Recognize sentences in a language. –Discover the structure of a document/program. –Construct (implicitly.
Concordia University Department of Computer Science and Software Engineering Click to edit Master title style COMPILER DESIGN Error recovery in top-down.
Error recovery in predictive parsing An error is detected during the predictive parsing when the terminal on top of the stack does not match the next input.
Syntax error handling –Errors can occur at many levels lexical: unknown operator syntactic: unbalanced parentheses semantic: variable never declared runtime:
Semantic analysis Jakub Yaghob
Problems with Top Down Parsing
LESSON 16.
Compiler design Bottom-up parsing Concepts
COP 4620 / 5625 Programming Language Translation / Compiler Writing Fall 2003 Lecture 5, 09/25/2003 Prof. Roy Levow.
Lecture 2 Lexical Analysis Joey Paquet, 2000, 2002, 2012.
Parsing IV Bottom-up Parsing
Introduction to Top Down Parser
Top-down parsing cannot be performed on left recursive grammars.
Syntax Analysis Chapter 4.
Compiler design Bottom-up parsing: Canonical LR and LALR
4 (c) parsing.
Syntax Analysis Sections :.
Lexical and Syntax Analysis
Top-Down Parsing CS 671 January 29, 2008.
CS 540 George Mason University
Compiler Design 7. Top-Down Table-Driven Parsing
Top-Down Parsing Identify a leftmost derivation for an input string
Top-Down Parsing The parse tree is created top to bottom.
Chapter 4 Top Down Parser.
Lecture 8: Top-Down Parsing
Bottom Up Parsing.
LL and Recursive-Descent Parsing Hal Perkins Autumn 2011
Bottom-Up Parsing “Shift-Reduce” Parsing
Computing Follow(A) : All Non-Terminals
Syntax Analysis - Parsing
Compiler design Syntactic analysis – part II First and follow sets
Nonrecursive Predictive Parsing
LL and Recursive-Descent Parsing Hal Perkins Autumn 2009
Compilers Principles, Techniques, & Tools Taught by Jing Zhang
Predictive Parsing Program
LL and Recursive-Descent Parsing Hal Perkins Winter 2008
Syntactic Analysis Part II
Compiler design Bottom-up parsing: Canonical LR and LALR
Compiler design Review COMP 442/6421 – Compiler Design
Parsing CSCI 432 Computer Science Theory
Presentation transcript:

Compiler design Error recovery in top-down predictive parsing COMP 442/6421 – Compiler Design Compiler design Error recovery in top-down predictive parsing Joey Paquet, 2000-2018

COMP 442/6421 – Compiler Design Syntax error recovery A syntax error happens when the stream of tokens coming from the lexical analyzer does not comply with the grammatical rules defining the programming language. The next token in input is not expected according to the syntactic definition of the language. One of the main roles of a compiler is to identify all programming errors and give meaningful indications about the location and nature of errors in the input program. Joey Paquet, 2000-2018

Goals of error recovery COMP 442/6421 – Compiler Design Goals of error recovery Detect all compile-time errors Report the presence of errors clearly and accurately Recover from each error quickly enough to be able to detect subsequent errors Should not slow down the processing of correct programs Avoid spurious errors that are just a consequence of an earlier error Joey Paquet, 2000-2018

COMP 442/6421 – Compiler Design Reporting errors Give the position of the error in the source file, maybe print the offending line and point at the error location. doy.cpp: In function `int main()': doy.cpp:25: `DayOfYear' undeclared (first use this function) doy.cpp:25: DayOfYear birthday; ^ If the nature of the error is easily identifiable, give a meaningful error message. The compiler should not provide erroneous information about the nature of errors. Joey Paquet, 2000-2018

COMP 442/6421 – Compiler Design Good error recovery Good error recovery highly depends on how quickly the error is detected. Often, an error will be detected only after the faulty token has passed. It will then be more difficult to achieve good error reporting, as well as good error recovery. Top-down parsers generally detect errors quicker than top-down parsers. Should recover from each error quickly enough to be able to detect subsequent errors. Error recovery should skip as less tokens as possible. Should not identify more errors than there really is. Cascades of errors that result from token skipping should be avoided. Should give meaningful information about the errors, while avoiding to give erroneous information. Error recovery should induce processing overhead only when errors are encountered. Should avoid to report other errors that are consequences of the application of error recovery, e.g. semantic errors. Joey Paquet, 2000-2018

Error recovery strategies COMP 442/6421 – Compiler Design Error recovery strategies There are many different strategies that a parser can employ to recover from syntactic errors. Although some are better than others, none of these methods provide a universal solution. Panic mode, or don’t panic (Nicklaus Wirth) Error productions Phrase level correction Global correction Joey Paquet, 2000-2018

Error Recovery Strategies COMP 442/6421 – Compiler Design Error Recovery Strategies Panic Mode On discovering an error, the parser discards input tokens until an element of a designated set of synchronizing tokens is found. Synchronizing tokens are typically delimiters such as semicolons or end of block delimiters. A systematic and general approach is to use the FIRST and FOLLOW sets as synchronizing tokens. Skipping tokens often has a side-effect of skipping other errors. Choosing the right set of synchronizing tokens is of prime importance. Simplest method to implement. Can be integrated in most parsing methods. Cannot enter an infinite loop. Joey Paquet, 2000-2018

Error Recovery Strategies COMP 442/6421 – Compiler Design Error Recovery Strategies Error Productions The grammar is augmented with “error productions”. For each possible error, an error production is added. An error is trapped when an error production is used. Assumes that all specific errors are known in advance. One error production is needed for each possible error. Error productions are specific to the rules in the grammar. A change in the grammar implies a change of the corresponding error productions. Extremely hard to maintain. Joey Paquet, 2000-2018

Error Recovery Strategies COMP 442/6421 – Compiler Design Error Recovery Strategies Phrase-Level Correction On discovering an error, the parser performs a local correction on the remaining input, e.g. replace a comma by a semicolon, delete an extraneous semicolon, insert a missing semicolon, etc. Corrections are done in specific contexts. There are myriads of different such contexts. Cannot cope with errors that occurred before the point of detection. Can enter an infinite loop, e.g. insertion of an expected token. Joey Paquet, 2000-2018

Error Recovery Strategies COMP 442/6421 – Compiler Design Error Recovery Strategies Global Correction Ideally, a compiler should make as few changes as possible in processing an incorrect token stream. Global correction is about choosing the minimal sequence of changes to obtain a least-cost correction. Given an incorrect input token stream x, global correction will find a parse tree for a related token stream y, such that the number of insertions, deletions, and changes of tokens required to transform x into y is as reduced as possible. Too costly to implement. The closest correct program does not carry the meaning intended by the programmer anyway. Can be used as a benchmark for other error correction techniques. Joey Paquet, 2000-2018

Different variations of “panic mode” error recovery COMP 442/6421 – Compiler Design Different variations of “panic mode” error recovery Joey Paquet, 2000-2018

Panic mode error recovery: variations COMP 442/6421 – Compiler Design Panic mode error recovery: variations Variation 1: Given a non-terminal A on top of the stack, skip input tokens until an element of FOLLOW(A) appears in the token stream. Pop A from the stack and resume parsing. Report on the error found and where the parsing was resumed. Variation 2: Given a non-terminal A on top of the stack, skip input tokens until an element of FIRST(A) appears in the token stream. Variation 3 If we combine variation 1 and 2, when there is a parse error and a variable A on top of the stack, we skip input tokens until we see either a token in FIRST(A), in which case we simply continue, a token in FOLLOW(A), in which case we pop A off the stack and continue. Joey Paquet, 2000-2018

Error Recovery in Recursive Descent Predictive Parsers COMP 442/6421 – Compiler Design Error Recovery in Recursive Descent Predictive Parsers Joey Paquet, 2000-2018

Error Recovery in Recursive Descent Predictive Parsers COMP 442/6421 – Compiler Design Error Recovery in Recursive Descent Predictive Parsers Three possible cases: The lookahead symbol is not in FIRST(LHS). If  is in FIRST(LHS) and the lookahead symbol is not in FOLLOW(LHS). The match() function is called in a no match situation. Solution: Create a skipErrors() function that skips tokens until an element of FIRST(LHS) or FOLLOW(LHS) is encountered. Upon entering any parsing function, call skipErrors(). Joey Paquet, 2000-2018

Error Recovery in Recursive Descent Predictive Parsers COMP 442/6421 – Compiler Design Error Recovery in Recursive Descent Predictive Parsers skipErrors([FIRST],[FOLLOW]) if ( lookahead is in [FIRST] or  is in [FIRST] and lookahead is in [FOLLOW] ) return true // no error detected, parse continues in this parsing function else write (“syntax error at “ lookahead.location) while (lookahead not in [FIRST  FOLLOW] ) lookahead = nextToken() if ( is in [FIRST] and lookahead is in [FOLLOW]) return false // error detected and parsing function should be aborted return true // error detected and parse continues in this parsing function match(token) if ( lookahead == token ) lookahead = nextToken() return true else write (“syntax error at” lookahead.location. “expected” token) return false Joey Paquet, 2000-2018

Error Recovery in Recursive Descent Predictive Parsers COMP 442/6421 – Compiler Design Error Recovery in Recursive Descent Predictive Parsers LHS(){ // LHSRHS1 | RHS2 | … |  if ( !skipErrors( FIRST(LHS),FOLLOW(LHS) ) ) return false; if (lookahead  FIRST(RHS1) ) if (non-terminals()  match(terminals) ) write(“LHSRHS1”) else success = false else if (lookahead  FIRST(RHS2) ) write(“LHSRHS2”) else if … // other right hand sides else if (lookahead  FOLLOW(LHS) ) // only if LHS exists write(“LHS”) return (success) Joey Paquet, 2000-2018

Example COMP 442/6421 – Compiler Design Joey Paquet, 2000-2018 E(){ if ( !skipErrors([0,1,(],[),$]) ) return false; if (lookahead is in [0,1,(]) if (T();E'();) write(E->TE') else success = false return (success) } E'(){ if ( !skipErrors([+],[),$]) ) return false; if (lookahead is in [+]) if (match('+');T();E'()) write(E'->TE') else success = false else if (lookahead is in [$,)] write(E'->epsilon); return (success) } T(){ if ( !skipErrors([0,1,(],[+,),$]) ) return false; if (lookahead is in [0,1,(]) if (F();T'();) write(T->FT') else success = false return (success) } T'(){ if ( !skipErrors([*],[+,),$]) ) return false; if (lookahead is in [*]) if (match('*');F();T'()) write(T'->*FT') else success = false else if (lookahead is in [+,),$] write(T'->epsilon) return (success) } F(){ if ( !skipErrors([0,1,(],[*,+,$,)]) ) return false; if (lookahead is in [0]) match('0') write(F->0) else if (lookahead is in [1]) match('1') write(F->1) else if (lookahead is in [(]) if (match('(');E();match(')')) write(F->1); else success = false return (success) } Joey Paquet, 2000-2018

Error Recovery in Table-Driven Predictive Parsers COMP 442/6421 – Compiler Design Error Recovery in Table-Driven Predictive Parsers Joey Paquet, 2000-2018

Error Recovery in Table-Driven Predictive Parsers COMP 442/6421 – Compiler Design Error Recovery in Table-Driven Predictive Parsers All empty cells in the table represent the occurrence of a syntax error Each case represents a specific kind of error Task when an empty (error) cell is read: Recover from the error Either pop the stack, or skip tokens (often called “scan”) Output an error message Joey Paquet, 2000-2018

Building the table with error cases COMP 442/6421 – Compiler Design Building the table with error cases Two possible cases: pop the stack if the next token is in the FOLLOW set of our current non-terminal on top of the stack. scan tokens until we get one with which we can resume the parse. skipError(){ // A is top() write (“syntax error at “ lookahead.location) if ( lookahead is $ or in FOLLOW( top() ) ) pop() // pop - equivalent to A   else while ( lookahead  FIRST( top() ) or   FIRST( top() ) and lookahead  FOLLOW( top() ) ) lookahead = nextToken() // scan } Joey Paquet, 2000-2018

Original table, grammar and sets COMP 442/6421 – Compiler Design Original table, grammar and sets r1: E  TE r2: E  +TE r3: E   r4: T  FT r5: T  FT r6: T   r7: F  0 r8: F  1 r9: F  ( E ) FST(E) : { 0,1,( } FST(E’) : { ,+ } FST(T) : { 0,1,( } FST(T’) : { ,* } FST(F) : { 0,1,( } FLW(E) : { $,) } FLW(E’) : { $,) } FLW(T) : { +,$,) } FLW(T’) : { +,$,) } FLW(F) : { ,+,$,) } 1 ( ) + * $ E r1 E’ r3 r2 T r4 T’ r6 r5 F r7 r8 r9 Joey Paquet, 2000-2018

Parsing table with error actions COMP 442/6421 – Compiler Design Parsing table with error actions pop: if the next token in input is in FOLLOW(LHS), pop() RHS from the stack. scan: else, repeat ( nextToken() ) until (FIRST(LHS) is found or if FIRST(LHS) constains , FOLLOW(RHS) is found) 1 ( ) + * $ E r1 R1 pop scan E’ R3 r2 r3 T r4 R4 T’ r6 r5 F r7 R8 R9 Joey Paquet, 2000-2018

Parsing algorithm parse(){ push($) push(S) a = nextToken() COMP 442/6421 – Compiler Design Parsing algorithm parse(){ push($) push(S) a = nextToken() while ( stack  $ ) do x = top() if ( x  T ) if ( x == a ) pop(x) ; a = nextToken() else skipError() ; success = false if ( TT[x,a]  ‘error’ ) pop(x) ; inverseRHSPush(TT[x,a]) if ( (a  $)  (success == false ) ) return(false) return(true)} Joey Paquet, 2000-2018

Parsing example with error recovery COMP 442/6421 – Compiler Design Parsing example with error recovery Stack Input Production Derivation 1 $E 0(*1)$ E 2 r1: ETE’  TE’ 3 $E’T R4: TFT’  FT’E’ 4 $E’T’F R7: F0  0T’E’ 5 $E’T’0 6 $E’T’ (*1)$ error - scan 7 *1)$ r5: T  FT  0*FT’E’ 8 $E’T’F* 9 1)$ r8: F  1  0*1T’E’ 10 $E’T’1 11 )$ r6: T    0*1E’ 12 $E’ r3: E    0*1 13 $ error - end Joey Paquet, 2000-2018