1 /* 2 * [The "BSD license"] 3 * Copyright (c) 2011 Terence Parr 4 * All rights reserved. 5 * 6 * Conversion to C#: 7 * Copyright (c) 2011 Sam Harwell, Tunnel Vision Laboratories, LLC 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 33 namespace Antlr.Runtime 34 { 35 using Antlr.Runtime.Tree; 36 37 using ArgumentNullException = System.ArgumentNullException; 38 using Exception = System.Exception; 39 using NotSupportedException = System.NotSupportedException; 40 using SerializationInfo = System.Runtime.Serialization.SerializationInfo; 41 using StreamingContext = System.Runtime.Serialization.StreamingContext; 42 43 /** <summary>The root of the ANTLR exception hierarchy.</summary> 44 * 45 * <remarks> 46 * To avoid English-only error messages and to generally make things 47 * as flexible as possible, these exceptions are not created with strings, 48 * but rather the information necessary to generate an error. Then 49 * the various reporting methods in Parser and Lexer can be overridden 50 * to generate a localized error message. For example, MismatchedToken 51 * exceptions are built with the expected token type. 52 * So, don't expect getMessage() to return anything. 53 * 54 * Note that as of Java 1.4, you can access the stack trace, which means 55 * that you can compute the complete trace of rules from the start symbol. 56 * This gives you considerable context information with which to generate 57 * useful error messages. 58 * 59 * ANTLR generates code that throws exceptions upon recognition error and 60 * also generates code to catch these exceptions in each rule. If you 61 * want to quit upon first error, you can turn off the automatic error 62 * handling mechanism using rulecatch action, but you still need to 63 * override methods mismatch and recoverFromMismatchSet. 64 * 65 * In general, the recognition exceptions can track where in a grammar a 66 * problem occurred and/or what was the expected input. While the parser 67 * knows its state (such as current input symbol and line info) that 68 * state can change before the exception is reported so current token index 69 * is computed and stored at exception time. From this info, you can 70 * perhaps print an entire line of input not just a single token, for example. 71 * Better to just say the recognizer had a problem and then let the parser 72 * figure out a fancy report. 73 * </remarks> 74 */ 75 [System.Serializable] 76 public class RecognitionException : Exception 77 { 78 /** <summary>What input stream did the error occur in?</summary> */ 79 private IIntStream _input; 80 81 /// <summary> 82 /// What was the lookahead index when this exception was thrown? 83 /// </summary> 84 private int _k; 85 86 /** <summary>What is index of token/char were we looking at when the error occurred?</summary> */ 87 private int _index; 88 89 /** <summary> 90 * The current Token when an error occurred. Since not all streams 91 * can retrieve the ith Token, we have to track the Token object. 92 * For parsers. Even when it's a tree parser, token might be set. 93 * </summary> 94 */ 95 private IToken _token; 96 97 /** <summary> 98 * If this is a tree parser exception, node is set to the node with 99 * the problem. 100 * </summary> 101 */ 102 private object _node; 103 104 /** <summary>The current char when an error occurred. For lexers.</summary> */ 105 private int _c; 106 107 /** <summary> 108 * Track the line (1-based) at which the error occurred in case this is 109 * generated from a lexer. We need to track this since the 110 * unexpected char doesn't carry the line info. 111 * </summary> 112 */ 113 private int _line; 114 115 /// <summary> 116 /// The 0-based index into the line where the error occurred. 117 /// </summary> 118 private int _charPositionInLine; 119 120 /** <summary> 121 * If you are parsing a tree node stream, you will encounter som 122 * imaginary nodes w/o line/col info. We now search backwards looking 123 * for most recent token with line/col info, but notify getErrorHeader() 124 * that info is approximate. 125 * </summary> 126 */ 127 private bool _approximateLineInfo; 128 129 /** <summary>Used for remote debugger deserialization</summary> */ RecognitionException()130 public RecognitionException() 131 : this("A recognition error occurred.", null, null) 132 { 133 } 134 RecognitionException(IIntStream input)135 public RecognitionException(IIntStream input) 136 : this("A recognition error occurred.", input, 1, null) 137 { 138 } 139 RecognitionException(IIntStream input, int k)140 public RecognitionException(IIntStream input, int k) 141 : this("A recognition error occurred.", input, k, null) 142 { 143 } 144 RecognitionException(string message)145 public RecognitionException(string message) 146 : this(message, null, null) 147 { 148 } 149 RecognitionException(string message, IIntStream input)150 public RecognitionException(string message, IIntStream input) 151 : this(message, input, 1, null) 152 { 153 } 154 RecognitionException(string message, IIntStream input, int k)155 public RecognitionException(string message, IIntStream input, int k) 156 : this(message, input, k, null) 157 { 158 } 159 RecognitionException(string message, Exception innerException)160 public RecognitionException(string message, Exception innerException) 161 : this(message, null, innerException) 162 { 163 } 164 RecognitionException(string message, IIntStream input, Exception innerException)165 public RecognitionException(string message, IIntStream input, Exception innerException) 166 : this(message, input, 1, innerException) 167 { 168 } 169 RecognitionException(string message, IIntStream input, int k, Exception innerException)170 public RecognitionException(string message, IIntStream input, int k, Exception innerException) 171 : base(message, innerException) 172 { 173 this._input = input; 174 this._k = k; 175 if (input != null) 176 { 177 this._index = input.Index + k - 1; 178 if (input is ITokenStream) 179 { 180 this._token = ((ITokenStream)input).LT(k); 181 this._line = _token.Line; 182 this._charPositionInLine = _token.CharPositionInLine; 183 } 184 185 ITreeNodeStream tns = input as ITreeNodeStream; 186 if (tns != null) 187 { 188 ExtractInformationFromTreeNodeStream(tns, k); 189 } 190 else 191 { 192 ICharStream charStream = input as ICharStream; 193 if (charStream != null) 194 { 195 int mark = input.Mark(); 196 try 197 { 198 for (int i = 0; i < k - 1; i++) 199 input.Consume(); 200 201 this._c = input.LA(1); 202 this._line = ((ICharStream)input).Line; 203 this._charPositionInLine = ((ICharStream)input).CharPositionInLine; 204 } 205 finally 206 { 207 input.Rewind(mark); 208 } 209 } 210 else 211 { 212 this._c = input.LA(k); 213 } 214 } 215 } 216 } 217 RecognitionException(SerializationInfo info, StreamingContext context)218 protected RecognitionException(SerializationInfo info, StreamingContext context) 219 : base(info, context) 220 { 221 if (info == null) 222 throw new ArgumentNullException("info"); 223 224 _index = info.GetInt32("Index"); 225 _c = info.GetInt32("C"); 226 _line = info.GetInt32("Line"); 227 _charPositionInLine = info.GetInt32("CharPositionInLine"); 228 _approximateLineInfo = info.GetBoolean("ApproximateLineInfo"); 229 } 230 231 /** <summary>Return the token type or char of the unexpected input element</summary> */ 232 public virtual int UnexpectedType 233 { 234 get 235 { 236 if ( _input is ITokenStream ) 237 { 238 return _token.Type; 239 } 240 241 ITreeNodeStream treeNodeStream = _input as ITreeNodeStream; 242 if ( treeNodeStream != null ) 243 { 244 ITreeAdaptor adaptor = treeNodeStream.TreeAdaptor; 245 return adaptor.GetType( _node ); 246 } 247 248 return _c; 249 } 250 } 251 252 public bool ApproximateLineInfo 253 { 254 get 255 { 256 return _approximateLineInfo; 257 } 258 protected set 259 { 260 _approximateLineInfo = value; 261 } 262 } 263 264 public IIntStream Input 265 { 266 get 267 { 268 return _input; 269 } 270 protected set 271 { 272 _input = value; 273 } 274 } 275 276 public int Lookahead 277 { 278 get 279 { 280 return _k; 281 } 282 } 283 284 public IToken Token 285 { 286 get 287 { 288 return _token; 289 } 290 set 291 { 292 _token = value; 293 } 294 } 295 296 public object Node 297 { 298 get 299 { 300 return _node; 301 } 302 protected set 303 { 304 _node = value; 305 } 306 } 307 308 public int Character 309 { 310 get 311 { 312 return _c; 313 } 314 protected set 315 { 316 _c = value; 317 } 318 } 319 320 public int Index 321 { 322 get 323 { 324 return _index; 325 } 326 protected set 327 { 328 _index = value; 329 } 330 } 331 332 public int Line 333 { 334 get 335 { 336 return _line; 337 } 338 set 339 { 340 _line = value; 341 } 342 } 343 344 public int CharPositionInLine 345 { 346 get 347 { 348 return _charPositionInLine; 349 } 350 set 351 { 352 _charPositionInLine = value; 353 } 354 } 355 GetObjectData(SerializationInfo info, StreamingContext context)356 public override void GetObjectData(SerializationInfo info, StreamingContext context) 357 { 358 if (info == null) 359 throw new ArgumentNullException("info"); 360 361 base.GetObjectData(info, context); 362 info.AddValue("Index", _index); 363 info.AddValue("C", _c); 364 info.AddValue("Line", _line); 365 info.AddValue("CharPositionInLine", _charPositionInLine); 366 info.AddValue("ApproximateLineInfo", _approximateLineInfo); 367 } 368 ExtractInformationFromTreeNodeStream(ITreeNodeStream input)369 protected virtual void ExtractInformationFromTreeNodeStream(ITreeNodeStream input) 370 { 371 this._node = input.LT(1); 372 373 object positionNode = null; 374 IPositionTrackingStream positionTrackingStream = input as IPositionTrackingStream; 375 if (positionTrackingStream != null) 376 { 377 positionNode = positionTrackingStream.GetKnownPositionElement(false); 378 if (positionNode == null) 379 { 380 positionNode = positionTrackingStream.GetKnownPositionElement(true); 381 this._approximateLineInfo = positionNode != null; 382 } 383 } 384 385 ITokenStreamInformation streamInformation = input as ITokenStreamInformation; 386 if (streamInformation != null) 387 { 388 IToken lastToken = streamInformation.LastToken; 389 IToken lastRealToken = streamInformation.LastRealToken; 390 if (lastRealToken != null) 391 { 392 this._token = lastRealToken; 393 this._line = lastRealToken.Line; 394 this._charPositionInLine = lastRealToken.CharPositionInLine; 395 this._approximateLineInfo = lastRealToken.Equals(lastToken); 396 } 397 } 398 else 399 { 400 ITreeAdaptor adaptor = input.TreeAdaptor; 401 IToken payload = adaptor.GetToken(positionNode ?? _node); 402 if (payload != null) 403 { 404 this._token = payload; 405 if (payload.Line <= 0) 406 { 407 // imaginary node; no line/pos info; scan backwards 408 int i = -1; 409 object priorNode = input.LT(i); 410 while (priorNode != null) 411 { 412 IToken priorPayload = adaptor.GetToken(priorNode); 413 if (priorPayload != null && priorPayload.Line > 0) 414 { 415 // we found the most recent real line / pos info 416 this._line = priorPayload.Line; 417 this._charPositionInLine = priorPayload.CharPositionInLine; 418 this._approximateLineInfo = true; 419 break; 420 } 421 422 --i; 423 try 424 { 425 priorNode = input.LT(i); 426 } 427 catch (NotSupportedException) 428 { 429 priorNode = null; 430 } 431 } 432 } 433 else 434 { 435 // node created from real token 436 this._line = payload.Line; 437 this._charPositionInLine = payload.CharPositionInLine; 438 } 439 } 440 else if (this._node is Tree.ITree) 441 { 442 this._line = ((Tree.ITree)this._node).Line; 443 this._charPositionInLine = ((Tree.ITree)this._node).CharPositionInLine; 444 if (this._node is CommonTree) 445 { 446 this._token = ((CommonTree)this._node).Token; 447 } 448 } 449 else 450 { 451 int type = adaptor.GetType(this._node); 452 string text = adaptor.GetText(this._node); 453 this._token = new CommonToken(type, text); 454 } 455 } 456 } 457 ExtractInformationFromTreeNodeStream(ITreeNodeStream input, int k)458 protected virtual void ExtractInformationFromTreeNodeStream(ITreeNodeStream input, int k) 459 { 460 int mark = input.Mark(); 461 try 462 { 463 for (int i = 0; i < k - 1; i++) 464 input.Consume(); 465 466 ExtractInformationFromTreeNodeStream(input); 467 } 468 finally 469 { 470 input.Rewind(mark); 471 } 472 } 473 } 474 } 475