Sophie

Sophie

distrib > Mageia > 7 > armv7hl > media > core-release > by-pkgid > a1ac99f7e5cfc095abe44203b7d37fb2 > files > 11

javacc-manual-7.0.2-2.mga7.noarch.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<!--

Copyright (c) 2006, Sun Microsystems, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the Sun Microsystems, Inc. nor the names of its
      contributors may be used to endorse or promote products derived from
      this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.

-->
<head>
	<link href="/styles.css" media="screen" rel="stylesheet" type="text/css" /> 
 <title>JavaCC: Error Reporting and Recovery</title>
<!-- Changed by: Michael Van De Vanter, 14-Jan-2003 -->
</head>
<body bgcolor="#FFFFFF" >

<h1>JavaCC [tm]: Error Reporting and Recovery</h1>

<p>
This document describes the error recovery features introduced in
Version 0.7.1.  This document also describes how features have changed
since Version 0.6.
</p>
<p>
The first change (from 0.6) is that we have two new exceptions:
</p>
<pre>
    . ParseException
    . TokenMgrError
</pre>
<p>
Whenever the token manager detects a problem, it throws the exception
TokenMgrError.  Previously, it used to print the message:
</p>
<pre>
  Lexical Error ...
</pre>
<p>
following which it use to throw the exception ParseError.
</p>
<p>
Whenever the parser detects a problem, it throws the exception
ParseException.  Previously, it used to print the message:
</p>
<pre>
  Encountered ... Was expecting one of ...
</pre>
<p>
following which it use to throw the exception ParseError.
</p>
<p>
In Version 0.7.1, error messages are never printed explicitly,
rather this information is stored inside the exception objects that
are thrown.  Please see the classes ParseException.java and
TokenMgrError.java (that get generated by JavaCC [tm] during parser
generation) for more details.
</p>
<p>
If the thrown exceptions are never caught, then a standard action is
taken by the virtual machine which normally includes printing the
stack trace and also the result of the "toString" method in the
exception.  So if you do not catch the JavaCC exceptions, a message
quite similar to the ones in Version 0.6.
</p>
<p>
But if you catch the exception, you must print the message yourself.
</p>
<p>
Exceptions in the Java [tm] programming language are all subclasses of
type Throwable.  Furthermore, exceptions are divided into two broad
categories - ERRORS and other exceptions.
</p>
<p>
Errors are exceptions that one is not expected to recover from -
examples of these are ThreadDeath or OutOfMemoryError.  Errors are
indicated by subclassing the exception "Error".  Exceptions subclassed
from Error need not be specified in the "throws" clause of method
declarations.
</p>
<p>
Exceptions other than errors are typically defined by subclassing the
exception "Exception".  These exceptions are typically handled by the
user program and must be declared in throws clauses of method
declarations (if it is possible for the method to throw that
exception).
</p>
<p>
The exception TokenMgrError is a subclass of Error, while the
exception ParseException is a subclass of Exception.  The reasoning
here is that the token manager is never expected to throw an exception
- you must be careful in defining your token specifications such that
you cover all cases.  Hence the suffix "Error" in TokenMgrError.  You
do not have to worry about this exception - if you have designed your
tokens well, it should never get thrown.  Whereas it is typical to
attempt recovery from Parser errors - hence the name "ParseException".
(Although if you still want to recover from token manager errors, you
can do it - it's just that you are not forced to catch them.)
</p>
<p>
In Version 0.7.1, we have added a syntax to specify additional exceptions
that may be thrown by methods corresponding to non-terminals.  This
syntax is identical to the Java "throws ..." syntax.  Here's an
example of how you use this:
</p>
<pre>

  void VariableDeclaration() throws SymbolTableException, IOException :
  {...}
  {
    ...
  }
</pre>
<p>
Here, VariableDeclaration is defined to throw exceptions
SymbolTableException and IOException in addition to ParseException.
</p>
<h2>Error Reporting</h2>
<p>
The scheme for error reporting is simpler in Version 0.7.1 (as compared
to Version 0.6) - simply modify the file ParseException.java to do
what you want it to do.  Typically, you would modify the getMessage
method to do your own customized error reporting.  All information
regarding these methods can be obtained from the comments in the
generated files ParseException.java and TokenMgrError.java.  It will
also help to understand the functionality of the class Throwable (read
a Java book for this).
</p>
<p>
There is a method in the generated parser called
"generateParseException".  You can call this method anytime you wish
to generate an object of type ParseException.  This object will
contain all the choices that the parser has attempted since the last
successfully consumed token.
</p>

<h2>Error Recovery</h2>
<p>
JavaCC offers two kinds of error recovery - shallow recovery and deep
recovery.  Shallow recovery recovers if none of the current choices
have succeeded in being selected, while deep recovery is when a choice
is selected, but then an error happens sometime during the parsing of
this choice.
</p>
<h3>Shallow Error Recovery</h3>
<p>
We shall explain shallow error recovery using the following example:
</p>
<pre>
void Stm() :
{}
{
  IfStm()
|
  WhileStm()
}
</pre>
<p>
Let's assume that IfStm starts with the reserved word "if" and WhileStm
starts with the reserved word "while".  Suppose you want to recover by
skipping all the way to the next semicolon when neither IfStm nor WhileStm
can be matched by the next input token (assuming a lookahead of 1).  That
is the next token is neither "if" nor "while".
</p>
<p>
What you do is write the following:
</p>
<pre>
void Stm() :
{}
{
  IfStm()
|
  WhileStm()
|
  error_skipto(SEMICOLON)
}
</pre>
<p>
But you have to define "error_skipto" first.  So far as JavaCC is concerned,
"error_skipto" is just like any other non-terminal.  The following is one
way to define "error_skipto" (here we use the standard JAVACODE production):
</p>
<pre>
JAVACODE
void error_skipto(int kind) {
  ParseException e = generateParseException();  // generate the exception object.
  System.out.println(e.toString());  // print the error message
  Token t;
  do {
    t = getNextToken();
  } while (t.kind != kind);
    // The above loop consumes tokens all the way up to a token of
    // "kind".  We use a do-while loop rather than a while because the
    // current token is the one immediately before the erroneous token
    // (in our case the token immediately before what should have been
    // "if"/"while".
}
</pre>
<p>
That's it for shallow error recovery.  In a future version of JavaCC
we will have support for modular composition of grammars.  When this
happens, one can place all these error recovery routines into a
separate module that can be "imported" into the main grammar module.
We intend to supply a library of useful routines (for error recovery
and otherwise) when we implement this capability.
</p>
<h3>Deep Error Recovery</h3>
<p>
Let's use the same example that we did for shallow recovery:
</p>
<pre>
void Stm() :
{}
{
  IfStm()
|
  WhileStm()
}
</pre>
<p>
In this case we wish to recover in the same way.  However, we wish to
recover even when there is an error deeper into the parse.  For
example, suppose the next token was "while" - therefore the choice
"WhileStm" was taken.  But suppose that during the parse of WhileStm
some error is encountered - say one has "while (foo { stm; }" - i.e., the
closing parentheses has been missed.  Shallow recovery will not work
for this situation.  You need deep recovery to achieve this.  For this,
we offer a new syntactic entity in JavaCC - the try-catch-finally block.
</p>
<p>
First, let us rewrite the above example for deep error recovery and then
explain the try-catch-finally block in more detail:
</p>
<pre>
void Stm() :
{}
{
  try {
    (
      IfStm()
    |
      WhileStm()
    )
  catch (ParseException e) {
    error_skipto(SEMICOLON);
  }
}
</pre>
<p>
That's all you need to do.  If there is any unrecovered error during the
parse of IfStm or WhileStm, then the catch block takes over.  You can
have any number of catch blocks and also optionally a finally block
(just as with Java errors).  What goes into the catch blocks is *Java code*,
not JavaCC expansions.  For example, the above example could have been
rewritten as:
</p>
<pre>
void Stm() :
{}
{
  try {
    (
      IfStm()
    |
      WhileStm()
    )
  catch (ParseException e) {
    System.out.println(e.toString());
    Token t;
    do {
      t = getNextToken();
    } while (t.kind != SEMICOLON);
  }
}
</pre>
<p>
Our belief is that it's best to avoid placing too much Java code in the
catch and finally blocks since it overwhelms the grammar reader.  Its best
to define methods that you can then call from the catch blocks.
</p>
<p>
Note that in the second writing of the example, we essentially copied
the code out of the implementation of error_skipto.  But we left out the
first statement - the call to generateParseException.  That's because in
this case, the catch block already provides us with the exception.  But
even if you did call this method, you will get back an identical object.
</p>
</body>
</html>