1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2005-2008 Terence Parr 4 * All rights reserved. 5 * 6 * Conversion to C#: 7 * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33namespace Antlr.Runtime { 34 using Antlr.Runtime.Tree; 35 36 using ArgumentNullException = System.ArgumentNullException; 37 using Exception = System.Exception; 38 using NonSerialized = System.NonSerializedAttribute; 39 using SerializationInfo = System.Runtime.Serialization.SerializationInfo; 40 using StreamingContext = System.Runtime.Serialization.StreamingContext; 41 42 /** <summary>The root of the ANTLR exception hierarchy.</summary> 43 * 44 * <remarks> 45 * To avoid English-only error messages and to generally make things 46 * as flexible as possible, these exceptions are not created with strings, 47 * but rather the information necessary to generate an error. Then 48 * the various reporting methods in Parser and Lexer can be overridden 49 * to generate a localized error message. For example, MismatchedToken 50 * exceptions are built with the expected token type. 51 * So, don't expect getMessage() to return anything. 52 * 53 * Note that as of Java 1.4, you can access the stack trace, which means 54 * that you can compute the complete trace of rules from the start symbol. 55 * This gives you considerable context information with which to generate 56 * useful error messages. 57 * 58 * ANTLR generates code that throws exceptions upon recognition error and 59 * also generates code to catch these exceptions in each rule. If you 60 * want to quit upon first error, you can turn off the automatic error 61 * handling mechanism using rulecatch action, but you still need to 62 * override methods mismatch and recoverFromMismatchSet. 63 * 64 * In general, the recognition exceptions can track where in a grammar a 65 * problem occurred and/or what was the expected input. While the parser 66 * knows its state (such as current input symbol and line info) that 67 * state can change before the exception is reported so current token index 68 * is computed and stored at exception time. From this info, you can 69 * perhaps print an entire line of input not just a single token, for example. 70 * Better to just say the recognizer had a problem and then let the parser 71 * figure out a fancy report. 72 * </remarks> 73 */ 74 [System.Serializable] 75 public class RecognitionException : Exception { 76 /** <summary>What input stream did the error occur in?</summary> */ 77 private IIntStream _input; 78 79 /** <summary>What is index of token/char were we looking at when the error occurred?</summary> */ 80 private int _index; 81 82 /** <summary> 83 * The current Token when an error occurred. Since not all streams 84 * can retrieve the ith Token, we have to track the Token object. 85 * For parsers. Even when it's a tree parser, token might be set. 86 * </summary> 87 */ 88 private IToken _token; 89 90 /** <summary> 91 * If this is a tree parser exception, node is set to the node with 92 * the problem. 93 * </summary> 94 */ 95 private object _node; 96 97 /** <summary>The current char when an error occurred. For lexers.</summary> */ 98 private int _c; 99 100 /** <summary> 101 * Track the line (1-based) at which the error occurred in case this is 102 * generated from a lexer. We need to track this since the 103 * unexpected char doesn't carry the line info. 104 * </summary> 105 */ 106 private int _line; 107 108 /// <summary> 109 /// The 0-based index into the line where the error occurred. 110 /// </summary> 111 private int _charPositionInLine; 112 113 /** <summary> 114 * If you are parsing a tree node stream, you will encounter som 115 * imaginary nodes w/o line/col info. We now search backwards looking 116 * for most recent token with line/col info, but notify getErrorHeader() 117 * that info is approximate. 118 * </summary> 119 */ 120 private bool _approximateLineInfo; 121 122 /** <summary>Used for remote debugger deserialization</summary> */ 123 public RecognitionException() 124 : this("A recognition error occurred.", null, null) { 125 } 126 127 public RecognitionException(IIntStream input) 128 : this("A recognition error occurred.", input, null) { 129 } 130 131 public RecognitionException(string message) 132 : this(message, null, null) { 133 } 134 135 public RecognitionException(string message, IIntStream input) 136 : this(message, input, null) { 137 } 138 139 public RecognitionException(string message, Exception innerException) 140 : this(message, null, innerException) { 141 } 142 143 public RecognitionException(string message, IIntStream input, Exception innerException) 144 : base(message, innerException) { 145 this._input = input; 146 if (input != null) { 147 this._index = input.Index; 148 if (input is ITokenStream) { 149 this._token = ((ITokenStream)input).LT(1); 150 this._line = _token.Line; 151 this._charPositionInLine = _token.CharPositionInLine; 152 } 153 if (input is ITreeNodeStream) { 154 ExtractInformationFromTreeNodeStream(input); 155 } else if (input is ICharStream) { 156 this._c = input.LA(1); 157 this._line = ((ICharStream)input).Line; 158 this._charPositionInLine = ((ICharStream)input).CharPositionInLine; 159 } else { 160 this._c = input.LA(1); 161 } 162 } 163 } 164 165 protected RecognitionException(SerializationInfo info, StreamingContext context) 166 : base(info, context) { 167 if (info == null) 168 throw new ArgumentNullException("info"); 169 170 _index = info.GetInt32("Index"); 171 _c = info.GetInt32("C"); 172 _line = info.GetInt32("Line"); 173 _charPositionInLine = info.GetInt32("CharPositionInLine"); 174 _approximateLineInfo = info.GetBoolean("ApproximateLineInfo"); 175 } 176 177 /** <summary>Return the token type or char of the unexpected input element</summary> */ 178 public virtual int UnexpectedType { 179 get { 180 if (_input is ITokenStream) { 181 return _token.Type; 182 } 183 184 ITreeNodeStream treeNodeStream = _input as ITreeNodeStream; 185 if (treeNodeStream != null) { 186 ITreeAdaptor adaptor = treeNodeStream.TreeAdaptor; 187 return adaptor.GetType(_node); 188 } 189 190 return _c; 191 } 192 } 193 194 public bool ApproximateLineInfo { 195 get { 196 return _approximateLineInfo; 197 } 198 protected set { 199 _approximateLineInfo = value; 200 } 201 } 202 203 public IIntStream Input { 204 get { 205 return _input; 206 } 207 protected set { 208 _input = value; 209 } 210 } 211 212 public IToken Token { 213 get { 214 return _token; 215 } 216 set { 217 _token = value; 218 } 219 } 220 221 public object Node { 222 get { 223 return _node; 224 } 225 protected set { 226 _node = value; 227 } 228 } 229 230 public int Character { 231 get { 232 return _c; 233 } 234 protected set { 235 _c = value; 236 } 237 } 238 239 public int Index { 240 get { 241 return _index; 242 } 243 protected set { 244 _index = value; 245 } 246 } 247 248 public int Line { 249 get { 250 return _line; 251 } 252 set { 253 _line = value; 254 } 255 } 256 257 public int CharPositionInLine { 258 get { 259 return _charPositionInLine; 260 } 261 set { 262 _charPositionInLine = value; 263 } 264 } 265 266 public override void GetObjectData(SerializationInfo info, StreamingContext context) { 267 if (info == null) 268 throw new ArgumentNullException("info"); 269 270 base.GetObjectData(info, context); 271 info.AddValue("Index", _index); 272 info.AddValue("C", _c); 273 info.AddValue("Line", _line); 274 info.AddValue("CharPositionInLine", _charPositionInLine); 275 info.AddValue("ApproximateLineInfo", _approximateLineInfo); 276 } 277 278 protected virtual void ExtractInformationFromTreeNodeStream(IIntStream input) { 279 ITokenStreamInformation streamInformation = input as ITokenStreamInformation; 280 if (streamInformation != null) { 281 IToken lastToken = streamInformation.LastToken; 282 IToken lastRealToken = streamInformation.LastRealToken; 283 if (lastRealToken != null) { 284 this._token = lastRealToken; 285 this._line = lastRealToken.Line; 286 this._charPositionInLine = lastRealToken.CharPositionInLine; 287 this._approximateLineInfo = lastRealToken.Equals(lastToken); 288 } 289 } else { 290 ITreeNodeStream nodes = (ITreeNodeStream)input; 291 this._node = nodes.LT(1); 292 ITreeAdaptor adaptor = nodes.TreeAdaptor; 293 IToken payload = adaptor.GetToken(_node); 294 if (payload != null) { 295 this._token = payload; 296 if (payload.Line <= 0) { 297 // imaginary node; no line/pos info; scan backwards 298 int i = -1; 299 object priorNode = nodes.LT(i); 300 while (priorNode != null) { 301 IToken priorPayload = adaptor.GetToken(priorNode); 302 if (priorPayload != null && priorPayload.Line > 0) { 303 // we found the most recent real line / pos info 304 this._line = priorPayload.Line; 305 this._charPositionInLine = priorPayload.CharPositionInLine; 306 this._approximateLineInfo = true; 307 break; 308 } 309 --i; 310 priorNode = nodes.LT(i); 311 } 312 } else { // node created from real token 313 this._line = payload.Line; 314 this._charPositionInLine = payload.CharPositionInLine; 315 } 316 } else if (this._node is Tree.ITree) { 317 this._line = ((Tree.ITree)this._node).Line; 318 this._charPositionInLine = ((Tree.ITree)this._node).CharPositionInLine; 319 if (this._node is CommonTree) { 320 this._token = ((CommonTree)this._node).Token; 321 } 322 } else { 323 int type = adaptor.GetType(this._node); 324 string text = adaptor.GetText(this._node); 325 this._token = new CommonToken(type, text); 326 } 327 } 328 } 329 } 330} 331