7 CD-PPT-4 Unit
7 CD-PPT-4 Unit
Compiler Design
Unit No 3: Error Recovery
SEMESTER: 7
PREPARED BY:
Syntax Error Recovery
2
2
Goals of Error Handling
• Give the position of the error in the source file, maybe print the
offending line and point at the error location
• 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
• If the error is easily correctable, a solution can be proposed or
applied by the compiler and a simple warning issued
4
4
Good Error Recovery
5
5
Error Recovery Strategies
6
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.
– 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.
7
7
Error Recovery Strategies
• Phrase Level
– 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.
– Replacements 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.
8
8
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 kinds of 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. 9
9
–
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, such an algorithm
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 small as
possible.
– Too costly to implement.
– The closest correct program does not carry the meaning
intended by the programmer anyway.
– Joey
CanPaquet,
be used as2002,
2000, a benchmark for other error correction
2008, 2012, 2014
10
10
techniques.
Error Recovery in Recursive
Descent Predictive Parsers
Cont.
return (true) // no error detected
else
write (“syntax error at “ lookahead.location)
while (lookahead not in [FIRST ∪ FOLLOW] )
lookahead = nextToken()
write (“parsing resumed at “ lookahead.location)
return (false) // error detected
match(token)
if ( lookahead == token )
lookahead = nextToken()
return (true)
else
write (“syntax error at” lookahead.location. “expected” token)
lookahead = nextToken()
return (false)
12
Joey Paquet, 2000, 2002, 2008, 2012, 2014 12
Constructing the Parser
LHS(){ // LHS→RHS1 | RHS2 | … | ε
success = skipErrors( FIRST(LHS),FOLLOW(LHS) )
if (lookahead ∈ FIRST(RHS1) )
if (non-terminals() ∧ match(terminals) )
write(“LHS→RHS1”)
else success = false
else if (lookahead ∈ FIRST(RHS2) )
if (non-terminals() ∧ match(terminals) )
write(“LHS→RHS2”)
else success = false
else if … // other right hand sides
else if (lookahead ∈ FOLLOW(LHS) ) // only if LHS→ε exists
write(“LHS→ε”)
else success = false
return (success)
13
Joey Paquet, 2000, 2002, 2008, 2012, 2014 13
Example
E(){
success = skipErrors([0,1,(],[),$])
if (lookahead is in [0,1,(]) //FIRST(TE')
if (T();E'();) write(E->TE')
else success = false
else success = false
return (success)
}
14
Joey Paquet, 2000, 2002, 2008, 2012, 2014 14
Example
E'(){
success = skipErrors([+],[),$])
if (lookahead is in [+]) //FIRST[+TE']
if (match('+');T();E'()) write(E'->TE')
else success = false
else if (lookahead is in [$,)] //FOLLOW[E'](epsilon)
write(E'->epsilon);
else success = false
return (success)
}
15
Joey Paquet, 2000, 2002, 2008, 2012, 2014 15
Example
T(){
success = skipErrors([0,1,(],[+,),$])
if (lookahead is in [0,1,(]) //FIRST[FT']
if (F();T'();) write(T->FT')
else success = false
else success = false
return (success)
}
16
Joey Paquet, 2000, 2002, 2008, 2012, 2014 16
Example
T'(){
success = skipErrors([*],[+,),$])
if (lookahead is in [*]) //FIRST[*FT']
if (match('*');F();T'()) write(T'->*FT')
else success = false
else if (lookahead is in [+,),$] //FOLLOW[T'] (epsilon)
write(T'->epsilon)
else success = false
return (success)
}
17
Joey Paquet, 2000, 2002, 2008, 2012, 2014 17
F(){
Example
success = skipErrors([0,1,(],[*,+,$,)])
if (lookahead is in [0]) //FIRST[0]
match('0') write(F->0)
else if (lookahead is in [1]) //FIRST[1]
match('1') write(F->1)
else if (lookahead is in [(]) //FIRST[(E)]
if (match('(');E();match(')')) write(F->1);
else success = false
else success = false
return (success)
}
18
Joey Paquet, 2000, 2002, 2008, 2012, 2014 18
Error Recovery in Table-Driven
Predictive Parsers
skipError(){ // A is top()
write (“syntax error at “ lookahead.location)
if (lookahead is $ or in FOLLOW(A))
pop() // pop. equivalent to A → ε
else
lookahead = nextToken() // scan.
}
20
Joey Paquet, 2000, 2002, 2008, 2012, 2014 20
Original table, grammar and
r1:
r2:
E
E′
→
→
TE′
+TE′
sets
FST(E)
FST(E’)
:
:
{
{
0,1,( }
ε,+ }
FLW(E)
FLW(E’)
:
:
{
{
$,) }
$,) }
r3: E′ → ε FST(T) : { 0,1,( } FLW(T) : { +,$,) }
r4: T → FT′ FST(T’) : { ε,* } FLW(T’) : { +,$,) }
r5: T′ → *FT′ FST(F) : { 0,1,( } FLW(F) : { *,+,$,) }
r6: T′ → ε
r7: F → 0
r8: F → 1
r9: F → ( E )
0 1 ( ) + * $
E r1 r1 r1
E’ r3 r2 r3
T r4 r4 r4
T’ r6 r6 r5 r6
F r7 r8 r9
21
21
Parsing table with error actions
0 1 ( ) + * $
E r1 r1 r1 pop scan scan pop
E’ scan scan scan r3 r2 scan r3
T r4 r4 r4 pop pop scan pop
T’ scan scan scan r6 r6 r5 r6
F r7 r8 r9 pop pop pop pop
22
22
parse(){
push($)
Parser Algorithm push(S)
a = nextToken()
while ( stack ≠ $ ) do
x = top()
if ( x ∈ T )
if ( x == a )
pop(x) ; a = nextToken()
else
skipError() ; success = false
else
if ( TT[x,a] ≠ ‘error’ )
pop(x) ; inverseMultiplePush(TT[x,a])
else
skipError() ; success = false
if ( (a ≠ $) ∨ (success == false ) )
return(false)
else
return(true)}
23
23
Disambiguating Rules for Parsing Conflict
• Shift-reduce conflict
• Prefer shift over reduce
• In case of nested if statements, preferring shift over reduce
implies most closely nested rule for dangling else
• Reduce-reduce conflict
• Error in design
24