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{ 35 using Antlr.Runtime.Tree; 36 37 using ArgumentException = System.ArgumentException; 38 using ArgumentNullException = System.ArgumentNullException; 39 using Exception = System.Exception; 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>What is index of token/char were we looking at when the error occurred?</summary> */ 82 private int _index; 83 84 /** <summary> 85 * The current Token when an error occurred. Since not all streams 86 * can retrieve the ith Token, we have to track the Token object. 87 * For parsers. Even when it's a tree parser, token might be set. 88 * </summary> 89 */ 90 private IToken _token; 91 92 /** <summary> 93 * If this is a tree parser exception, node is set to the node with 94 * the problem. 95 * </summary> 96 */ 97 private object _node; 98 99 /** <summary>The current char when an error occurred. For lexers.</summary> */ 100 private int _c; 101 102 /** <summary> 103 * Track the line (1-based) at which the error occurred in case this is 104 * generated from a lexer. We need to track this since the 105 * unexpected char doesn't carry the line info. 106 * </summary> 107 */ 108 private int _line; 109 110 /// <summary> 111 /// The 0-based index into the line where the error occurred. 112 /// </summary> 113 private int _charPositionInLine; 114 115 /** <summary> 116 * If you are parsing a tree node stream, you will encounter som 117 * imaginary nodes w/o line/col info. We now search backwards looking 118 * for most recent token with line/col info, but notify getErrorHeader() 119 * that info is approximate. 120 * </summary> 121 */ 122 private bool _approximateLineInfo; 123 124 /** <summary>Used for remote debugger deserialization</summary> */ 125 public RecognitionException() 126 : this("A recognition error occurred.", null, null) 127 { 128 } 129 130 public RecognitionException( IIntStream input ) 131 : this("A recognition error occurred.", input, null) 132 { 133 } 134 135 public RecognitionException(string message) 136 : this(message, null, null) 137 { 138 } 139 140 public RecognitionException(string message, IIntStream input) 141 : this(message, input, null) 142 { 143 } 144 145 public RecognitionException(string message, Exception innerException) 146 : this(message, null, innerException) 147 { 148 } 149 150 public RecognitionException(string message, IIntStream input, Exception innerException) 151 : base(message, innerException) 152 { 153 this._input = input; 154 if (input != null) 155 { 156 this._index = input.Index; 157 if (input is ITokenStream) 158 { 159 this._token = ((ITokenStream)input).LT(1); 160 this._line = _token.Line; 161 this._charPositionInLine = _token.CharPositionInLine; 162 } 163 164 ITreeNodeStream tns = input as ITreeNodeStream; 165 if (tns != null) 166 { 167 ExtractInformationFromTreeNodeStream(tns); 168 } 169 else 170 { 171 ICharStream charStream = input as ICharStream; 172 if (charStream != null) 173 { 174 this._c = input.LA(1); 175 this._line = ((ICharStream)input).Line; 176 this._charPositionInLine = ((ICharStream)input).CharPositionInLine; 177 } 178 else 179 { 180 this._c = input.LA(1); 181 } 182 } 183 } 184 } 185 186 protected RecognitionException(SerializationInfo info, StreamingContext context) 187 : base(info, context) 188 { 189 if (info == null) 190 throw new ArgumentNullException("info"); 191 192 _index = info.GetInt32("Index"); 193 _c = info.GetInt32("C"); 194 _line = info.GetInt32("Line"); 195 _charPositionInLine = info.GetInt32("CharPositionInLine"); 196 _approximateLineInfo = info.GetBoolean("ApproximateLineInfo"); 197 } 198 199 /** <summary>Return the token type or char of the unexpected input element</summary> */ 200 public virtual int UnexpectedType 201 { 202 get 203 { 204 if ( _input is ITokenStream ) 205 { 206 return _token.Type; 207 } 208 209 ITreeNodeStream treeNodeStream = _input as ITreeNodeStream; 210 if ( treeNodeStream != null ) 211 { 212 ITreeAdaptor adaptor = treeNodeStream.TreeAdaptor; 213 return adaptor.GetType( _node ); 214 } 215 216 return _c; 217 } 218 } 219 220 public bool ApproximateLineInfo 221 { 222 get 223 { 224 return _approximateLineInfo; 225 } 226 protected set 227 { 228 _approximateLineInfo = value; 229 } 230 } 231 232 public IIntStream Input 233 { 234 get 235 { 236 return _input; 237 } 238 protected set 239 { 240 _input = value; 241 } 242 } 243 244 public IToken Token 245 { 246 get 247 { 248 return _token; 249 } 250 set 251 { 252 _token = value; 253 } 254 } 255 256 public object Node 257 { 258 get 259 { 260 return _node; 261 } 262 protected set 263 { 264 _node = value; 265 } 266 } 267 268 public int Character 269 { 270 get 271 { 272 return _c; 273 } 274 protected set 275 { 276 _c = value; 277 } 278 } 279 280 public int Index 281 { 282 get 283 { 284 return _index; 285 } 286 protected set 287 { 288 _index = value; 289 } 290 } 291 292 public int Line 293 { 294 get 295 { 296 return _line; 297 } 298 set 299 { 300 _line = value; 301 } 302 } 303 304 public int CharPositionInLine 305 { 306 get 307 { 308 return _charPositionInLine; 309 } 310 set 311 { 312 _charPositionInLine = value; 313 } 314 } 315 316 public override void GetObjectData(SerializationInfo info, StreamingContext context) 317 { 318 if (info == null) 319 throw new ArgumentNullException("info"); 320 321 base.GetObjectData(info, context); 322 info.AddValue("Index", _index); 323 info.AddValue("C", _c); 324 info.AddValue("Line", _line); 325 info.AddValue("CharPositionInLine", _charPositionInLine); 326 info.AddValue("ApproximateLineInfo", _approximateLineInfo); 327 } 328 329 protected virtual void ExtractInformationFromTreeNodeStream(ITreeNodeStream input) 330 { 331 this._node = input.LT(1); 332 ITokenStreamInformation streamInformation = input as ITokenStreamInformation; 333 if (streamInformation != null) 334 { 335 IToken lastToken = streamInformation.LastToken; 336 IToken lastRealToken = streamInformation.LastRealToken; 337 if (lastRealToken != null) 338 { 339 this._token = lastRealToken; 340 this._line = lastRealToken.Line; 341 this._charPositionInLine = lastRealToken.CharPositionInLine; 342 this._approximateLineInfo = lastRealToken.Equals(lastToken); 343 } 344 } 345 else 346 { 347 ITreeAdaptor adaptor = input.TreeAdaptor; 348 IToken payload = adaptor.GetToken(_node); 349 if (payload != null) 350 { 351 this._token = payload; 352 if (payload.Line <= 0) 353 { 354 // imaginary node; no line/pos info; scan backwards 355 int i = -1; 356 object priorNode = input.LT(i); 357 while (priorNode != null) 358 { 359 IToken priorPayload = adaptor.GetToken(priorNode); 360 if (priorPayload != null && priorPayload.Line > 0) 361 { 362 // we found the most recent real line / pos info 363 this._line = priorPayload.Line; 364 this._charPositionInLine = priorPayload.CharPositionInLine; 365 this._approximateLineInfo = true; 366 break; 367 } 368 --i; 369 try 370 { 371 priorNode = input.LT(i); 372 } 373 catch (ArgumentException) 374 { 375 priorNode = null; 376 } 377 } 378 } 379 else 380 { 381 // node created from real token 382 this._line = payload.Line; 383 this._charPositionInLine = payload.CharPositionInLine; 384 } 385 } 386 else if (this._node is Tree.ITree) 387 { 388 this._line = ((Tree.ITree)this._node).Line; 389 this._charPositionInLine = ((Tree.ITree)this._node).CharPositionInLine; 390 if (this._node is CommonTree) 391 { 392 this._token = ((CommonTree)this._node).Token; 393 } 394 } 395 else 396 { 397 int type = adaptor.GetType(this._node); 398 string text = adaptor.GetText(this._node); 399 this._token = new CommonToken(type, text); 400 } 401 } 402 } 403 } 404} 405