/* * [The "BSD licence"] * Copyright (c) 2005-2008 Terence Parr * All rights reserved. * * Conversion to C#: * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, 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: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ namespace Antlr.Runtime { using Antlr.Runtime.Tree; using ArgumentException = System.ArgumentException; using ArgumentNullException = System.ArgumentNullException; using Exception = System.Exception; using SerializationInfo = System.Runtime.Serialization.SerializationInfo; using StreamingContext = System.Runtime.Serialization.StreamingContext; /** The root of the ANTLR exception hierarchy. * * * To avoid English-only error messages and to generally make things * as flexible as possible, these exceptions are not created with strings, * but rather the information necessary to generate an error. Then * the various reporting methods in Parser and Lexer can be overridden * to generate a localized error message. For example, MismatchedToken * exceptions are built with the expected token type. * So, don't expect getMessage() to return anything. * * Note that as of Java 1.4, you can access the stack trace, which means * that you can compute the complete trace of rules from the start symbol. * This gives you considerable context information with which to generate * useful error messages. * * ANTLR generates code that throws exceptions upon recognition error and * also generates code to catch these exceptions in each rule. If you * want to quit upon first error, you can turn off the automatic error * handling mechanism using rulecatch action, but you still need to * override methods mismatch and recoverFromMismatchSet. * * In general, the recognition exceptions can track where in a grammar a * problem occurred and/or what was the expected input. While the parser * knows its state (such as current input symbol and line info) that * state can change before the exception is reported so current token index * is computed and stored at exception time. From this info, you can * perhaps print an entire line of input not just a single token, for example. * Better to just say the recognizer had a problem and then let the parser * figure out a fancy report. * */ [System.Serializable] public class RecognitionException : Exception { /** What input stream did the error occur in? */ private IIntStream _input; /** What is index of token/char were we looking at when the error occurred? */ private int _index; /** * The current Token when an error occurred. Since not all streams * can retrieve the ith Token, we have to track the Token object. * For parsers. Even when it's a tree parser, token might be set. * */ private IToken _token; /** * If this is a tree parser exception, node is set to the node with * the problem. * */ private object _node; /** The current char when an error occurred. For lexers. */ private int _c; /** * Track the line (1-based) at which the error occurred in case this is * generated from a lexer. We need to track this since the * unexpected char doesn't carry the line info. * */ private int _line; /// /// The 0-based index into the line where the error occurred. /// private int _charPositionInLine; /** * If you are parsing a tree node stream, you will encounter som * imaginary nodes w/o line/col info. We now search backwards looking * for most recent token with line/col info, but notify getErrorHeader() * that info is approximate. * */ private bool _approximateLineInfo; /** Used for remote debugger deserialization */ public RecognitionException() : this("A recognition error occurred.", null, null) { } public RecognitionException( IIntStream input ) : this("A recognition error occurred.", input, null) { } public RecognitionException(string message) : this(message, null, null) { } public RecognitionException(string message, IIntStream input) : this(message, input, null) { } public RecognitionException(string message, Exception innerException) : this(message, null, innerException) { } public RecognitionException(string message, IIntStream input, Exception innerException) : base(message, innerException) { this._input = input; if (input != null) { this._index = input.Index; if (input is ITokenStream) { this._token = ((ITokenStream)input).LT(1); this._line = _token.Line; this._charPositionInLine = _token.CharPositionInLine; } ITreeNodeStream tns = input as ITreeNodeStream; if (tns != null) { ExtractInformationFromTreeNodeStream(tns); } else { ICharStream charStream = input as ICharStream; if (charStream != null) { this._c = input.LA(1); this._line = ((ICharStream)input).Line; this._charPositionInLine = ((ICharStream)input).CharPositionInLine; } else { this._c = input.LA(1); } } } } protected RecognitionException(SerializationInfo info, StreamingContext context) : base(info, context) { if (info == null) throw new ArgumentNullException("info"); _index = info.GetInt32("Index"); _c = info.GetInt32("C"); _line = info.GetInt32("Line"); _charPositionInLine = info.GetInt32("CharPositionInLine"); _approximateLineInfo = info.GetBoolean("ApproximateLineInfo"); } /** Return the token type or char of the unexpected input element */ public virtual int UnexpectedType { get { if ( _input is ITokenStream ) { return _token.Type; } ITreeNodeStream treeNodeStream = _input as ITreeNodeStream; if ( treeNodeStream != null ) { ITreeAdaptor adaptor = treeNodeStream.TreeAdaptor; return adaptor.GetType( _node ); } return _c; } } public bool ApproximateLineInfo { get { return _approximateLineInfo; } protected set { _approximateLineInfo = value; } } public IIntStream Input { get { return _input; } protected set { _input = value; } } public IToken Token { get { return _token; } set { _token = value; } } public object Node { get { return _node; } protected set { _node = value; } } public int Character { get { return _c; } protected set { _c = value; } } public int Index { get { return _index; } protected set { _index = value; } } public int Line { get { return _line; } set { _line = value; } } public int CharPositionInLine { get { return _charPositionInLine; } set { _charPositionInLine = value; } } public override void GetObjectData(SerializationInfo info, StreamingContext context) { if (info == null) throw new ArgumentNullException("info"); base.GetObjectData(info, context); info.AddValue("Index", _index); info.AddValue("C", _c); info.AddValue("Line", _line); info.AddValue("CharPositionInLine", _charPositionInLine); info.AddValue("ApproximateLineInfo", _approximateLineInfo); } protected virtual void ExtractInformationFromTreeNodeStream(ITreeNodeStream input) { this._node = input.LT(1); ITokenStreamInformation streamInformation = input as ITokenStreamInformation; if (streamInformation != null) { IToken lastToken = streamInformation.LastToken; IToken lastRealToken = streamInformation.LastRealToken; if (lastRealToken != null) { this._token = lastRealToken; this._line = lastRealToken.Line; this._charPositionInLine = lastRealToken.CharPositionInLine; this._approximateLineInfo = lastRealToken.Equals(lastToken); } } else { ITreeAdaptor adaptor = input.TreeAdaptor; IToken payload = adaptor.GetToken(_node); if (payload != null) { this._token = payload; if (payload.Line <= 0) { // imaginary node; no line/pos info; scan backwards int i = -1; object priorNode = input.LT(i); while (priorNode != null) { IToken priorPayload = adaptor.GetToken(priorNode); if (priorPayload != null && priorPayload.Line > 0) { // we found the most recent real line / pos info this._line = priorPayload.Line; this._charPositionInLine = priorPayload.CharPositionInLine; this._approximateLineInfo = true; break; } --i; try { priorNode = input.LT(i); } catch (ArgumentException) { priorNode = null; } } } else { // node created from real token this._line = payload.Line; this._charPositionInLine = payload.CharPositionInLine; } } else if (this._node is Tree.ITree) { this._line = ((Tree.ITree)this._node).Line; this._charPositionInLine = ((Tree.ITree)this._node).CharPositionInLine; if (this._node is CommonTree) { this._token = ((CommonTree)this._node).Token; } } else { int type = adaptor.GetType(this._node); string text = adaptor.GetText(this._node); this._token = new CommonToken(type, text); } } } } }