001: /*
002: [The "BSD licence"]
003: Copyright (c) 2005-2006 Terence Parr
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009: 1. Redistributions of source code must retain the above copyright
010: notice, this list of conditions and the following disclaimer.
011: 2. Redistributions in binary form must reproduce the above copyright
012: notice, this list of conditions and the following disclaimer in the
013: documentation and/or other materials provided with the distribution.
014: 3. The name of the author may not be used to endorse or promote products
015: derived from this software without specific prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
018: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
019: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
020: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
021: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028: package org.antlr.runtime;
029:
030: import org.antlr.runtime.tree.*;
031:
032: /** The root of the ANTLR exception hierarchy.
033: *
034: * To avoid English-only error messages and to generally make things
035: * as flexible as possible, these exceptions are not created with strings,
036: * but rather the information necessary to generate an error. Then
037: * the various reporting methods in Parser and Lexer can be overridden
038: * to generate a localized error message. For example, MismatchedToken
039: * exceptions are built with the expected token type.
040: * So, don't expect getMessage() to return anything.
041: *
042: * Note that as of Java 1.4, you can access the stack trace, which means
043: * that you can compute the complete trace of rules from the start symbol.
044: * This gives you considerable context information with which to generate
045: * useful error messages.
046: *
047: * ANTLR generates code that throws exceptions upon recognition error and
048: * also generates code to catch these exceptions in each rule. If you
049: * want to quit upon first error, you can turn off the automatic error
050: * handling mechanism using rulecatch action, but you still need to
051: * override methods mismatch and recoverFromMismatchSet.
052: *
053: * In general, the recognition exceptions can track where in a grammar a
054: * problem occurred and/or what was the expected input. While the parser
055: * knows its state (such as current input symbol and line info) that
056: * state can change before the exception is reported so current token index
057: * is computed and stored at exception time. From this info, you can
058: * perhaps print an entire line of input not just a single token, for example.
059: * Better to just say the recognizer had a problem and then let the parser
060: * figure out a fancy report.
061: */
062: public class RecognitionException extends Exception {
063: /** What input stream did the error occur in? */
064: public transient IntStream input;
065:
066: /** What is index of token/char were we looking at when the error occurred? */
067: public int index;
068:
069: /** The current Token when an error occurred. Since not all streams
070: * can retrieve the ith Token, we have to track the Token object.
071: * For parsers. Even when it's a tree parser, token might be set.
072: */
073: public Token token;
074:
075: /** If this is a tree parser exception, node is set to the node with
076: * the problem.
077: */
078: public Object node;
079:
080: /** The current char when an error occurred. For lexers. */
081: public int c;
082:
083: /** Track the line at which the error occurred in case this is
084: * generated from a lexer. We need to track this since the
085: * unexpected char doesn't carry the line info.
086: */
087: public int line;
088:
089: public int charPositionInLine;
090:
091: /** If you are parsing a tree node stream, you will encounter som
092: * imaginary nodes w/o line/col info. We now search backwards looking
093: * for most recent token with line/col info, but notify getErrorHeader()
094: * that info is approximate.
095: */
096: public boolean approximateLineInfo;
097:
098: /** Used for remote debugger deserialization */
099: public RecognitionException() {
100: }
101:
102: public RecognitionException(IntStream input) {
103: this .input = input;
104: this .index = input.index();
105: if (input instanceof TokenStream) {
106: this .token = ((TokenStream) input).LT(1);
107: this .line = token.getLine();
108: this .charPositionInLine = token.getCharPositionInLine();
109: }
110: if (input instanceof TreeNodeStream) {
111: extractInformationFromTreeNodeStream(input);
112: } else if (input instanceof CharStream) {
113: this .c = input.LA(1);
114: this .line = ((CharStream) input).getLine();
115: this .charPositionInLine = ((CharStream) input)
116: .getCharPositionInLine();
117: } else {
118: this .c = input.LA(1);
119: }
120: }
121:
122: protected void extractInformationFromTreeNodeStream(IntStream input) {
123: TreeNodeStream nodes = (TreeNodeStream) input;
124: this .node = nodes.LT(1);
125: TreeAdaptor adaptor = nodes.getTreeAdaptor();
126: Token payload = adaptor.getToken(node);
127: if (payload != null) {
128: this .token = payload;
129: if (payload.getLine() <= 0) {
130: // imaginary node; no line/pos info; scan backwards
131: int i = -1;
132: Object priorNode = nodes.LT(i);
133: while (priorNode != null) {
134: Token priorPayload = adaptor.getToken(priorNode);
135: if (priorPayload != null
136: && priorPayload.getLine() > 0) {
137: // we found the most recent real line / pos info
138: this .line = priorPayload.getLine();
139: this .charPositionInLine = priorPayload
140: .getCharPositionInLine();
141: this .approximateLineInfo = true;
142: break;
143: }
144: --i;
145: priorNode = nodes.LT(i);
146: }
147: } else { // node created from real token
148: this .line = payload.getLine();
149: this .charPositionInLine = payload
150: .getCharPositionInLine();
151: }
152: } else if (this .node instanceof Tree) {
153: this .line = ((Tree) this .node).getLine();
154: this .charPositionInLine = ((Tree) this .node)
155: .getCharPositionInLine();
156: if (this .node instanceof CommonTree) {
157: this .token = ((CommonTree) this .node).token;
158: }
159: } else {
160: int type = adaptor.getType(this .node);
161: String text = adaptor.getText(this .node);
162: this .token = new CommonToken(type, text);
163: }
164: }
165:
166: /** Return the token type or char of the unexpected input element */
167: public int getUnexpectedType() {
168: if (input instanceof TokenStream) {
169: return token.getType();
170: } else if (input instanceof TreeNodeStream) {
171: TreeNodeStream nodes = (TreeNodeStream) input;
172: TreeAdaptor adaptor = nodes.getTreeAdaptor();
173: return adaptor.getType(node);
174: } else {
175: return c;
176: }
177: }
178: }
|