Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 8

UNIT-4

ERROR RECOVERY
One of the important tasks that a compiler must perform is the detection of and recovery
from errors. Recovery from errors is important, because the compiler will be scanning and
compiling the entire program, perhaps in the presence of errors; so as many errors as
possible need to be detected . After detecting an error, the first thing that a compiler is
supposed to do is to report the error by producing a suitable diagnostic. A good error
diagnostic should possess the following properties.
a. The message should be produced in terms of the original source program
rather than in terms of some internal representation of the source program.
b. The error message should be easy to understand by the user .
c. The error message should be specific and should localize the problem.

d. The message should not be redundant.

RECOVERY FROM LEXICAL PHASE ERRORS


The lexical analyzer detects an error when it discovers that an input's prefix does not fit the
specification of any token class. After detecting an error, the lexical analyzer can invoke an
error recovery routine. This can entail a variety of remedial actions.
The simplest possible error recovery is to skip the erroneous characters until the lexical
analyzer finds another token. But this is likely to cause the parser to read a deletion error,
which can cause severe difficulties in the syntax analysis and remaining phases. One way
the parser can help the lexical analyzer can improve its ability to recover from errors is to
make its list of legitimate tokens (in the current context) available to the error recovery
routine. The error-recovery routine can then decide whether a remaining input's prefix
matches one of these tokens closely enough to be treated as that token.

RECOVERY FROM SYNTACTIC PHASE ERRORS


A parser detects an error when it has no legal move from its current configuration. The LL (1)
and LR (1) parsers use the valid prefix property; therefore, they are capable of announcing
an error as soon as they read an input that is not a valid continuation of the previous input's
prefix. This is earliest time that a left-to-right parser can announce an error. But there are a
variety of other types of parsers that do not necessarily have this property.
The advantages of using a parser with a valid-prefix-property capability is that it reports an
error as soon as possible, and it minimizes the amount of erroneous output passed to
subsequent phases of the compiler.

Panic Mode Recovery


Panic mode recovery is an error recovery method that can be used in any kind of parsing,
because error recovery depends somewhat on the type of parsing technique used. In panic
mode recovery, a parser discards input symbols until a statement delimiter , such as a
semicolon or an end, is encountered . The parser then deletes stack entries until it finds an
entry that will allow it to continue parsing, given the synchronizing token on the input. This
method is simple to implement, and it never gets into an infinite loop.

Phrase Level Recovery

ERROR RECOVERY IN LR PARSING


Another method of error recovery that can be implemented is called "phrase level recovery".
Each error entry in the LR parsing table is examined, and, based on language usage; an
appropriate error-recovery procedure is constructed. For example, to recover from a
construct error that starts with an operator, the error-recovery routine will push an imaginary
id onto the stack and cover it with the appropriate state. While doing this, the error entries in
a particular state that call for a particular reduction on some input symbols are replaced by
that reduction. This has the effect of postponing the error detection until one or more
reductions are made; but the error will still be caught before a shift.
A phrase level error-recovery implementation for an LR parser is shown below. The parsing
table's grammar is:
The SLR parsing table for the above grammar is shown in Table 1.

id

E
1

Accept

S 3/ R

S 4/ R

S 3/ R

S 4/ R

5
6

The conflict is resolved by giving higher precedence to * and using left associativity, as
shown in Table 2.

Table 2: Higher Precedent * and Left-Associativity

id

E
1

Accept

5
6

The parsing table with error routines is shown in Table 3, where routine e 1 is called from
states I , I 3 , and I 4 , which pushes an imaginary id onto the stack and covers it with state I 2 .
The routine e 2 is called from state I 1 , which pushes + onto stack and covers it with state I 3 .

id

Accept

5
6

Table 3: Parsing Table with Error Routines


For example, if we trace the behavior of the parser described above for the input id + *id $:
Stack Contents

$I
$ I id I
$ I EI

$ I EI 1 + I

$ I EI 1 + I 3 id I

Unspent Input

Moves

id+*id$

shift and enter into state 2

+*id$

reduce by production number 3

+*id$

shift and enter into state 3

*id$

call error routine e 1

*id$

reduce by production number 3

*id$

shift and enter into state 4

id$

shift and enter into state 2

reduce by production number 3

reduce by production number 2

reduce by production number 1

Accept

(id I 2 pushed by e 1)
$ I EI 1 + I 3 EI

$ I EI 1 + I 3 E I 5 * I

$ I EI 1 + I 3 E I 5 * I 4 id I
$ I EI 1 + I 3 E I 5 * I 4 EI
$ I EI 1 + I 3 EI
$ I EI

Similarly, if we trace the behavior of the parser for the input id id*id $:
Stack Contents
$I
$ I id I
$ I EI

Unspent Input

Moves

id id*id$

shift and enter into state 2

id*id$

reduce by production number 3

id*id$

call error routine e

Stack Contents
$ I EI 1 + I

Unspent Input

Moves

id*id$

shift and enter into state 2

*id$

reduce by production number 3

*id$

shift and enter into state 4

id$

shift and enter into state 2

reduce by production number 3

reduce by production number 2

reduce by production number 1

Accept

( I 3 pushed by e 2)
$ I EI 1 + I 3 id I
$ I EI 1 + I 3 EI

$ I EI 1 + I 3 EI 5 * I

$ I EI 1 + I 3 EI 5 * I 4 id I
$ I EI 1 + I 3 EI 5 * I 4 EI
$ I EI 1 + I 3 EI
$ I EI

PREDICTIVE PARSING ERROR RECOVERY


An error is detected during predictive parsing when the terminal on the top of the stack does
not match the next input symbol, or when nonterminal A is on top of the stack and a is the
next input symbol. M [A,a ] is the error entry. Panic mode recovery can be used to recover
from an error detected by the LL parser. The effectiveness of panic mode recovery depends
on the choice of the synchronizing token. Several heuristics can be used when selecting the
synchronizing token in order to ensure quick recovery from common errors:

Another method of error recovery that can be implemented is called "phrase level recovery".
In phrase level recovery, each error entry in the LL parsing table is examined, and based on
language usage, an appropriate error-recovery procedure is constructed
A phrase level error-recovery implementation for an LL parser is shown in Tables 4 and 5.
The parsing table is constructed for the following grammar:

Id

E TE

T FT

F id

T 1

id

+ TE

T 1 * FT

E 1

T 1

pop

Pop

Pop

Accept

Table 4: LL Parsing Table


The modified table is shown in Table 5. Routine e 1 , when called, pushes an imaginary id into
the input; and routine e 2 , when called, removes all the remaining symbols from the input.
id

E TE

T FT

F id

F
E

E 1

T 1

T 1

id
+
*

+ TE

E 1

T 1 * FT

pop
Pop
Pop

E 1

T 1

Accept

Table 5: Phrase Level Error-Recovery Implementation


For example, if we trace the behavior of the parser shown in Table 5 for the input id + *id $:
Stack Contents

Unspent Input

Moves

$E

id+*id$

derive using E TE

$ E 1T

id+*id$

derive using T FT

$ E 1T 1F

id+*id$

derive using F id

$ E 1 T 1 id

id+*id$

Pop

$ E 1T

+*id$

derive using T 1

+*id$

derive using E 1 + TE

$ E 1T +

+*id$

Pop

$ E 1T

*id$

call error routine e 1

$ E 1T

id*id$

derive using T FT

$E

(imaginary id is pushed by e 1 )
$ E 1T 1F

id*id$

derive using F id

$ E 1 T 1 id

id*id$

Pop

$ E 1T

*id$

derive using T 1 * FT

$ E 1T 1F

id$

derive using F id

$ E 1 T 1 id

id$

Pop

$ E 1T

derive using T

Stack Contents

$E

Unspent Input

Moves

derive using E 1

Accept

Similarly, if we trace the behavior for the input id id*id $:


Stack Contents

Unspent Input

Moves

$E

id id*id$

derive using E TE

$ E 1T

id+*id$

derive using T FT

$ E 1T 1F

id+*id$

derive using F id

$ E 1 T 1 id

id+*id$

Pop

$ E 1T

id*id$

derive using T 1

id*id$

derive using E 1

id*id$

call error routine e

Accept

$E

(id*id$ is removed by e 2 )
$

RECOVERY FROM SEMANTIC ERRORS


The primary sources of semantic errors are undeclared names and type incompatibilities.
Recovery from an undeclared name is rather straightforward. The first time the undeclared
name is encountered, an entry can be made in the symbol table for that name with an
attribute that is appropriate to the current context. For example, if missing declaration error
of x is encountered, then the error-recovery routine enters the appropriate attribute
for x in x 's symbol table, depending on the current context of x . A flag is then set in
the x symbol table record to indicate that an attribute has been added, and to recover from
an error or not in response to the declaration of x .

You might also like