1unit Antlr.Runtime; 2(* 3[The "BSD licence"] 4Copyright (c) 2008 Erik van Bilsen 5Copyright (c) 2005-2007 Kunle Odutola 6All rights reserved. 7 8Redistribution and use in source and binary forms, with or without 9modification, are permitted provided that the following conditions 10are met: 111. Redistributions of source code MUST RETAIN the above copyright 12 notice, this list of conditions and the following disclaimer. 132. Redistributions in binary form MUST REPRODUCE the above copyright 14 notice, this list of conditions and the following disclaimer in 15 the documentation and/or other materials provided with the 16 distribution. 173. The name of the author may not be used to endorse or promote products 18 derived from this software without specific prior WRITTEN permission. 194. Unless explicitly state otherwise, any contribution intentionally 20 submitted for inclusion in this work to the copyright owner or licensor 21 shall be under the terms and conditions of this license, without any 22 additional terms or conditions. 23 24THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34*) 35 36interface 37 38{$IF CompilerVersion < 20} 39{$MESSAGE ERROR 'You need Delphi 2009 or higher to use the Antlr runtime'} 40{$IFEND} 41 42uses 43 SysUtils, 44 Classes, 45 Generics.Defaults, 46 Generics.Collections, 47 Antlr.Runtime.Tools, 48 Antlr.Runtime.Collections; 49 50type 51 TCharStreamConstants = (cscEOF = -1); 52 53type 54 ERecognitionException = class; 55 ENoViableAltException = class; 56 57 /// <summary> 58 /// A simple stream of integers. This is useful when all we care about is the char 59 /// or token type sequence (such as for interpretation). 60 /// </summary> 61 IIntStream = interface(IANTLRInterface) 62 ['{6B851BDB-DD9C-422B-AD1E-567E52D2654F}'] 63 { Property accessors } 64 function GetSourceName: String; 65 66 { Methods } 67 /// <summary> 68 /// Advances the read position of the stream. Updates line and column state 69 /// </summary> 70 procedure Consume; 71 72 /// <summary> 73 /// Get int at current input pointer + I ahead (where I=1 is next int) 74 /// Negative indexes are allowed. LA(-1) is previous token (token just matched). 75 /// LA(-i) where i is before first token should yield -1, invalid char or EOF. 76 /// </summary> 77 function LA(I: Integer): Integer; 78 function LAChar(I: Integer): Char; 79 80 /// <summary>Tell the stream to start buffering if it hasn't already.</summary> 81 /// <remarks> 82 /// Executing Rewind(Mark()) on a stream should not affect the input position. 83 /// The Lexer tracks line/col info as well as input index so its markers are 84 /// not pure input indexes. Same for tree node streams. */ 85 /// </remarks> 86 /// <returns>Return a marker that can be passed to 87 /// <see cref="IIntStream.Rewind(Integer)"/> to return to the current position. 88 /// This could be the current input position, a value return from 89 /// <see cref="IIntStream.Index"/>, or some other marker.</returns> 90 function Mark: Integer; 91 92 /// <summary> 93 /// Return the current input symbol index 0..N where N indicates the 94 /// last symbol has been read. The index is the symbol about to be 95 /// read not the most recently read symbol. 96 /// </summary> 97 function Index: Integer; 98 99 /// <summary> 100 /// Resets the stream so that the next call to 101 /// <see cref="IIntStream.Index"/> would return marker. 102 /// </summary> 103 /// <remarks> 104 /// The marker will usually be <see cref="IIntStream.Index"/> but 105 /// it doesn't have to be. It's just a marker to indicate what 106 /// state the stream was in. This is essentially calling 107 /// <see cref="IIntStream.Release"/> and <see cref="IIntStream.Seek"/>. 108 /// If there are other markers created after the specified marker, 109 /// this routine must unroll them like a stack. Assumes the state the 110 /// stream was in when this marker was created. 111 /// </remarks> 112 procedure Rewind(const Marker: Integer); overload; 113 114 /// <summary> 115 /// Rewind to the input position of the last marker. 116 /// </summary> 117 /// <remarks> 118 /// Used currently only after a cyclic DFA and just before starting 119 /// a sem/syn predicate to get the input position back to the start 120 /// of the decision. Do not "pop" the marker off the state. Mark(I) 121 /// and Rewind(I) should balance still. It is like invoking 122 /// Rewind(last marker) but it should not "pop" the marker off. 123 /// It's like Seek(last marker's input position). 124 /// </remarks> 125 procedure Rewind; overload; 126 127 /// <summary> 128 /// You may want to commit to a backtrack but don't want to force the 129 /// stream to keep bookkeeping objects around for a marker that is 130 /// no longer necessary. This will have the same behavior as 131 /// <see cref="IIntStream.Rewind(Integer)"/> except it releases resources without 132 /// the backward seek. 133 /// </summary> 134 /// <remarks> 135 /// This must throw away resources for all markers back to the marker 136 /// argument. So if you're nested 5 levels of Mark(), and then Release(2) 137 /// you have to release resources for depths 2..5. 138 /// </remarks> 139 procedure Release(const Marker: Integer); 140 141 /// <summary> 142 /// Set the input cursor to the position indicated by index. This is 143 /// normally used to seek ahead in the input stream. 144 /// </summary> 145 /// <remarks> 146 /// No buffering is required to do this unless you know your stream 147 /// will use seek to move backwards such as when backtracking. 148 /// 149 /// This is different from rewind in its multi-directional requirement 150 /// and in that its argument is strictly an input cursor (index). 151 /// 152 /// For char streams, seeking forward must update the stream state such 153 /// as line number. For seeking backwards, you will be presumably 154 /// backtracking using the 155 /// <see cref="IIntStream.Mark"/>/<see cref="IIntStream.Rewind(Integer)"/> 156 /// mechanism that restores state and so this method does not need to 157 /// update state when seeking backwards. 158 /// 159 /// Currently, this method is only used for efficient backtracking using 160 /// memoization, but in the future it may be used for incremental parsing. 161 /// 162 /// The index is 0..N-1. A seek to position i means that LA(1) will return 163 /// the ith symbol. So, seeking to 0 means LA(1) will return the first 164 /// element in the stream. 165 /// </remarks> 166 procedure Seek(const Index: Integer); 167 168 /// <summary>Returns the size of the entire stream.</summary> 169 /// <remarks> 170 /// Only makes sense for streams that buffer everything up probably, 171 /// but might be useful to display the entire stream or for testing. 172 /// This value includes a single EOF. 173 /// </remarks> 174 function Size: Integer; 175 176 { Properties } 177 178 /// <summary> 179 /// Where are you getting symbols from? Normally, implementations will 180 /// pass the buck all the way to the lexer who can ask its input stream 181 /// for the file name or whatever. 182 /// </summary> 183 property SourceName: String read GetSourceName; 184 end; 185 186 /// <summary>A source of characters for an ANTLR lexer </summary> 187 ICharStream = interface(IIntStream) 188 ['{C30EF0DB-F4BD-4CBC-8C8F-828DABB6FF36}'] 189 { Property accessors } 190 function GetLine: Integer; 191 procedure SetLine(const Value: Integer); 192 function GetCharPositionInLine: Integer; 193 procedure SetCharPositionInLine(const Value: Integer); 194 195 { Methods } 196 197 /// <summary> 198 /// Get the ith character of lookahead. This is usually the same as 199 /// LA(I). This will be used for labels in the generated lexer code. 200 /// I'd prefer to return a char here type-wise, but it's probably 201 /// better to be 32-bit clean and be consistent with LA. 202 /// </summary> 203 function LT(const I: Integer): Integer; 204 205 /// <summary> 206 /// This primarily a useful interface for action code (just make sure 207 /// actions don't use this on streams that don't support it). 208 /// For infinite streams, you don't need this. 209 /// </summary> 210 function Substring(const Start, Stop: Integer): String; 211 212 { Properties } 213 214 /// <summary> 215 /// The current line in the character stream (ANTLR tracks the 216 /// line information automatically. To support rewinding character 217 /// streams, we are able to [re-]set the line. 218 /// </summary> 219 property Line: Integer read GetLine write SetLine; 220 221 /// <summary> 222 /// The index of the character relative to the beginning of the 223 /// line (0..N-1). To support rewinding character streams, we are 224 /// able to [re-]set the character position. 225 /// </summary> 226 property CharPositionInLine: Integer read GetCharPositionInLine write SetCharPositionInLine; 227 end; 228 229 IToken = interface(IANTLRInterface) 230 ['{73BF129C-2F45-4C68-838E-BF5D3536AC6D}'] 231 { Property accessors } 232 function GetTokenType: Integer; 233 procedure SetTokenType(const Value: Integer); 234 function GetLine: Integer; 235 procedure SetLine(const Value: Integer); 236 function GetCharPositionInLine: Integer; 237 procedure SetCharPositionInLine(const Value: Integer); 238 function GetChannel: Integer; 239 procedure SetChannel(const Value: Integer); 240 function GetTokenIndex: Integer; 241 procedure SetTokenIndex(const Value: Integer); 242 function GetText: String; 243 procedure SetText(const Value: String); 244 245 { Properties } 246 property TokenType: Integer read GetTokenType write SetTokenType; 247 248 /// <summary>The line number on which this token was matched; line=1..N</summary> 249 property Line: Integer read GetLine write SetLine; 250 251 /// <summary> 252 /// The index of the first character relative to the beginning of the line 0..N-1 253 /// </summary> 254 property CharPositionInLine: Integer read GetCharPositionInLine write SetCharPositionInLine; 255 256 /// <summary>The line number on which this token was matched; line=1..N</summary> 257 property Channel: Integer read GetChannel write SetChannel; 258 259 /// <summary> 260 /// An index from 0..N-1 of the token object in the input stream 261 /// </summary> 262 /// <remarks> 263 /// This must be valid in order to use the ANTLRWorks debugger. 264 /// </remarks> 265 property TokenIndex: Integer read GetTokenIndex write SetTokenIndex; 266 267 /// <summary>The text of the token</summary> 268 /// <remarks> 269 /// When setting the text, it might be a NOP such as for the CommonToken, 270 /// which doesn't have string pointers, just indexes into a char buffer. 271 /// </remarks> 272 property Text: String read GetText write SetText; 273 end; 274 275 /// <summary> 276 /// A source of tokens must provide a sequence of tokens via NextToken() 277 /// and also must reveal it's source of characters; CommonToken's text is 278 /// computed from a CharStream; it only store indices into the char stream. 279 /// 280 /// Errors from the lexer are never passed to the parser. Either you want 281 /// to keep going or you do not upon token recognition error. If you do not 282 /// want to continue lexing then you do not want to continue parsing. Just 283 /// throw an exception not under RecognitionException and Delphi will naturally 284 /// toss you all the way out of the recognizers. If you want to continue 285 /// lexing then you should not throw an exception to the parser--it has already 286 /// requested a token. Keep lexing until you get a valid one. Just report 287 /// errors and keep going, looking for a valid token. 288 /// </summary> 289 ITokenSource = interface(IANTLRInterface) 290 ['{2C71FAD0-AEEE-417D-B576-4059F7C4CEB4}'] 291 { Property accessors } 292 function GetSourceName: String; 293 294 { Methods } 295 296 /// <summary> 297 /// Returns a Token object from the input stream (usually a CharStream). 298 /// Does not fail/return upon lexing error; just keeps chewing on the 299 /// characters until it gets a good one; errors are not passed through 300 /// to the parser. 301 /// </summary> 302 function NextToken: IToken; 303 304 { Properties } 305 306 /// <summary> 307 /// Where are you getting tokens from? normally the implication will simply 308 /// ask lexers input stream. 309 /// </summary> 310 property SourceName: String read GetSourceName; 311 end; 312 313 /// <summary>A stream of tokens accessing tokens from a TokenSource </summary> 314 ITokenStream = interface(IIntStream) 315 ['{59E5B39D-31A6-496D-9FA9-AC75CC584B68}'] 316 { Property accessors } 317 function GetTokenSource: ITokenSource; 318 procedure SetTokenSource(const Value: ITokenSource); 319 320 { Methods } 321 322 /// <summary> 323 /// Get Token at current input pointer + I ahead (where I=1 is next 324 /// Token). 325 /// I < 0 indicates tokens in the past. So -1 is previous token and -2 is 326 /// two tokens ago. LT(0) is undefined. For I>=N, return Token.EOFToken. 327 /// Return null for LT(0) and any index that results in an absolute address 328 /// that is negative. 329 /// </summary> 330 function LT(const K: Integer): IToken; 331 332 /// <summary> 333 /// Get a token at an absolute index I; 0..N-1. This is really only 334 /// needed for profiling and debugging and token stream rewriting. 335 /// If you don't want to buffer up tokens, then this method makes no 336 /// sense for you. Naturally you can't use the rewrite stream feature. 337 /// I believe DebugTokenStream can easily be altered to not use 338 /// this method, removing the dependency. 339 /// </summary> 340 function Get(const I: Integer): IToken; 341 342 /// <summary>Return the text of all tokens from start to stop, inclusive. 343 /// If the stream does not buffer all the tokens then it can just 344 /// return ''; Users should not access $ruleLabel.text in 345 /// an action of course in that case. 346 /// </summary> 347 function ToString(const Start, Stop: Integer): String; overload; 348 349 /// <summary>Because the user is not required to use a token with an index stored 350 /// in it, we must provide a means for two token objects themselves to 351 /// indicate the start/end location. Most often this will just delegate 352 /// to the other ToString(Integer,Integer). This is also parallel with 353 /// the TreeNodeStream.ToString(Object,Object). 354 /// </summary> 355 function ToString(const Start, Stop: IToken): String; overload; 356 357 { Properties } 358 property TokenSource: ITokenSource read GetTokenSource write SetTokenSource; 359 end; 360 361 /// <summary> 362 /// This is the complete state of a stream. 363 /// 364 /// When walking ahead with cyclic DFA for syntactic predicates, we 365 /// need to record the state of the input stream (char index, line, 366 /// etc...) so that we can rewind the state after scanning ahead. 367 /// </summary> 368 ICharStreamState = interface(IANTLRInterface) 369 ['{62D2A1CD-ED3A-4C95-A366-AB8F2E54060B}'] 370 { Property accessors } 371 function GetP: Integer; 372 procedure SetP(const Value: Integer); 373 function GetLine: Integer; 374 procedure SetLine(const Value: Integer); 375 function GetCharPositionInLine: Integer; 376 procedure SetCharPositionInLine(const Value: Integer); 377 378 { Properties } 379 /// <summary>Index into the char stream of next lookahead char </summary> 380 property P: Integer read GetP write SetP; 381 382 /// <summary>What line number is the scanner at before processing buffer[P]? </summary> 383 property Line: Integer read GetLine write SetLine; 384 385 /// <summary>What char position 0..N-1 in line is scanner before processing buffer[P]? </summary> 386 property CharPositionInLine: Integer read GetCharPositionInLine write SetCharPositionInLine; 387 end; 388 389 /// <summary> 390 /// A pretty quick <see cref="ICharStream"/> that uses a character array 391 /// directly as it's underlying source. 392 /// </summary> 393 IANTLRStringStream = interface(ICharStream) 394 ['{2FA24299-FF97-4AB6-8CA6-5D3DA13C4AB2}'] 395 { Methods } 396 397 /// <summary> 398 /// Resets the stream so that it is in the same state it was 399 /// when the object was created *except* the data array is not 400 /// touched. 401 /// </summary> 402 procedure Reset; 403 404 end; 405 406 /// <summary> 407 /// A character stream - an <see cref="ICharStream"/> - that loads 408 /// and caches the contents of it's underlying file fully during 409 /// object construction 410 /// </summary> 411 /// <remarks> 412 /// This looks very much like an ANTLReaderStream or an ANTLRInputStream 413 /// but, it is a special case. Since we know the exact size of the file to 414 /// load, we can avoid lots of data copying and buffer resizing. 415 /// </remarks> 416 IANTLRFileStream = interface(IANTLRStringStream) 417 ['{2B0145DB-2DAA-48A0-8316-B47A69EDDD1A}'] 418 { Methods } 419 420 /// <summary> 421 /// Loads and buffers the specified file to be used as this 422 /// ANTLRFileStream's source 423 /// </summary> 424 /// <param name="FileName">File to load</param> 425 /// <param name="Encoding">Encoding to apply to file</param> 426 procedure Load(const FileName: String; const Encoding: TEncoding); 427 end; 428 429 /// <summary> 430 /// A stripped-down version of org.antlr.misc.BitSet that is just 431 /// good enough to handle runtime requirements such as FOLLOW sets 432 /// for automatic error recovery. 433 /// </summary> 434 IBitSet = interface(IANTLRInterface) 435 ['{F2045045-FC46-4779-A65D-56C65D257A8E}'] 436 { Property accessors } 437 function GetIsNil: Boolean; 438 439 { Methods } 440 441 /// <summary>return "this or a" in a new set </summary> 442 function BitSetOr(const A: IBitSet): IBitSet; 443 444 /// <summary>Or this element into this set (grow as necessary to accommodate)</summary> 445 procedure Add(const El: Integer); 446 447 /// <summary> Grows the set to a larger number of bits.</summary> 448 /// <param name="bit">element that must fit in set 449 /// </param> 450 procedure GrowToInclude(const Bit: Integer); 451 452 procedure OrInPlace(const A: IBitSet); 453 function Size: Integer; 454 function Member(const El: Integer): Boolean; 455 456 // remove this element from this set 457 procedure Remove(const El: Integer); 458 459 function NumBits: Integer; 460 461 /// <summary>return how much space is being used by the bits array not 462 /// how many actually have member bits on. 463 /// </summary> 464 function LengthInLongWords: Integer; 465 466 function ToArray: TIntegerArray; 467 function ToPackedArray: TUInt64Array; 468 469 function ToString: String; overload; 470 function ToString(const TokenNames: TStringArray): String; overload; 471 function Equals(Obj: TObject): Boolean; 472 473 { Properties } 474 property IsNil: Boolean read GetIsNil; 475 end; 476 TBitSetArray = array of IBitSet; 477 478 /// <summary> 479 /// The set of fields needed by an abstract recognizer to recognize input 480 /// and recover from errors 481 /// </summary> 482 /// <remarks> 483 /// As a separate state object, it can be shared among multiple grammars; 484 /// e.g., when one grammar imports another. 485 /// These fields are publicly visible but the actual state pointer per 486 /// parser is protected. 487 /// </remarks> 488 IRecognizerSharedState = interface(IANTLRInterface) 489 ['{6CB6E17A-0B01-4AA7-8D49-5742A3CB8901}'] 490 { Property accessors } 491 function GetFollowing: TBitSetArray; 492 procedure SetFollowing(const Value: TBitSetArray); 493 function GetFollowingStackPointer: Integer; 494 procedure SetFollowingStackPointer(const Value: Integer); 495 function GetErrorRecovery: Boolean; 496 procedure SetErrorRecovery(const Value: Boolean); 497 function GetLastErrorIndex: Integer; 498 procedure SetLastErrorIndex(const Value: Integer); 499 function GetFailed: Boolean; 500 procedure SetFailed(const Value: Boolean); 501 function GetSyntaxErrors: Integer; 502 procedure SetSyntaxErrors(const Value: Integer); 503 function GetBacktracking: Integer; 504 procedure SetBacktracking(const Value: Integer); 505 function GetRuleMemo: TDictionaryArray<Integer, Integer>; 506 function GetRuleMemoCount: Integer; 507 procedure SetRuleMemoCount(const Value: Integer); 508 function GetToken: IToken; 509 procedure SetToken(const Value: IToken); 510 function GetTokenStartCharIndex: Integer; 511 procedure SetTokenStartCharIndex(const Value: Integer); 512 function GetTokenStartLine: Integer; 513 procedure SetTokenStartLine(const Value: Integer); 514 function GetTokenStartCharPositionInLine: Integer; 515 procedure SetTokenStartCharPositionInLine(const Value: Integer); 516 function GetChannel: Integer; 517 procedure SetChannel(const Value: Integer); 518 function GetTokenType: Integer; 519 procedure SetTokenType(const Value: Integer); 520 function GetText: String; 521 procedure SetText(const Value: String); 522 523 { Properties } 524 525 /// <summary> 526 /// Tracks the set of token types that can follow any rule invocation. 527 /// Stack grows upwards. When it hits the max, it grows 2x in size 528 /// and keeps going. 529 /// </summary> 530 property Following: TBitSetArray read GetFollowing write SetFollowing; 531 property FollowingStackPointer: Integer read GetFollowingStackPointer write SetFollowingStackPointer; 532 533 /// <summary> 534 /// This is true when we see an error and before having successfully 535 /// matched a token. Prevents generation of more than one error message 536 /// per error. 537 /// </summary> 538 property ErrorRecovery: Boolean read GetErrorRecovery write SetErrorRecovery; 539 540 /// <summary> 541 /// The index into the input stream where the last error occurred. 542 /// </summary> 543 /// <remarks> 544 /// This is used to prevent infinite loops where an error is found 545 /// but no token is consumed during recovery...another error is found, 546 /// ad naseum. This is a failsafe mechanism to guarantee that at least 547 /// one token/tree node is consumed for two errors. 548 /// </remarks> 549 property LastErrorIndex: Integer read GetLastErrorIndex write SetLastErrorIndex; 550 551 /// <summary> 552 /// In lieu of a return value, this indicates that a rule or token 553 /// has failed to match. Reset to false upon valid token match. 554 /// </summary> 555 property Failed: Boolean read GetFailed write SetFailed; 556 557 /// <summary> 558 /// Did the recognizer encounter a syntax error? Track how many. 559 /// </summary> 560 property SyntaxErrors: Integer read GetSyntaxErrors write SetSyntaxErrors; 561 562 /// <summary> 563 /// If 0, no backtracking is going on. Safe to exec actions etc... 564 /// If >0 then it's the level of backtracking. 565 /// </summary> 566 property Backtracking: Integer read GetBacktracking write SetBacktracking; 567 568 /// <summary> 569 /// An array[size num rules] of Map<Integer,Integer> that tracks 570 /// the stop token index for each rule. 571 /// </summary> 572 /// <remarks> 573 /// RuleMemo[RuleIndex] is the memoization table for RuleIndex. 574 /// For key RuleStartIndex, you get back the stop token for 575 /// associated rule or MEMO_RULE_FAILED. 576 /// 577 /// This is only used if rule memoization is on (which it is by default). 578 /// </remarks> 579 property RuleMemo: TDictionaryArray<Integer, Integer> read GetRuleMemo; 580 property RuleMemoCount: Integer read GetRuleMemoCount write SetRuleMemoCount; 581 582 // Lexer Specific Members 583 // LEXER FIELDS (must be in same state object to avoid casting 584 // constantly in generated code and Lexer object) :( 585 586 /// <summary> 587 /// Token object normally returned by NextToken() after matching lexer rules. 588 /// </summary> 589 /// <remarks> 590 /// The goal of all lexer rules/methods is to create a token object. 591 /// This is an instance variable as multiple rules may collaborate to 592 /// create a single token. NextToken will return this object after 593 /// matching lexer rule(s). If you subclass to allow multiple token 594 /// emissions, then set this to the last token to be matched or 595 /// something nonnull so that the auto token emit mechanism will not 596 /// emit another token. 597 /// </remarks> 598 property Token: IToken read GetToken write SetToken; 599 600 /// <summary> 601 /// What character index in the stream did the current token start at? 602 /// </summary> 603 /// <remarks> 604 /// Needed, for example, to get the text for current token. Set at 605 /// the start of nextToken. 606 /// </remarks> 607 property TokenStartCharIndex: Integer read GetTokenStartCharIndex write SetTokenStartCharIndex; 608 609 /// <summary> 610 /// The line on which the first character of the token resides 611 /// </summary> 612 property TokenStartLine: Integer read GetTokenStartLine write SetTokenStartLine; 613 614 /// <summary>The character position of first character within the line</summary> 615 property TokenStartCharPositionInLine: Integer read GetTokenStartCharPositionInLine write SetTokenStartCharPositionInLine; 616 617 /// <summary>The channel number for the current token</summary> 618 property Channel: Integer read GetChannel write SetChannel; 619 620 /// <summary>The token type for the current token</summary> 621 property TokenType: Integer read GetTokenType write SetTokenType; 622 623 /// <summary> 624 /// You can set the text for the current token to override what is in 625 /// the input char buffer. Use setText() or can set this instance var. 626 /// </summary> 627 property Text: String read GetText write SetText; 628 end; 629 630 ICommonToken = interface(IToken) 631 ['{06B1B0C3-2A0D-477A-AE30-414F51ACE8A0}'] 632 { Property accessors } 633 function GetStartIndex: Integer; 634 procedure SetStartIndex(const Value: Integer); 635 function GetStopIndex: Integer; 636 procedure SetStopIndex(const Value: Integer); 637 function GetInputStream: ICharStream; 638 procedure SetInputStream(const Value: ICharStream); 639 640 { Methods } 641 function ToString: String; 642 643 { Properties } 644 property StartIndex: Integer read GetStartIndex write SetStartIndex; 645 property StopIndex: Integer read GetStopIndex write SetStopIndex; 646 property InputStream: ICharStream read GetInputStream write SetInputStream; 647 end; 648 649 /// <summary> 650 /// A Token object like we'd use in ANTLR 2.x; has an actual string created 651 /// and associated with this object. These objects are needed for imaginary 652 /// tree nodes that have payload objects. We need to create a Token object 653 /// that has a string; the tree node will point at this token. CommonToken 654 /// has indexes into a char stream and hence cannot be used to introduce 655 /// new strings. 656 /// </summary> 657 IClassicToken = interface(IToken) 658 { Property accessors } 659 function GetTokenType: Integer; 660 procedure SetTokenType(const Value: Integer); 661 function GetLine: Integer; 662 procedure SetLine(const Value: Integer); 663 function GetCharPositionInLine: Integer; 664 procedure SetCharPositionInLine(const Value: Integer); 665 function GetChannel: Integer; 666 procedure SetChannel(const Value: Integer); 667 function GetTokenIndex: Integer; 668 procedure SetTokenIndex(const Value: Integer); 669 function GetText: String; 670 procedure SetText(const Value: String); 671 function GetInputStream: ICharStream; 672 procedure SetInputStream(const Value: ICharStream); 673 674 { Properties } 675 property TokenType: Integer read GetTokenType write SetTokenType; 676 property Line: Integer read GetLine write SetLine; 677 property CharPositionInLine: Integer read GetCharPositionInLine write SetCharPositionInLine; 678 property Channel: Integer read GetChannel write SetChannel; 679 property TokenIndex: Integer read GetTokenIndex write SetTokenIndex; 680 property Text: String read GetText write SetText; 681 property InputStream: ICharStream read GetInputStream write SetInputStream; 682 end; 683 684 /// <summary> 685 /// A generic recognizer that can handle recognizers generated from 686 /// lexer, parser, and tree grammars. This is all the parsing 687 /// support code essentially; most of it is error recovery stuff and 688 /// backtracking. 689 /// </summary> 690 IBaseRecognizer = interface(IANTLRObject) 691 ['{90813CE2-614B-4773-A26E-936E7DE7E9E9}'] 692 { Property accessors } 693 function GetInput: IIntStream; 694 function GetBacktrackingLevel: Integer; 695 function GetState: IRecognizerSharedState; 696 function GetNumberOfSyntaxErrors: Integer; 697 function GetGrammarFileName: String; 698 function GetSourceName: String; 699 function GetTokenNames: TStringArray; 700 701 { Methods } 702 procedure BeginBacktrack(const Level: Integer); 703 procedure EndBacktrack(const Level: Integer; const Successful: Boolean); 704 705 /// <summary>Reset the parser's state. Subclasses must rewind the input stream.</summary> 706 procedure Reset; 707 708 /// <summary> 709 /// Match current input symbol against ttype. Attempt 710 /// single token insertion or deletion error recovery. If 711 /// that fails, throw EMismatchedTokenException. 712 /// </summary> 713 /// <remarks> 714 /// To turn off single token insertion or deletion error 715 /// recovery, override MismatchRecover() and have it call 716 /// plain Mismatch(), which does not recover. Then any error 717 /// in a rule will cause an exception and immediate exit from 718 /// rule. Rule would recover by resynchronizing to the set of 719 /// symbols that can follow rule ref. 720 /// </remarks> 721 function Match(const Input: IIntStream; const TokenType: Integer; 722 const Follow: IBitSet): IANTLRInterface; 723 724 function MismatchIsUnwantedToken(const Input: IIntStream; 725 const TokenType: Integer): Boolean; 726 727 function MismatchIsMissingToken(const Input: IIntStream; 728 const Follow: IBitSet): Boolean; 729 730 /// <summary>A hook to listen in on the token consumption during error recovery. 731 /// The DebugParser subclasses this to fire events to the listenter. 732 /// </summary> 733 procedure BeginResync; 734 procedure EndResync; 735 736 /// <summary> 737 /// Report a recognition problem. 738 /// </summary> 739 /// <remarks> 740 /// This method sets errorRecovery to indicate the parser is recovering 741 /// not parsing. Once in recovery mode, no errors are generated. 742 /// To get out of recovery mode, the parser must successfully Match 743 /// a token (after a resync). So it will go: 744 /// 745 /// 1. error occurs 746 /// 2. enter recovery mode, report error 747 /// 3. consume until token found in resynch set 748 /// 4. try to resume parsing 749 /// 5. next Match() will reset errorRecovery mode 750 /// 751 /// If you override, make sure to update syntaxErrors if you care about that. 752 /// </remarks> 753 procedure ReportError(const E: ERecognitionException); 754 755 /// <summary> Match the wildcard: in a symbol</summary> 756 procedure MatchAny(const Input: IIntStream); 757 758 procedure DisplayRecognitionError(const TokenNames: TStringArray; 759 const E: ERecognitionException); 760 761 /// <summary> 762 /// What error message should be generated for the various exception types? 763 /// 764 /// Not very object-oriented code, but I like having all error message generation 765 /// within one method rather than spread among all of the exception classes. This 766 /// also makes it much easier for the exception handling because the exception 767 /// classes do not have to have pointers back to this object to access utility 768 /// routines and so on. Also, changing the message for an exception type would be 769 /// difficult because you would have to subclassing exception, but then somehow get 770 /// ANTLR to make those kinds of exception objects instead of the default. 771 /// 772 /// This looks weird, but trust me--it makes the most sense in terms of flexibility. 773 /// 774 /// For grammar debugging, you will want to override this to add more information 775 /// such as the stack frame with GetRuleInvocationStack(e, this.GetType().Fullname) 776 /// and, for no viable alts, the decision description and state etc... 777 /// 778 /// Override this to change the message generated for one or more exception types. 779 /// </summary> 780 function GetErrorMessage(const E: ERecognitionException; 781 const TokenNames: TStringArray): String; 782 783 /// <summary> 784 /// What is the error header, normally line/character position information? 785 /// </summary> 786 function GetErrorHeader(const E: ERecognitionException): String; 787 788 /// <summary> 789 /// How should a token be displayed in an error message? The default 790 /// is to display just the text, but during development you might 791 /// want to have a lot of information spit out. Override in that case 792 /// to use t.ToString() (which, for CommonToken, dumps everything about 793 /// the token). This is better than forcing you to override a method in 794 /// your token objects because you don't have to go modify your lexer 795 /// so that it creates a new type. 796 /// </summary> 797 function GetTokenErrorDisplay(const T: IToken): String; 798 799 /// <summary> 800 /// Override this method to change where error messages go 801 /// </summary> 802 procedure EmitErrorMessage(const Msg: String); 803 804 /// <summary> 805 /// Recover from an error found on the input stream. This is 806 /// for NoViableAlt and mismatched symbol exceptions. If you enable 807 /// single token insertion and deletion, this will usually not 808 /// handle mismatched symbol exceptions but there could be a mismatched 809 /// token that the Match() routine could not recover from. 810 /// </summary> 811 procedure Recover(const Input: IIntStream; const RE: ERecognitionException); 812 813 // Not currently used 814 function RecoverFromMismatchedSet(const Input: IIntStream; 815 const E: ERecognitionException; const Follow: IBitSet): IANTLRInterface; 816 817 procedure ConsumeUntil(const Input: IIntStream; const TokenType: Integer); overload; 818 819 /// <summary>Consume tokens until one matches the given token set </summary> 820 procedure ConsumeUntil(const Input: IIntStream; const BitSet: IBitSet); overload; 821 822 /// <summary> 823 /// Returns List <String> of the rules in your parser instance 824 /// leading up to a call to this method. You could override if 825 /// you want more details such as the file/line info of where 826 /// in the parser source code a rule is invoked. 827 /// </summary> 828 /// <remarks> 829 /// NOT IMPLEMENTED IN THE DELPHI VERSION YET 830 /// This is very useful for error messages and for context-sensitive 831 /// error recovery. 832 /// </remarks> 833 //function GetRuleInvocationStack: IList<IANTLRInterface>; overload; 834 835 /// <summary> 836 /// A more general version of GetRuleInvocationStack where you can 837 /// pass in, for example, a RecognitionException to get it's rule 838 /// stack trace. This routine is shared with all recognizers, hence, 839 /// static. 840 /// 841 /// TODO: move to a utility class or something; weird having lexer call this 842 /// </summary> 843 /// <remarks> 844 /// NOT IMPLEMENTED IN THE DELPHI VERSION YET 845 /// </remarks> 846 //function GetRuleInvocationStack(const E: Exception; 847 // const RecognizerClassName: String): IList<IANTLRInterface>; overload; 848 849 /// <summary>A convenience method for use most often with template rewrites. 850 /// Convert a List<Token> to List<String> 851 /// </summary> 852 function ToStrings(const Tokens: IList<IToken>): IList<String>; 853 854 /// <summary> 855 /// Given a rule number and a start token index number, return 856 /// MEMO_RULE_UNKNOWN if the rule has not parsed input starting from 857 /// start index. If this rule has parsed input starting from the 858 /// start index before, then return where the rule stopped parsing. 859 /// It returns the index of the last token matched by the rule. 860 /// </summary> 861 /// <remarks> 862 /// For now we use a hashtable and just the slow Object-based one. 863 /// Later, we can make a special one for ints and also one that 864 /// tosses out data after we commit past input position i. 865 /// </remarks> 866 function GetRuleMemoization(const RuleIndex, RuleStartIndex: Integer): Integer; 867 868 /// <summary> 869 /// Has this rule already parsed input at the current index in the 870 /// input stream? Return the stop token index or MEMO_RULE_UNKNOWN. 871 /// If we attempted but failed to parse properly before, return 872 /// MEMO_RULE_FAILED. 873 /// 874 /// This method has a side-effect: if we have seen this input for 875 /// this rule and successfully parsed before, then seek ahead to 876 /// 1 past the stop token matched for this rule last time. 877 /// </summary> 878 function AlreadyParsedRule(const Input: IIntStream; 879 const RuleIndex: Integer): Boolean; 880 881 /// <summary> 882 /// Record whether or not this rule parsed the input at this position 883 /// successfully. Use a standard hashtable for now. 884 /// </summary> 885 procedure Memoize(const Input: IIntStream; const RuleIndex, 886 RuleStartIndex: Integer); 887 888 /// <summary> 889 /// Return how many rule/input-index pairs there are in total. 890 /// TODO: this includes synpreds. :( 891 /// </summary> 892 /// <returns></returns> 893 function GetRuleMemoizationChaceSize: Integer; 894 895 procedure TraceIn(const RuleName: String; const RuleIndex: Integer; 896 const InputSymbol: String); 897 procedure TraceOut(const RuleName: String; const RuleIndex: Integer; 898 const InputSymbol: String); 899 900 { Properties } 901 property Input: IIntStream read GetInput; 902 property BacktrackingLevel: Integer read GetBacktrackingLevel; 903 property State: IRecognizerSharedState read GetState; 904 905 /// <summary> 906 /// Get number of recognition errors (lexer, parser, tree parser). Each 907 /// recognizer tracks its own number. So parser and lexer each have 908 /// separate count. Does not count the spurious errors found between 909 /// an error and next valid token match 910 /// 911 /// See also ReportError() 912 /// </summary> 913 property NumberOfSyntaxErrors: Integer read GetNumberOfSyntaxErrors; 914 915 /// <summary> 916 /// For debugging and other purposes, might want the grammar name. 917 /// Have ANTLR generate an implementation for this property. 918 /// </summary> 919 /// <returns></returns> 920 property GrammarFileName: String read GetGrammarFileName; 921 922 /// <summary> 923 /// For debugging and other purposes, might want the source name. 924 /// Have ANTLR provide a hook for this property. 925 /// </summary> 926 /// <returns>The source name</returns> 927 property SourceName: String read GetSourceName; 928 929 /// <summary> 930 /// Used to print out token names like ID during debugging and 931 /// error reporting. The generated parsers implement a method 932 /// that overrides this to point to their string[] tokenNames. 933 /// </summary> 934 property TokenNames: TStringArray read GetTokenNames; 935 end; 936 937 /// <summary> 938 /// The most common stream of tokens is one where every token is buffered up 939 /// and tokens are prefiltered for a certain channel (the parser will only 940 /// see these tokens and cannot change the filter channel number during the 941 /// parse). 942 /// 943 /// TODO: how to access the full token stream? How to track all tokens matched per rule? 944 /// </summary> 945 ICommonTokenStream = interface(ITokenStream) 946 { Methods } 947 948 /// <summary> 949 /// A simple filter mechanism whereby you can tell this token stream 950 /// to force all tokens of type TType to be on Channel. 951 /// </summary> 952 /// 953 /// <remarks> 954 /// For example, 955 /// when interpreting, we cannot exec actions so we need to tell 956 /// the stream to force all WS and NEWLINE to be a different, ignored 957 /// channel. 958 /// </remarks> 959 procedure SetTokenTypeChannel(const TType, Channel: Integer); 960 961 procedure DiscardTokenType(const TType: Integer); 962 963 procedure DiscardOffChannelTokens(const Discard: Boolean); 964 965 function GetTokens: IList<IToken>; overload; 966 function GetTokens(const Start, Stop: Integer): IList<IToken>; overload; 967 968 /// <summary>Given a start and stop index, return a List of all tokens in 969 /// the token type BitSet. Return null if no tokens were found. This 970 /// method looks at both on and off channel tokens. 971 /// </summary> 972 function GetTokens(const Start, Stop: Integer; 973 const Types: IBitSet): IList<IToken>; overload; 974 975 function GetTokens(const Start, Stop: Integer; 976 const Types: IList<Integer>): IList<IToken>; overload; 977 978 function GetTokens(const Start, Stop, 979 TokenType: Integer): IList<IToken>; overload; 980 981 procedure Reset; 982 end; 983 984 IDFA = interface; 985 986 TSpecialStateTransitionHandler = function(const DFA: IDFA; S: Integer; 987 const Input: IIntStream): Integer of Object; 988 989 /// <summary> 990 /// A DFA implemented as a set of transition tables. 991 /// </summary> 992 /// <remarks> 993 /// <para> 994 /// Any state that has a semantic predicate edge is special; those states are 995 /// generated with if-then-else structures in a SpecialStateTransition() 996 /// which is generated by cyclicDFA template. 997 /// </para> 998 /// <para> 999 /// There are at most 32767 states (16-bit signed short). Could get away with byte 1000 /// sometimes but would have to generate different types and the simulation code too. 1001 /// </para> 1002 /// <para> 1003 /// As a point of reference, the Tokens rule DFA for the lexer in the Java grammar 1004 /// sample has approximately 326 states. 1005 /// </para> 1006 /// </remarks> 1007 IDFA = interface(IANTLRInterface) 1008 ['{36312B59-B718-48EF-A0EC-4529DE70F4C2}'] 1009 { Property accessors } 1010 function GetSpecialStateTransitionHandler: TSpecialStateTransitionHandler; 1011 procedure SetSpecialStateTransitionHandler(const Value: TSpecialStateTransitionHandler); 1012 1013 { Methods } 1014 1015 /// <summary> 1016 /// From the input stream, predict what alternative will succeed using this 1017 /// DFA (representing the covering regular approximation to the underlying CFL). 1018 /// </summary> 1019 /// <param name="Input">Input stream</param> 1020 /// <returns>Return an alternative number 1..N. Throw an exception upon error.</returns> 1021 function Predict(const Input: IIntStream): Integer; 1022 1023 /// <summary> 1024 /// A hook for debugging interface 1025 /// </summary> 1026 /// <param name="NVAE"></param> 1027 procedure Error(const NVAE: ENoViableAltException); 1028 1029 function SpecialStateTransition(const S: Integer; const Input: IIntStream): Integer; 1030 1031 function Description: String; 1032 1033 function SpecialTransition(const State, Symbol: Integer): Integer; 1034 1035 { Properties } 1036 property SpecialStateTransitionHandler: TSpecialStateTransitionHandler read GetSpecialStateTransitionHandler write SetSpecialStateTransitionHandler; 1037 end; 1038 1039 /// <summary> 1040 /// A lexer is recognizer that draws input symbols from a character stream. 1041 /// lexer grammars result in a subclass of this object. A Lexer object 1042 /// uses simplified Match() and error recovery mechanisms in the interest 1043 /// of speed. 1044 /// </summary> 1045 ILexer = interface(IBaseRecognizer) 1046 ['{331AAB49-E7CD-40E7-AEF5-427F7D6577AD}'] 1047 { Property accessors } 1048 function GetCharStream: ICharStream; 1049 procedure SetCharStream(const Value: ICharStream); 1050 function GetLine: Integer; 1051 function GetCharPositionInLine: Integer; 1052 function GetCharIndex: Integer; 1053 function GetText: String; 1054 procedure SetText(const Value: String); 1055 1056 { Methods } 1057 1058 /// <summary> 1059 /// Return a token from this source; i.e., Match a token on the char stream. 1060 /// </summary> 1061 function NextToken: IToken; 1062 1063 /// <summary> 1064 /// Instruct the lexer to skip creating a token for current lexer rule and 1065 /// look for another token. NextToken() knows to keep looking when a lexer 1066 /// rule finishes with token set to SKIP_TOKEN. Recall that if token==null 1067 /// at end of any token rule, it creates one for you and emits it. 1068 /// </summary> 1069 procedure Skip; 1070 1071 /// <summary>This is the lexer entry point that sets instance var 'token' </summary> 1072 procedure DoTokens; 1073 1074 /// <summary> 1075 /// Currently does not support multiple emits per nextToken invocation 1076 /// for efficiency reasons. Subclass and override this method and 1077 /// NextToken (to push tokens into a list and pull from that list rather 1078 /// than a single variable as this implementation does). 1079 /// </summary> 1080 procedure Emit(const Token: IToken); overload; 1081 1082 /// <summary> 1083 /// The standard method called to automatically emit a token at the 1084 /// outermost lexical rule. The token object should point into the 1085 /// char buffer start..stop. If there is a text override in 'text', 1086 /// use that to set the token's text. 1087 /// </summary> 1088 /// <remarks><para>Override this method to emit custom Token objects.</para> 1089 /// <para>If you are building trees, then you should also override 1090 /// Parser or TreeParser.GetMissingSymbol().</para> 1091 ///</remarks> 1092 function Emit: IToken; overload; 1093 1094 procedure Match(const S: String); overload; 1095 procedure Match(const C: Integer); overload; 1096 procedure MatchAny; 1097 procedure MatchRange(const A, B: Integer); 1098 1099 /// <summary> 1100 /// Lexers can normally Match any char in it's vocabulary after matching 1101 /// a token, so do the easy thing and just kill a character and hope 1102 /// it all works out. You can instead use the rule invocation stack 1103 /// to do sophisticated error recovery if you are in a Fragment rule. 1104 /// </summary> 1105 procedure Recover(const RE: ERecognitionException); 1106 1107 function GetCharErrorDisplay(const C: Integer): String; 1108 1109 procedure TraceIn(const RuleName: String; const RuleIndex: Integer); 1110 procedure TraceOut(const RuleName: String; const RuleIndex: Integer); 1111 1112 { Properties } 1113 1114 /// <summary>Set the char stream and reset the lexer </summary> 1115 property CharStream: ICharStream read GetCharStream write SetCharStream; 1116 property Line: Integer read GetLine; 1117 property CharPositionInLine: Integer read GetCharPositionInLine; 1118 1119 /// <summary>What is the index of the current character of lookahead? </summary> 1120 property CharIndex: Integer read GetCharIndex; 1121 1122 /// <summary> 1123 /// Gets or sets the 'lexeme' for the current token. 1124 /// </summary> 1125 /// <remarks> 1126 /// <para> 1127 /// The getter returns the text matched so far for the current token or any 1128 /// text override. 1129 /// </para> 1130 /// <para> 1131 /// The setter sets the complete text of this token. It overrides/wipes any 1132 /// previous changes to the text. 1133 /// </para> 1134 /// </remarks> 1135 property Text: String read GetText write SetText; 1136 end; 1137 1138 /// <summary>A parser for TokenStreams. Parser grammars result in a subclass 1139 /// of this. 1140 /// </summary> 1141 IParser = interface(IBaseRecognizer) 1142 ['{7420879A-5D1F-43CA-BD49-2264D7514501}'] 1143 { Property accessors } 1144 function GetTokenStream: ITokenStream; 1145 procedure SetTokenStream(const Value: ITokenStream); 1146 1147 { Methods } 1148 procedure TraceIn(const RuleName: String; const RuleIndex: Integer); 1149 procedure TraceOut(const RuleName: String; const RuleIndex: Integer); 1150 1151 { Properties } 1152 1153 /// <summary>Set the token stream and reset the parser </summary> 1154 property TokenStream: ITokenStream read GetTokenStream write SetTokenStream; 1155 end; 1156 1157 /// <summary> 1158 /// Rules can return start/stop info as well as possible trees and templates 1159 /// </summary> 1160 IRuleReturnScope = interface(IANTLRInterface) 1161 ['{E9870056-BF6D-4CB2-B71C-10B80797C0B4}'] 1162 { Property accessors } 1163 function GetStart: IANTLRInterface; 1164 procedure SetStart(const Value: IANTLRInterface); 1165 function GetStop: IANTLRInterface; 1166 procedure SetStop(const Value: IANTLRInterface); 1167 function GetTree: IANTLRInterface; 1168 procedure SetTree(const Value: IANTLRInterface); 1169 function GetTemplate: IANTLRInterface; 1170 1171 { Properties } 1172 1173 /// <summary>Return the start token or tree </summary> 1174 property Start: IANTLRInterface read GetStart write SetStart; 1175 1176 /// <summary>Return the stop token or tree </summary> 1177 property Stop: IANTLRInterface read GetStop write SetStop; 1178 1179 /// <summary>Has a value potentially if output=AST; </summary> 1180 property Tree: IANTLRInterface read GetTree write SetTree; 1181 1182 /// <summary> 1183 /// Has a value potentially if output=template; 1184 /// Don't use StringTemplate type to avoid dependency on ST assembly 1185 /// </summary> 1186 property Template: IANTLRInterface read GetTemplate; 1187 end; 1188 1189 /// <summary> 1190 /// Rules that return more than a single value must return an object 1191 /// containing all the values. Besides the properties defined in 1192 /// RuleLabelScope.PredefinedRulePropertiesScope there may be user-defined 1193 /// return values. This class simply defines the minimum properties that 1194 /// are always defined and methods to access the others that might be 1195 /// available depending on output option such as template and tree. 1196 /// 1197 /// Note text is not an actual property of the return value, it is computed 1198 /// from start and stop using the input stream's ToString() method. I 1199 /// could add a ctor to this so that we can pass in and store the input 1200 /// stream, but I'm not sure we want to do that. It would seem to be undefined 1201 /// to get the .text property anyway if the rule matches tokens from multiple 1202 /// input streams. 1203 /// 1204 /// I do not use getters for fields of objects that are used simply to 1205 /// group values such as this aggregate. 1206 /// </summary> 1207 IParserRuleReturnScope = interface(IRuleReturnScope) 1208 ['{9FB62050-E23B-4FE4-87D5-2C1EE67AEC3E}'] 1209 end; 1210 1211 /// <summary>Useful for dumping out the input stream after doing some 1212 /// augmentation or other manipulations. 1213 /// </summary> 1214 /// 1215 /// <remarks> 1216 /// You can insert stuff, Replace, and delete chunks. Note that the 1217 /// operations are done lazily--only if you convert the buffer to a 1218 /// String. This is very efficient because you are not moving data around 1219 /// all the time. As the buffer of tokens is converted to strings, the 1220 /// ToString() method(s) check to see if there is an operation at the 1221 /// current index. If so, the operation is done and then normal String 1222 /// rendering continues on the buffer. This is like having multiple Turing 1223 /// machine instruction streams (programs) operating on a single input tape. :) 1224 /// 1225 /// Since the operations are done lazily at ToString-time, operations do not 1226 /// screw up the token index values. That is, an insert operation at token 1227 /// index I does not change the index values for tokens I+1..N-1. 1228 /// 1229 /// Because operations never actually alter the buffer, you may always get 1230 /// the original token stream back without undoing anything. Since 1231 /// the instructions are queued up, you can easily simulate transactions and 1232 /// roll back any changes if there is an error just by removing instructions. 1233 /// For example, 1234 /// 1235 /// var 1236 /// Input: ICharStream; 1237 /// Lex: ILexer; 1238 /// Tokens: ITokenRewriteStream; 1239 /// Parser: IParser; 1240 /// Input := TANTLRFileStream.Create('input'); 1241 /// Lex := TLexer.Create(Input); 1242 /// Tokens := TTokenRewriteStream.Create(Lex); 1243 /// Parser := TParser.Create(tokens); 1244 /// Parser.startRule(); 1245 /// 1246 /// Then in the rules, you can execute 1247 /// var 1248 /// t,u: IToken; 1249 /// ... 1250 /// Input.InsertAfter(t, 'text to put after t'); 1251 /// Input.InsertAfter(u, 'text after u'); 1252 /// WriteLn(Tokens.ToString()); 1253 /// 1254 /// Actually, you have to cast the 'input' to a TokenRewriteStream. :( 1255 /// 1256 /// You can also have multiple "instruction streams" and get multiple 1257 /// rewrites from a single pass over the input. Just name the instruction 1258 /// streams and use that name again when printing the buffer. This could be 1259 /// useful for generating a C file and also its header file--all from the 1260 /// same buffer: 1261 /// 1262 /// Tokens.InsertAfter('pass1', t, 'text to put after t'); 1263 /// Tokens.InsertAfter('pass2', u, 'text after u'); 1264 /// WriteLn(Tokens.ToString('pass1')); 1265 /// WriteLn(Tokens.ToString('pass2')); 1266 /// 1267 /// If you don't use named rewrite streams, a "default" stream is used as 1268 /// the first example shows. 1269 /// </remarks> 1270 ITokenRewriteStream = interface(ICommonTokenStream) 1271 ['{7B49CBB6-9395-4781-B616-F201889EEA13}'] 1272 { Methods } 1273 procedure Rollback(const InstructionIndex: Integer); overload; 1274 1275 /// <summary>Rollback the instruction stream for a program so that 1276 /// the indicated instruction (via instructionIndex) is no 1277 /// longer in the stream. UNTESTED! 1278 /// </summary> 1279 procedure Rollback(const ProgramName: String; 1280 const InstructionIndex: Integer); overload; 1281 1282 procedure DeleteProgram; overload; 1283 1284 /// <summary>Reset the program so that no instructions exist </summary> 1285 procedure DeleteProgram(const ProgramName: String); overload; 1286 1287 procedure InsertAfter(const T: IToken; const Text: IANTLRInterface); overload; 1288 procedure InsertAfter(const Index: Integer; const Text: IANTLRInterface); overload; 1289 procedure InsertAfter(const ProgramName: String; const T: IToken; 1290 const Text: IANTLRInterface); overload; 1291 procedure InsertAfter(const ProgramName: String; const Index: Integer; 1292 const Text: IANTLRInterface); overload; 1293 procedure InsertAfter(const T: IToken; const Text: String); overload; 1294 procedure InsertAfter(const Index: Integer; const Text: String); overload; 1295 procedure InsertAfter(const ProgramName: String; const T: IToken; 1296 const Text: String); overload; 1297 procedure InsertAfter(const ProgramName: String; const Index: Integer; 1298 const Text: String); overload; 1299 1300 procedure InsertBefore(const T: IToken; const Text: IANTLRInterface); overload; 1301 procedure InsertBefore(const Index: Integer; const Text: IANTLRInterface); overload; 1302 procedure InsertBefore(const ProgramName: String; const T: IToken; 1303 const Text: IANTLRInterface); overload; 1304 procedure InsertBefore(const ProgramName: String; const Index: Integer; 1305 const Text: IANTLRInterface); overload; 1306 procedure InsertBefore(const T: IToken; const Text: String); overload; 1307 procedure InsertBefore(const Index: Integer; const Text: String); overload; 1308 procedure InsertBefore(const ProgramName: String; const T: IToken; 1309 const Text: String); overload; 1310 procedure InsertBefore(const ProgramName: String; const Index: Integer; 1311 const Text: String); overload; 1312 1313 procedure Replace(const Index: Integer; const Text: IANTLRInterface); overload; 1314 procedure Replace(const Start, Stop: Integer; const Text: IANTLRInterface); overload; 1315 procedure Replace(const IndexT: IToken; const Text: IANTLRInterface); overload; 1316 procedure Replace(const Start, Stop: IToken; const Text: IANTLRInterface); overload; 1317 procedure Replace(const ProgramName: String; const Start, Stop: Integer; 1318 const Text: IANTLRInterface); overload; 1319 procedure Replace(const ProgramName: String; const Start, Stop: IToken; 1320 const Text: IANTLRInterface); overload; 1321 procedure Replace(const Index: Integer; const Text: String); overload; 1322 procedure Replace(const Start, Stop: Integer; const Text: String); overload; 1323 procedure Replace(const IndexT: IToken; const Text: String); overload; 1324 procedure Replace(const Start, Stop: IToken; const Text: String); overload; 1325 procedure Replace(const ProgramName: String; const Start, Stop: Integer; 1326 const Text: String); overload; 1327 procedure Replace(const ProgramName: String; const Start, Stop: IToken; 1328 const Text: String); overload; 1329 1330 procedure Delete(const Index: Integer); overload; 1331 procedure Delete(const Start, Stop: Integer); overload; 1332 procedure Delete(const IndexT: IToken); overload; 1333 procedure Delete(const Start, Stop: IToken); overload; 1334 procedure Delete(const ProgramName: String; const Start, Stop: Integer); overload; 1335 procedure Delete(const ProgramName: String; const Start, Stop: IToken); overload; 1336 1337 function GetLastRewriteTokenIndex: Integer; 1338 1339 function ToOriginalString: String; overload; 1340 function ToOriginalString(const Start, Stop: Integer): String; overload; 1341 1342 function ToString(const ProgramName: String): String; overload; 1343 function ToString(const ProgramName: String; 1344 const Start, Stop: Integer): String; overload; 1345 1346 function ToDebugString: String; overload; 1347 function ToDebugString(const Start, Stop: Integer): String; overload; 1348 end; 1349 1350 /// <summary>The root of the ANTLR exception hierarchy.</summary> 1351 /// <remarks> 1352 /// To avoid English-only error messages and to generally make things 1353 /// as flexible as possible, these exceptions are not created with strings, 1354 /// but rather the information necessary to generate an error. Then 1355 /// the various reporting methods in Parser and Lexer can be overridden 1356 /// to generate a localized error message. For example, MismatchedToken 1357 /// exceptions are built with the expected token type. 1358 /// So, don't expect getMessage() to return anything. 1359 /// 1360 /// You can access the stack trace, which means that you can compute the 1361 /// complete trace of rules from the start symbol. This gives you considerable 1362 /// context information with which to generate useful error messages. 1363 /// 1364 /// ANTLR generates code that throws exceptions upon recognition error and 1365 /// also generates code to catch these exceptions in each rule. If you 1366 /// want to quit upon first error, you can turn off the automatic error 1367 /// handling mechanism using rulecatch action, but you still need to 1368 /// override methods mismatch and recoverFromMismatchSet. 1369 /// 1370 /// In general, the recognition exceptions can track where in a grammar a 1371 /// problem occurred and/or what was the expected input. While the parser 1372 /// knows its state (such as current input symbol and line info) that 1373 /// state can change before the exception is reported so current token index 1374 /// is computed and stored at exception time. From this info, you can 1375 /// perhaps print an entire line of input not just a single token, for example. 1376 /// Better to just say the recognizer had a problem and then let the parser 1377 /// figure out a fancy report. 1378 /// </remarks> 1379 ERecognitionException = class(Exception) 1380 strict private 1381 FApproximateLineInfo: Boolean; 1382 strict protected 1383 /// <summary>What input stream did the error occur in? </summary> 1384 FInput: IIntStream; 1385 1386 /// <summary> 1387 /// What is index of token/char were we looking at when the error occurred? 1388 /// </summary> 1389 FIndex: Integer; 1390 1391 /// <summary> 1392 /// The current Token when an error occurred. Since not all streams 1393 /// can retrieve the ith Token, we have to track the Token object. 1394 /// </summary> 1395 FToken: IToken; 1396 1397 /// <summary>[Tree parser] Node with the problem.</summary> 1398 FNode: IANTLRInterface; 1399 1400 /// <summary>The current char when an error occurred. For lexers. </summary> 1401 FC: Integer; 1402 1403 /// <summary>Track the line at which the error occurred in case this is 1404 /// generated from a lexer. We need to track this since the 1405 /// unexpected char doesn't carry the line info. 1406 /// </summary> 1407 FLine: Integer; 1408 FCharPositionInLine: Integer; 1409 strict protected 1410 procedure ExtractInformationFromTreeNodeStream(const Input: IIntStream); 1411 function GetUnexpectedType: Integer; virtual; 1412 public 1413 /// <summary>Used for remote debugger deserialization </summary> 1414 constructor Create; overload; 1415 constructor Create(const AMessage: String); overload; 1416 constructor Create(const AInput: IIntStream); overload; 1417 constructor Create(const AMessage: String; const AInput: IIntStream); overload; 1418 1419 /// <summary> 1420 /// If you are parsing a tree node stream, you will encounter some 1421 /// imaginary nodes w/o line/col info. We now search backwards looking 1422 /// for most recent token with line/col info, but notify getErrorHeader() 1423 /// that info is approximate. 1424 /// </summary> 1425 property ApproximateLineInfo: Boolean read FApproximateLineInfo write FApproximateLineInfo; 1426 1427 /// <summary> 1428 /// Returns the current Token when the error occurred (for parsers 1429 /// although a tree parser might also set the token) 1430 /// </summary> 1431 property Token: IToken read FToken write FToken; 1432 1433 /// <summary> 1434 /// Returns the [tree parser] node where the error occured (for tree parsers). 1435 /// </summary> 1436 property Node: IANTLRInterface read FNode write FNode; 1437 1438 /// <summary> 1439 /// Returns the line at which the error occurred (for lexers) 1440 /// </summary> 1441 property Line: Integer read FLine write FLine; 1442 1443 /// <summary> 1444 /// Returns the character position in the line when the error 1445 /// occurred (for lexers) 1446 /// </summary> 1447 property CharPositionInLine: Integer read FCharPositionInLine write FCharPositionInLine; 1448 1449 /// <summary>Returns the input stream in which the error occurred</summary> 1450 property Input: IIntStream read FInput write FInput; 1451 1452 /// <summary> 1453 /// Returns the token type or char of the unexpected input element 1454 /// </summary> 1455 property UnexpectedType: Integer read GetUnexpectedType; 1456 1457 /// <summary> 1458 /// Returns the current char when the error occurred (for lexers) 1459 /// </summary> 1460 property Character: Integer read FC write FC; 1461 1462 /// <summary> 1463 /// Returns the token/char index in the stream when the error occurred 1464 /// </summary> 1465 property Index: Integer read FIndex write FIndex; 1466 end; 1467 1468 /// <summary> 1469 /// A mismatched char or Token or tree node. 1470 /// </summary> 1471 EMismatchedTokenException = class(ERecognitionException) 1472 strict private 1473 FExpecting: Integer; 1474 public 1475 constructor Create(const AExpecting: Integer; const AInput: IIntStream); 1476 1477 function ToString: String; override; 1478 1479 property Expecting: Integer read FExpecting write FExpecting; 1480 end; 1481 1482 EUnwantedTokenException = class(EMismatchedTokenException) 1483 strict private 1484 function GetUnexpectedToken: IToken; 1485 public 1486 property UnexpectedToken: IToken read GetUnexpectedToken; 1487 1488 function ToString: String; override; 1489 end; 1490 1491 /// <summary> 1492 /// We were expecting a token but it's not found. The current token 1493 /// is actually what we wanted next. Used for tree node errors too. 1494 /// </summary> 1495 EMissingTokenException = class(EMismatchedTokenException) 1496 strict private 1497 FInserted: IANTLRInterface; 1498 function GetMissingType: Integer; 1499 public 1500 constructor Create(const AExpecting: Integer; const AInput: IIntStream; 1501 const AInserted: IANTLRInterface); 1502 1503 function ToString: String; override; 1504 1505 property MissingType: Integer read GetMissingType; 1506 property Inserted: IANTLRInterface read FInserted write FInserted; 1507 end; 1508 1509 EMismatchedTreeNodeException = class(ERecognitionException) 1510 strict private 1511 FExpecting: Integer; 1512 public 1513 constructor Create(const AExpecting: Integer; const AInput: IIntStream); 1514 1515 function ToString: String; override; 1516 1517 property Expecting: Integer read FExpecting write FExpecting; 1518 end; 1519 1520 ENoViableAltException = class(ERecognitionException) 1521 strict private 1522 FGrammarDecisionDescription: String; 1523 FDecisionNumber: Integer; 1524 FStateNumber: Integer; 1525 public 1526 constructor Create(const AGrammarDecisionDescription: String; 1527 const ADecisionNumber, AStateNumber: Integer; const AInput: IIntStream); 1528 1529 function ToString: String; override; 1530 1531 property GrammarDecisionDescription: String read FGrammarDecisionDescription; 1532 property DecisionNumber: Integer read FDecisionNumber; 1533 property StateNumber: Integer read FStateNumber; 1534 end; 1535 1536 EEarlyExitException = class(ERecognitionException) 1537 strict private 1538 FDecisionNumber: Integer; 1539 public 1540 constructor Create(const ADecisionNumber: Integer; const AInput: IIntStream); 1541 1542 property DecisionNumber: Integer read FDecisionNumber; 1543 end; 1544 1545 EMismatchedSetException = class(ERecognitionException) 1546 strict private 1547 FExpecting: IBitSet; 1548 public 1549 constructor Create(const AExpecting: IBitSet; const AInput: IIntStream); 1550 1551 function ToString: String; override; 1552 1553 property Expecting: IBitSet read FExpecting write FExpecting; 1554 end; 1555 1556 EMismatchedNotSetException = class(EMismatchedSetException) 1557 1558 public 1559 function ToString: String; override; 1560 end; 1561 1562 EFailedPredicateException = class(ERecognitionException) 1563 strict private 1564 FRuleName: String; 1565 FPredicateText: String; 1566 public 1567 constructor Create(const AInput: IIntStream; const ARuleName, 1568 APredicateText: String); 1569 1570 function ToString: String; override; 1571 1572 property RuleName: String read FRuleName write FRuleName; 1573 property PredicateText: String read FPredicateText write FPredicateText; 1574 end; 1575 1576 EMismatchedRangeException = class(ERecognitionException) 1577 strict private 1578 FA: Integer; 1579 FB: Integer; 1580 public 1581 constructor Create(const AA, AB: Integer; const AInput: IIntStream); 1582 1583 function ToString: String; override; 1584 1585 property A: Integer read FA write FA; 1586 property B: Integer read FB write FB; 1587 end; 1588 1589type 1590 TCharStreamState = class(TANTLRObject, ICharStreamState) 1591 strict private 1592 FP: Integer; 1593 FLine: Integer; 1594 FCharPositionInLine: Integer; 1595 protected 1596 { ICharStreamState } 1597 function GetP: Integer; 1598 procedure SetP(const Value: Integer); 1599 function GetLine: Integer; 1600 procedure SetLine(const Value: Integer); 1601 function GetCharPositionInLine: Integer; 1602 procedure SetCharPositionInLine(const Value: Integer); 1603 end; 1604 1605type 1606 TANTLRStringStream = class(TANTLRObject, IANTLRStringStream, ICharStream) 1607 private 1608 FData: PChar; 1609 FOwnsData: Boolean; 1610 1611 /// <summary>How many characters are actually in the buffer?</summary> 1612 FN: Integer; 1613 1614 /// <summary>Current line number within the input (1..n )</summary> 1615 FLine: Integer; 1616 1617 /// <summary>Index in our array for the next char (0..n-1)</summary> 1618 FP: Integer; 1619 1620 /// <summary> 1621 /// The index of the character relative to the beginning of the 1622 /// line (0..n-1) 1623 /// </summary> 1624 FCharPositionInLine: Integer; 1625 1626 /// <summary> 1627 /// Tracks the depth of nested <see cref="IIntStream.Mark"/> calls 1628 /// </summary> 1629 FMarkDepth: Integer; 1630 1631 /// <summary> 1632 /// A list of CharStreamState objects that tracks the stream state 1633 /// (i.e. line, charPositionInLine, and p) that can change as you 1634 /// move through the input stream. Indexed from 1..markDepth. 1635 /// A null is kept @ index 0. Create upon first call to Mark(). 1636 /// </summary> 1637 FMarkers: IList<ICharStreamState>; 1638 1639 /// <summary> 1640 /// Track the last Mark() call result value for use in Rewind(). 1641 /// </summary> 1642 FLastMarker: Integer; 1643 /// <summary> 1644 /// What is name or source of this char stream? 1645 /// </summary> 1646 FName: String; 1647 protected 1648 { IIntStream } 1649 function GetSourceName: String; virtual; 1650 1651 procedure Consume; virtual; 1652 function LA(I: Integer): Integer; virtual; 1653 function LAChar(I: Integer): Char; 1654 function Index: Integer; 1655 function Size: Integer; 1656 function Mark: Integer; virtual; 1657 procedure Rewind(const Marker: Integer); overload; virtual; 1658 procedure Rewind; overload; virtual; 1659 procedure Release(const Marker: Integer); virtual; 1660 procedure Seek(const Index: Integer); virtual; 1661 1662 property SourceName: String read GetSourceName write FName; 1663 protected 1664 { ICharStream } 1665 function GetLine: Integer; virtual; 1666 procedure SetLine(const Value: Integer); virtual; 1667 function GetCharPositionInLine: Integer; virtual; 1668 procedure SetCharPositionInLine(const Value: Integer); virtual; 1669 function LT(const I: Integer): Integer; virtual; 1670 function Substring(const Start, Stop: Integer): String; virtual; 1671 protected 1672 { IANTLRStringStream } 1673 procedure Reset; virtual; 1674 public 1675 constructor Create; overload; 1676 1677 /// <summary> 1678 /// Initializes a new instance of the ANTLRStringStream class for the 1679 /// specified string. This copies data from the string to a local 1680 /// character array 1681 /// </summary> 1682 constructor Create(const AInput: String); overload; 1683 1684 /// <summary> 1685 /// Initializes a new instance of the ANTLRStringStream class for the 1686 /// specified character array. This is the preferred constructor as 1687 /// no data is copied 1688 /// </summary> 1689 constructor Create(const AData: PChar; 1690 const ANumberOfActualCharsInArray: Integer); overload; 1691 1692 destructor Destroy; override; 1693 end; 1694 1695 TANTLRFileStream = class(TANTLRStringStream, IANTLRFileStream) 1696 strict private 1697 /// <summary>Fully qualified name of the stream's underlying file</summary> 1698 FFileName: String; 1699 protected 1700 { IIntStream } 1701 function GetSourceName: String; override; 1702 protected 1703 { IANTLRFileStream } 1704 1705 procedure Load(const FileName: String; const Encoding: TEncoding); virtual; 1706 public 1707 /// <summary> 1708 /// Initializes a new instance of the ANTLRFileStream class for the 1709 /// specified file name 1710 /// </summary> 1711 constructor Create(const AFileName: String); overload; 1712 1713 /// <summary> 1714 /// Initializes a new instance of the ANTLRFileStream class for the 1715 /// specified file name and encoding 1716 /// </summary> 1717 constructor Create(const AFileName: String; const AEncoding: TEncoding); overload; 1718 end; 1719 1720 TBitSet = class(TANTLRObject, IBitSet, ICloneable) 1721 strict private 1722 const 1723 BITS = 64; // number of bits / ulong 1724 LOG_BITS = 6; // 2 shl 6 = 64 1725 1726 ///<summary> We will often need to do a mod operator (i mod nbits). 1727 /// Its turns out that, for powers of two, this mod operation is 1728 /// same as <![CDATA[(I and (nbits-1))]]>. Since mod is slow, we use a precomputed 1729 /// mod mask to do the mod instead. 1730 /// </summary> 1731 MOD_MASK = BITS - 1; 1732 strict private 1733 /// <summary>The actual data bits </summary> 1734 FBits: TUInt64Array; 1735 strict private 1736 class function WordNumber(const Bit: Integer): Integer; static; 1737 class function BitMask(const BitNumber: Integer): UInt64; static; 1738 class function NumWordsToHold(const El: Integer): Integer; static; 1739 protected 1740 { ICloneable } 1741 function Clone: IANTLRInterface; virtual; 1742 protected 1743 { IBitSet } 1744 function GetIsNil: Boolean; virtual; 1745 function BitSetOr(const A: IBitSet): IBitSet; virtual; 1746 procedure Add(const El: Integer); virtual; 1747 procedure GrowToInclude(const Bit: Integer); virtual; 1748 procedure OrInPlace(const A: IBitSet); virtual; 1749 function Size: Integer; virtual; 1750 function Member(const El: Integer): Boolean; virtual; 1751 procedure Remove(const El: Integer); virtual; 1752 function NumBits: Integer; virtual; 1753 function LengthInLongWords: Integer; virtual; 1754 function ToArray: TIntegerArray; virtual; 1755 function ToPackedArray: TUInt64Array; virtual; 1756 function ToString(const TokenNames: TStringArray): String; reintroduce; overload; virtual; 1757 public 1758 /// <summary>Construct a bitset of size one word (64 bits) </summary> 1759 constructor Create; overload; 1760 1761 /// <summary>Construction from a static array of ulongs </summary> 1762 constructor Create(const ABits: array of UInt64); overload; 1763 1764 /// <summary>Construction from a list of integers </summary> 1765 constructor Create(const AItems: IList<Integer>); overload; 1766 1767 /// <summary>Construct a bitset given the size</summary> 1768 /// <param name="nbits">The size of the bitset in bits</param> 1769 constructor Create(const ANBits: Integer); overload; 1770 1771 class function BitSetOf(const El: Integer): IBitSet; overload; static; 1772 class function BitSetOf(const A, B: Integer): IBitSet; overload; static; 1773 class function BitSetOf(const A, B, C: Integer): IBitSet; overload; static; 1774 class function BitSetOf(const A, B, C, D: Integer): IBitSet; overload; static; 1775 1776 function ToString: String; overload; override; 1777 function Equals(Obj: TObject): Boolean; override; 1778 end; 1779 1780 TRecognizerSharedState = class(TANTLRObject, IRecognizerSharedState) 1781 strict private 1782 FFollowing: TBitSetArray; 1783 FFollowingStackPointer: Integer; 1784 FErrorRecovery: Boolean; 1785 FLastErrorIndex: Integer; 1786 FFailed: Boolean; 1787 FSyntaxErrors: Integer; 1788 FBacktracking: Integer; 1789 FRuleMemo: TDictionaryArray<Integer, Integer>; 1790 FToken: IToken; 1791 FTokenStartCharIndex: Integer; 1792 FTokenStartLine: Integer; 1793 FTokenStartCharPositionInLine: Integer; 1794 FChannel: Integer; 1795 FTokenType: Integer; 1796 FText: String; 1797 protected 1798 { IRecognizerSharedState } 1799 function GetFollowing: TBitSetArray; 1800 procedure SetFollowing(const Value: TBitSetArray); 1801 function GetFollowingStackPointer: Integer; 1802 procedure SetFollowingStackPointer(const Value: Integer); 1803 function GetErrorRecovery: Boolean; 1804 procedure SetErrorRecovery(const Value: Boolean); 1805 function GetLastErrorIndex: Integer; 1806 procedure SetLastErrorIndex(const Value: Integer); 1807 function GetFailed: Boolean; 1808 procedure SetFailed(const Value: Boolean); 1809 function GetSyntaxErrors: Integer; 1810 procedure SetSyntaxErrors(const Value: Integer); 1811 function GetBacktracking: Integer; 1812 procedure SetBacktracking(const Value: Integer); 1813 function GetRuleMemo: TDictionaryArray<Integer, Integer>; 1814 function GetRuleMemoCount: Integer; 1815 procedure SetRuleMemoCount(const Value: Integer); 1816 function GetToken: IToken; 1817 procedure SetToken(const Value: IToken); 1818 function GetTokenStartCharIndex: Integer; 1819 procedure SetTokenStartCharIndex(const Value: Integer); 1820 function GetTokenStartLine: Integer; 1821 procedure SetTokenStartLine(const Value: Integer); 1822 function GetTokenStartCharPositionInLine: Integer; 1823 procedure SetTokenStartCharPositionInLine(const Value: Integer); 1824 function GetChannel: Integer; 1825 procedure SetChannel(const Value: Integer); 1826 function GetTokenType: Integer; 1827 procedure SetTokenType(const Value: Integer); 1828 function GetText: String; 1829 procedure SetText(const Value: String); 1830 public 1831 constructor Create; 1832 end; 1833 1834 TCommonToken = class(TANTLRObject, ICommonToken, IToken) 1835 strict protected 1836 FTokenType: Integer; 1837 FLine: Integer; 1838 FCharPositionInLine: Integer; 1839 FChannel: Integer; 1840 FInput: ICharStream; 1841 1842 /// <summary>We need to be able to change the text once in a while. If 1843 /// this is non-null, then getText should return this. Note that 1844 /// start/stop are not affected by changing this. 1845 /// </summary> 1846 FText: String; 1847 1848 /// <summary>What token number is this from 0..n-1 tokens; < 0 implies invalid index </summary> 1849 FIndex: Integer; 1850 1851 /// <summary>The char position into the input buffer where this token starts </summary> 1852 FStart: Integer; 1853 1854 /// <summary>The char position into the input buffer where this token stops </summary> 1855 FStop: Integer; 1856 protected 1857 { IToken } 1858 function GetTokenType: Integer; virtual; 1859 procedure SetTokenType(const Value: Integer); virtual; 1860 function GetLine: Integer; virtual; 1861 procedure SetLine(const Value: Integer); virtual; 1862 function GetCharPositionInLine: Integer; virtual; 1863 procedure SetCharPositionInLine(const Value: Integer); virtual; 1864 function GetChannel: Integer; virtual; 1865 procedure SetChannel(const Value: Integer); virtual; 1866 function GetTokenIndex: Integer; virtual; 1867 procedure SetTokenIndex(const Value: Integer); virtual; 1868 function GetText: String; virtual; 1869 procedure SetText(const Value: String); virtual; 1870 protected 1871 { ICommonToken } 1872 function GetStartIndex: Integer; 1873 procedure SetStartIndex(const Value: Integer); 1874 function GetStopIndex: Integer; 1875 procedure SetStopIndex(const Value: Integer); 1876 function GetInputStream: ICharStream; 1877 procedure SetInputStream(const Value: ICharStream); 1878 protected 1879 constructor Create; overload; 1880 public 1881 constructor Create(const ATokenType: Integer); overload; 1882 constructor Create(const AInput: ICharStream; const ATokenType, AChannel, 1883 AStart, AStop: Integer); overload; 1884 constructor Create(const ATokenType: Integer; const AText: String); overload; 1885 constructor Create(const AOldToken: IToken); overload; 1886 1887 function ToString: String; override; 1888 end; 1889 1890 TClassicToken = class(TANTLRObject, IClassicToken, IToken) 1891 strict private 1892 FText: String; 1893 FTokenType: Integer; 1894 FLine: Integer; 1895 FCharPositionInLine: Integer; 1896 FChannel: Integer; 1897 1898 /// <summary>What token number is this from 0..n-1 tokens </summary> 1899 FIndex: Integer; 1900 protected 1901 { IClassicToken } 1902 function GetTokenType: Integer; virtual; 1903 procedure SetTokenType(const Value: Integer); virtual; 1904 function GetLine: Integer; virtual; 1905 procedure SetLine(const Value: Integer); virtual; 1906 function GetCharPositionInLine: Integer; virtual; 1907 procedure SetCharPositionInLine(const Value: Integer); virtual; 1908 function GetChannel: Integer; virtual; 1909 procedure SetChannel(const Value: Integer); virtual; 1910 function GetTokenIndex: Integer; virtual; 1911 procedure SetTokenIndex(const Value: Integer); virtual; 1912 function GetText: String; virtual; 1913 procedure SetText(const Value: String); virtual; 1914 function GetInputStream: ICharStream; virtual; 1915 procedure SetInputStream(const Value: ICharStream); virtual; 1916 public 1917 constructor Create(const ATokenType: Integer); overload; 1918 constructor Create(const AOldToken: IToken); overload; 1919 constructor Create(const ATokenType: Integer; const AText: String); overload; 1920 constructor Create(const ATokenType: Integer; const AText: String; 1921 const AChannel: Integer); overload; 1922 1923 function ToString: String; override; 1924 end; 1925 1926 TToken = class sealed 1927 public 1928 const 1929 EOR_TOKEN_TYPE = 1; 1930 1931 /// <summary>imaginary tree navigation type; traverse "get child" link </summary> 1932 DOWN = 2; 1933 1934 /// <summary>imaginary tree navigation type; finish with a child list </summary> 1935 UP = 3; 1936 1937 MIN_TOKEN_TYPE = UP + 1; 1938 EOF = Integer(cscEOF); 1939 INVALID_TOKEN_TYPE = 0; 1940 1941 /// <summary> 1942 /// All tokens go to the parser (unless skip() is called in that rule) 1943 /// on a particular "channel". The parser tunes to a particular channel 1944 /// so that whitespace etc... can go to the parser on a "hidden" channel. 1945 /// </summary> 1946 DEFAULT_CHANNEL = 0; 1947 1948 /// <summary> 1949 /// Anything on different channel than DEFAULT_CHANNEL is not parsed by parser. 1950 /// </summary> 1951 HIDDEN_CHANNEL = 99; 1952 public 1953 class var 1954 EOF_TOKEN: IToken; 1955 INVALID_TOKEN: IToken; 1956 /// <summary> 1957 /// In an action, a lexer rule can set token to this SKIP_TOKEN and ANTLR 1958 /// will avoid creating a token for this symbol and try to fetch another. 1959 /// </summary> 1960 SKIP_TOKEN: IToken; 1961 private 1962 class procedure Initialize; static; 1963 end; 1964 1965 /// <summary> 1966 /// Global constants 1967 /// </summary> 1968 TConstants = class sealed 1969 public 1970 const 1971 VERSION = '3.1b1'; 1972 1973 // Moved to version 2 for v3.1: added grammar name to enter/exit Rule 1974 DEBUG_PROTOCOL_VERSION = '2'; 1975 1976 ANTLRWORKS_DIR = 'antlrworks'; 1977 end; 1978 1979 TBaseRecognizer = class abstract(TANTLRObject, IBaseRecognizer) 1980 public 1981 const 1982 MEMO_RULE_FAILED = -2; 1983 MEMO_RULE_UNKNOWN = -1; 1984 INITIAL_FOLLOW_STACK_SIZE = 100; 1985 NEXT_TOKEN_RULE_NAME = 'nextToken'; 1986 // copies from Token object for convenience in actions 1987 DEFAULT_TOKEN_CHANNEL = TToken.DEFAULT_CHANNEL; 1988 HIDDEN = TToken.HIDDEN_CHANNEL; 1989 strict protected 1990 /// <summary> 1991 /// An externalized representation of the - shareable - internal state of 1992 /// this lexer, parser or tree parser. 1993 /// </summary> 1994 /// <remarks> 1995 /// The state of a lexer, parser, or tree parser are collected into 1996 /// external state objects so that the state can be shared. This sharing 1997 /// is needed to have one grammar import others and share same error 1998 /// variables and other state variables. It's a kind of explicit multiple 1999 /// inheritance via delegation of methods and shared state. 2000 /// </remarks> 2001 FState: IRecognizerSharedState; 2002 2003 property State: IRecognizerSharedState read FState; 2004 strict protected 2005 /// <summary> 2006 /// Match needs to return the current input symbol, which gets put 2007 /// into the label for the associated token ref; e.g., x=ID. Token 2008 /// and tree parsers need to return different objects. Rather than test 2009 /// for input stream type or change the IntStream interface, I use 2010 /// a simple method to ask the recognizer to tell me what the current 2011 /// input symbol is. 2012 /// </summary> 2013 /// <remarks>This is ignored for lexers.</remarks> 2014 function GetCurrentInputSymbol(const Input: IIntStream): IANTLRInterface; virtual; 2015 2016 /// <summary> 2017 /// Factor out what to do upon token mismatch so tree parsers can behave 2018 /// differently. Override and call MismatchRecover(input, ttype, follow) 2019 /// to get single token insertion and deletion. Use this to turn off 2020 /// single token insertion and deletion. Override mismatchRecover 2021 /// to call this instead. 2022 /// </summary> 2023 procedure Mismatch(const Input: IIntStream; const TokenType: Integer; 2024 const Follow: IBitSet); virtual; 2025 2026 /// <summary> 2027 /// Attempt to Recover from a single missing or extra token. 2028 /// </summary> 2029 /// <remarks> 2030 /// EXTRA TOKEN 2031 /// 2032 /// LA(1) is not what we are looking for. If LA(2) has the right token, 2033 /// however, then assume LA(1) is some extra spurious token. Delete it 2034 /// and LA(2) as if we were doing a normal Match(), which advances the 2035 /// input. 2036 /// 2037 /// MISSING TOKEN 2038 /// 2039 /// If current token is consistent with what could come after 2040 /// ttype then it is ok to "insert" the missing token, else throw 2041 /// exception For example, Input "i=(3;" is clearly missing the 2042 /// ')'. When the parser returns from the nested call to expr, it 2043 /// will have call chain: 2044 /// 2045 /// stat -> expr -> atom 2046 /// 2047 /// and it will be trying to Match the ')' at this point in the 2048 /// derivation: 2049 /// 2050 /// => ID '=' '(' INT ')' ('+' atom)* ';' 2051 /// ^ 2052 /// Match() will see that ';' doesn't Match ')' and report a 2053 /// mismatched token error. To Recover, it sees that LA(1)==';' 2054 /// is in the set of tokens that can follow the ')' token 2055 /// reference in rule atom. It can assume that you forgot the ')'. 2056 /// </remarks> 2057 function RecoverFromMismatchedToken(const Input: IIntStream; 2058 const TokenType: Integer; const Follow: IBitSet): IANTLRInterface; virtual; 2059 2060 /// <summary> 2061 /// Conjure up a missing token during error recovery. 2062 /// </summary> 2063 /// <remarks> 2064 /// The recognizer attempts to recover from single missing 2065 /// symbols. But, actions might refer to that missing symbol. 2066 /// For example, x=ID {f($x);}. The action clearly assumes 2067 /// that there has been an identifier matched previously and that 2068 /// $x points at that token. If that token is missing, but 2069 /// the next token in the stream is what we want we assume that 2070 /// this token is missing and we keep going. Because we 2071 /// have to return some token to replace the missing token, 2072 /// we have to conjure one up. This method gives the user control 2073 /// over the tokens returned for missing tokens. Mostly, 2074 /// you will want to create something special for identifier 2075 /// tokens. For literals such as '{' and ',', the default 2076 /// action in the parser or tree parser works. It simply creates 2077 /// a CommonToken of the appropriate type. The text will be the token. 2078 /// If you change what tokens must be created by the lexer, 2079 /// override this method to create the appropriate tokens. 2080 /// </remarks> 2081 function GetMissingSymbol(const Input: IIntStream; 2082 const E: ERecognitionException; const ExpectedTokenType: Integer; 2083 const Follow: IBitSet): IANTLRInterface; virtual; 2084 2085 /// <summary> 2086 /// Push a rule's follow set using our own hardcoded stack 2087 /// </summary> 2088 /// <param name="fset"></param> 2089 procedure PushFollow(const FSet: IBitSet); 2090 2091 /// <summary>Compute the context-sensitive FOLLOW set for current rule. 2092 /// This is set of token types that can follow a specific rule 2093 /// reference given a specific call chain. You get the set of 2094 /// viable tokens that can possibly come next (lookahead depth 1) 2095 /// given the current call chain. Contrast this with the 2096 /// definition of plain FOLLOW for rule r: 2097 /// 2098 /// FOLLOW(r)={x | S=>*alpha r beta in G and x in FIRST(beta)} 2099 /// 2100 /// where x in T* and alpha, beta in V*; T is set of terminals and 2101 /// V is the set of terminals and nonterminals. In other words, 2102 /// FOLLOW(r) is the set of all tokens that can possibly follow 2103 /// references to r in *any* sentential form (context). At 2104 /// runtime, however, we know precisely which context applies as 2105 /// we have the call chain. We may compute the exact (rather 2106 /// than covering superset) set of following tokens. 2107 /// 2108 /// For example, consider grammar: 2109 /// 2110 /// stat : ID '=' expr ';' // FOLLOW(stat)=={EOF} 2111 /// | "return" expr '.' 2112 /// ; 2113 /// expr : atom ('+' atom)* ; // FOLLOW(expr)=={';','.',')'} 2114 /// atom : INT // FOLLOW(atom)=={'+',')',';','.'} 2115 /// | '(' expr ')' 2116 /// ; 2117 /// 2118 /// The FOLLOW sets are all inclusive whereas context-sensitive 2119 /// FOLLOW sets are precisely what could follow a rule reference. 2120 /// For input input "i=(3);", here is the derivation: 2121 /// 2122 /// stat => ID '=' expr ';' 2123 /// => ID '=' atom ('+' atom)* ';' 2124 /// => ID '=' '(' expr ')' ('+' atom)* ';' 2125 /// => ID '=' '(' atom ')' ('+' atom)* ';' 2126 /// => ID '=' '(' INT ')' ('+' atom)* ';' 2127 /// => ID '=' '(' INT ')' ';' 2128 /// 2129 /// At the "3" token, you'd have a call chain of 2130 /// 2131 /// stat -> expr -> atom -> expr -> atom 2132 /// 2133 /// What can follow that specific nested ref to atom? Exactly ')' 2134 /// as you can see by looking at the derivation of this specific 2135 /// input. Contrast this with the FOLLOW(atom)={'+',')',';','.'}. 2136 /// 2137 /// You want the exact viable token set when recovering from a 2138 /// token mismatch. Upon token mismatch, if LA(1) is member of 2139 /// the viable next token set, then you know there is most likely 2140 /// a missing token in the input stream. "Insert" one by just not 2141 /// throwing an exception. 2142 /// </summary> 2143 function ComputeContextSensitiveRuleFOLLOW: IBitSet; virtual; 2144 2145 (* Compute the error recovery set for the current rule. During 2146 * rule invocation, the parser pushes the set of tokens that can 2147 * follow that rule reference on the stack; this amounts to 2148 * computing FIRST of what follows the rule reference in the 2149 * enclosing rule. This local follow set only includes tokens 2150 * from within the rule; i.e., the FIRST computation done by 2151 * ANTLR stops at the end of a rule. 2152 * 2153 * EXAMPLE 2154 * 2155 * When you find a "no viable alt exception", the input is not 2156 * consistent with any of the alternatives for rule r. The best 2157 * thing to do is to consume tokens until you see something that 2158 * can legally follow a call to r *or* any rule that called r. 2159 * You don't want the exact set of viable next tokens because the 2160 * input might just be missing a token--you might consume the 2161 * rest of the input looking for one of the missing tokens. 2162 * 2163 * Consider grammar: 2164 * 2165 * a : '[' b ']' 2166 * | '(' b ')' 2167 * ; 2168 * b : c '^' INT ; 2169 * c : ID 2170 * | INT 2171 * ; 2172 * 2173 * At each rule invocation, the set of tokens that could follow 2174 * that rule is pushed on a stack. Here are the various "local" 2175 * follow sets: 2176 * 2177 * FOLLOW(b1_in_a) = FIRST(']') = ']' 2178 * FOLLOW(b2_in_a) = FIRST(')') = ')' 2179 * FOLLOW(c_in_b) = FIRST('^') = '^' 2180 * 2181 * Upon erroneous input "[]", the call chain is 2182 * 2183 * a -> b -> c 2184 * 2185 * and, hence, the follow context stack is: 2186 * 2187 * depth local follow set after call to rule 2188 * 0 <EOF> a (from main()) 2189 * 1 ']' b 2190 * 3 '^' c 2191 * 2192 * Notice that ')' is not included, because b would have to have 2193 * been called from a different context in rule a for ')' to be 2194 * included. 2195 * 2196 * For error recovery, we cannot consider FOLLOW(c) 2197 * (context-sensitive or otherwise). We need the combined set of 2198 * all context-sensitive FOLLOW sets--the set of all tokens that 2199 * could follow any reference in the call chain. We need to 2200 * resync to one of those tokens. Note that FOLLOW(c)='^' and if 2201 * we resync'd to that token, we'd consume until EOF. We need to 2202 * sync to context-sensitive FOLLOWs for a, b, and c: {']','^'}. 2203 * In this case, for input "[]", LA(1) is in this set so we would 2204 * not consume anything and after printing an error rule c would 2205 * return normally. It would not find the required '^' though. 2206 * At this point, it gets a mismatched token error and throws an 2207 * exception (since LA(1) is not in the viable following token 2208 * set). The rule exception handler tries to Recover, but finds 2209 * the same recovery set and doesn't consume anything. Rule b 2210 * exits normally returning to rule a. Now it finds the ']' (and 2211 * with the successful Match exits errorRecovery mode). 2212 * 2213 * So, you cna see that the parser walks up call chain looking 2214 * for the token that was a member of the recovery set. 2215 * 2216 * Errors are not generated in errorRecovery mode. 2217 * 2218 * ANTLR's error recovery mechanism is based upon original ideas: 2219 * 2220 * "Algorithms + Data Structures = Programs" by Niklaus Wirth 2221 * 2222 * and 2223 * 2224 * "A note on error recovery in recursive descent parsers": 2225 * http://portal.acm.org/citation.cfm?id=947902.947905 2226 * 2227 * Later, Josef Grosch had some good ideas: 2228 * 2229 * "Efficient and Comfortable Error Recovery in Recursive Descent 2230 * Parsers": 2231 * ftp://www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip 2232 * 2233 * Like Grosch I implemented local FOLLOW sets that are combined 2234 * at run-time upon error to avoid overhead during parsing. 2235 *) 2236 function ComputeErrorRecoverySet: IBitSet; virtual; 2237 2238 function CombineFollows(const Exact: Boolean): IBitSet; 2239 protected 2240 { IBaseRecognizer } 2241 function GetInput: IIntStream; virtual; abstract; 2242 function GetBacktrackingLevel: Integer; 2243 function GetState: IRecognizerSharedState; 2244 function GetNumberOfSyntaxErrors: Integer; 2245 function GetGrammarFileName: String; virtual; 2246 function GetSourceName: String; virtual; abstract; 2247 function GetTokenNames: TStringArray; virtual; 2248 2249 procedure BeginBacktrack(const Level: Integer); virtual; 2250 procedure EndBacktrack(const Level: Integer; const Successful: Boolean); virtual; 2251 procedure Reset; virtual; 2252 function Match(const Input: IIntStream; const TokenType: Integer; 2253 const Follow: IBitSet): IANTLRInterface; virtual; 2254 function MismatchIsUnwantedToken(const Input: IIntStream; 2255 const TokenType: Integer): Boolean; 2256 function MismatchIsMissingToken(const Input: IIntStream; 2257 const Follow: IBitSet): Boolean; 2258 procedure BeginResync; virtual; 2259 procedure EndResync; virtual; 2260 procedure ReportError(const E: ERecognitionException); virtual; 2261 procedure MatchAny(const Input: IIntStream); virtual; 2262 procedure DisplayRecognitionError(const TokenNames: TStringArray; 2263 const E: ERecognitionException); virtual; 2264 function GetErrorMessage(const E: ERecognitionException; 2265 const TokenNames: TStringArray): String; virtual; 2266 function GetErrorHeader(const E: ERecognitionException): String; virtual; 2267 function GetTokenErrorDisplay(const T: IToken): String; virtual; 2268 procedure EmitErrorMessage(const Msg: String); virtual; 2269 procedure Recover(const Input: IIntStream; const RE: ERecognitionException); virtual; 2270 function RecoverFromMismatchedSet(const Input: IIntStream; 2271 const E: ERecognitionException; const Follow: IBitSet): IANTLRInterface; virtual; 2272 procedure ConsumeUntil(const Input: IIntStream; const TokenType: Integer); overload; virtual; 2273 procedure ConsumeUntil(const Input: IIntStream; const BitSet: IBitSet); overload; virtual; 2274 //function GetRuleInvocationStack: IList<IANTLRInterface>; overload; virtual; 2275 //function GetRuleInvocationStack(const E: Exception; 2276 // const RecognizerClassName: String): IList<IANTLRInterface>; overload; 2277 function ToStrings(const Tokens: IList<IToken>): IList<String>; virtual; 2278 function GetRuleMemoization(const RuleIndex, RuleStartIndex: Integer): Integer; virtual; 2279 function AlreadyParsedRule(const Input: IIntStream; 2280 const RuleIndex: Integer): Boolean; virtual; 2281 procedure Memoize(const Input: IIntStream; const RuleIndex, 2282 RuleStartIndex: Integer); virtual; 2283 function GetRuleMemoizationChaceSize: Integer; 2284 2285 procedure TraceIn(const RuleName: String; const RuleIndex: Integer; 2286 const InputSymbol: String); virtual; 2287 procedure TraceOut(const RuleName: String; const RuleIndex: Integer; 2288 const InputSymbol: String); virtual; 2289 2290 property Input: IIntStream read GetInput; 2291 public 2292 constructor Create; overload; 2293 constructor Create(const AState: IRecognizerSharedState); overload; 2294 end; 2295 2296 TCommonTokenStream = class(TANTLRObject, ICommonTokenStream, ITokenStream) 2297 strict private 2298 FTokenSource: ITokenSource; 2299 2300 /// <summary>Record every single token pulled from the source so we can reproduce 2301 /// chunks of it later. 2302 /// </summary> 2303 FTokens: IList<IToken>; 2304 2305 /// <summary><![CDATA[Map<tokentype, channel>]]> to override some Tokens' channel numbers </summary> 2306 FChannelOverrideMap: IDictionary<Integer, Integer>; 2307 2308 /// <summary><![CDATA[Set<tokentype>;]]> discard any tokens with this type </summary> 2309 FDiscardSet: IHashList<Integer, Integer>; 2310 2311 /// <summary>Skip tokens on any channel but this one; this is how we skip whitespace... </summary> 2312 FChannel: Integer; 2313 2314 /// <summary>By default, track all incoming tokens </summary> 2315 FDiscardOffChannelTokens: Boolean; 2316 2317 /// <summary>Track the last Mark() call result value for use in Rewind().</summary> 2318 FLastMarker: Integer; 2319 2320 /// <summary> 2321 /// The index into the tokens list of the current token (next token 2322 /// to consume). p==-1 indicates that the tokens list is empty 2323 /// </summary> 2324 FP: Integer; 2325 strict protected 2326 /// <summary>Load all tokens from the token source and put in tokens. 2327 /// This is done upon first LT request because you might want to 2328 /// set some token type / channel overrides before filling buffer. 2329 /// </summary> 2330 procedure FillBuffer; virtual; 2331 2332 /// <summary>Look backwards k tokens on-channel tokens </summary> 2333 function LB(const K: Integer): IToken; virtual; 2334 2335 /// <summary>Given a starting index, return the index of the first on-channel 2336 /// token. 2337 /// </summary> 2338 function SkipOffTokenChannels(const I: Integer): Integer; virtual; 2339 function SkipOffTokenChannelsReverse(const I: Integer): Integer; virtual; 2340 protected 2341 { IIntStream } 2342 function GetSourceName: String; virtual; 2343 2344 procedure Consume; virtual; 2345 function LA(I: Integer): Integer; virtual; 2346 function LAChar(I: Integer): Char; 2347 function Mark: Integer; virtual; 2348 function Index: Integer; virtual; 2349 procedure Rewind(const Marker: Integer); overload; virtual; 2350 procedure Rewind; overload; virtual; 2351 procedure Release(const Marker: Integer); virtual; 2352 procedure Seek(const Index: Integer); virtual; 2353 function Size: Integer; virtual; 2354 protected 2355 { ITokenStream } 2356 function GetTokenSource: ITokenSource; virtual; 2357 procedure SetTokenSource(const Value: ITokenSource); virtual; 2358 2359 function LT(const K: Integer): IToken; virtual; 2360 function Get(const I: Integer): IToken; virtual; 2361 function ToString(const Start, Stop: Integer): String; reintroduce; overload; virtual; 2362 function ToString(const Start, Stop: IToken): String; reintroduce; overload; virtual; 2363 protected 2364 { ICommonTokenStream } 2365 procedure SetTokenTypeChannel(const TType, Channel: Integer); 2366 procedure DiscardTokenType(const TType: Integer); 2367 procedure DiscardOffChannelTokens(const Discard: Boolean); 2368 function GetTokens: IList<IToken>; overload; 2369 function GetTokens(const Start, Stop: Integer): IList<IToken>; overload; 2370 function GetTokens(const Start, Stop: Integer; 2371 const Types: IBitSet): IList<IToken>; overload; 2372 function GetTokens(const Start, Stop: Integer; 2373 const Types: IList<Integer>): IList<IToken>; overload; 2374 function GetTokens(const Start, Stop, 2375 TokenType: Integer): IList<IToken>; overload; 2376 procedure Reset; virtual; 2377 public 2378 constructor Create; overload; 2379 constructor Create(const ATokenSource: ITokenSource); overload; 2380 constructor Create(const ATokenSource: ITokenSource; 2381 const AChannel: Integer); overload; 2382 constructor Create(const ALexer: ILexer); overload; 2383 constructor Create(const ALexer: ILexer; 2384 const AChannel: Integer); overload; 2385 2386 function ToString: String; overload; override; 2387 end; 2388 2389 TDFA = class abstract(TANTLRObject, IDFA) 2390 strict private 2391 FSpecialStateTransitionHandler: TSpecialStateTransitionHandler; 2392 FEOT: TSmallintArray; 2393 FEOF: TSmallintArray; 2394 FMin: TCharArray; 2395 FMax: TCharArray; 2396 FAccept: TSmallintArray; 2397 FSpecial: TSmallintArray; 2398 FTransition: TSmallintMatrix; 2399 FDecisionNumber: Integer; 2400 FRecognizer: Pointer; { IBaseRecognizer } 2401 function GetRecognizer: IBaseRecognizer; 2402 procedure SetRecognizer(const Value: IBaseRecognizer); 2403 strict protected 2404 procedure NoViableAlt(const S: Integer; const Input: IIntStream); 2405 2406 property Recognizer: IBaseRecognizer read GetRecognizer write SetRecognizer; 2407 property DecisionNumber: Integer read FDecisionNumber write FDecisionNumber; 2408 property EOT: TSmallintArray read FEOT write FEOT; 2409 property EOF: TSmallintArray read FEOF write FEOF; 2410 property Min: TCharArray read FMin write FMin; 2411 property Max: TCharArray read FMax write FMax; 2412 property Accept: TSmallintArray read FAccept write FAccept; 2413 property Special: TSmallintArray read FSpecial write FSpecial; 2414 property Transition: TSmallintMatrix read FTransition write FTransition; 2415 protected 2416 { IDFA } 2417 function GetSpecialStateTransitionHandler: TSpecialStateTransitionHandler; 2418 procedure SetSpecialStateTransitionHandler(const Value: TSpecialStateTransitionHandler); 2419 2420 function Predict(const Input: IIntStream): Integer; 2421 procedure Error(const NVAE: ENoViableAltException); virtual; 2422 function SpecialStateTransition(const S: Integer; 2423 const Input: IIntStream): Integer; virtual; 2424 function Description: String; virtual; 2425 function SpecialTransition(const State, Symbol: Integer): Integer; 2426 public 2427 class function UnpackEncodedString(const EncodedString: String): TSmallintArray; static; 2428 class function UnpackEncodedStringArray(const EncodedStrings: TStringArray): TSmallintMatrix; overload; static; 2429 class function UnpackEncodedStringArray(const EncodedStrings: array of String): TSmallintMatrix; overload; static; 2430 class function UnpackEncodedStringToUnsignedChars(const EncodedString: String): TCharArray; static; 2431 end; 2432 2433 TLexer = class abstract(TBaseRecognizer, ILexer, ITokenSource) 2434 strict private 2435 const 2436 TOKEN_dot_EOF = Ord(cscEOF); 2437 strict private 2438 /// <summary>Where is the lexer drawing characters from? </summary> 2439 FInput: ICharStream; 2440 protected 2441 { IBaseRecognizer } 2442 function GetSourceName: String; override; 2443 function GetInput: IIntStream; override; 2444 procedure Reset; override; 2445 procedure ReportError(const E: ERecognitionException); override; 2446 function GetErrorMessage(const E: ERecognitionException; 2447 const TokenNames: TStringArray): String; override; 2448 protected 2449 { ILexer } 2450 function GetCharStream: ICharStream; virtual; 2451 procedure SetCharStream(const Value: ICharStream); virtual; 2452 function GetLine: Integer; virtual; 2453 function GetCharPositionInLine: Integer; virtual; 2454 function GetCharIndex: Integer; virtual; 2455 function GetText: String; virtual; 2456 procedure SetText(const Value: String); virtual; 2457 2458 function NextToken: IToken; virtual; 2459 procedure Skip; 2460 procedure DoTokens; virtual; abstract; 2461 procedure Emit(const Token: IToken); overload; virtual; 2462 function Emit: IToken; overload; virtual; 2463 procedure Match(const S: String); reintroduce; overload; virtual; 2464 procedure Match(const C: Integer); reintroduce; overload; virtual; 2465 procedure MatchAny; reintroduce; overload; virtual; 2466 procedure MatchRange(const A, B: Integer); virtual; 2467 procedure Recover(const RE: ERecognitionException); reintroduce; overload; virtual; 2468 function GetCharErrorDisplay(const C: Integer): String; 2469 procedure TraceIn(const RuleName: String; const RuleIndex: Integer); reintroduce; overload; virtual; 2470 procedure TraceOut(const RuleName: String; const RuleIndex: Integer); reintroduce; overload; virtual; 2471 strict protected 2472 property Input: ICharStream read FInput; 2473 property CharIndex: Integer read GetCharIndex; 2474 property Text: String read GetText write SetText; 2475 public 2476 constructor Create; overload; 2477 constructor Create(const AInput: ICharStream); overload; 2478 constructor Create(const AInput: ICharStream; 2479 const AState: IRecognizerSharedState); overload; 2480 end; 2481 2482 TParser = class(TBaseRecognizer, IParser) 2483 strict private 2484 FInput: ITokenStream; 2485 protected 2486 property Input: ITokenStream read FInput; 2487 protected 2488 { IBaseRecognizer } 2489 procedure Reset; override; 2490 function GetCurrentInputSymbol(const Input: IIntStream): IANTLRInterface; override; 2491 function GetMissingSymbol(const Input: IIntStream; 2492 const E: ERecognitionException; const ExpectedTokenType: Integer; 2493 const Follow: IBitSet): IANTLRInterface; override; 2494 function GetSourceName: String; override; 2495 function GetInput: IIntStream; override; 2496 protected 2497 { IParser } 2498 function GetTokenStream: ITokenStream; virtual; 2499 procedure SetTokenStream(const Value: ITokenStream); virtual; 2500 2501 procedure TraceIn(const RuleName: String; const RuleIndex: Integer); reintroduce; overload; 2502 procedure TraceOut(const RuleName: String; const RuleIndex: Integer); reintroduce; overload; 2503 public 2504 constructor Create(const AInput: ITokenStream); overload; 2505 constructor Create(const AInput: ITokenStream; 2506 const AState: IRecognizerSharedState); overload; 2507 end; 2508 2509 TRuleReturnScope = class(TANTLRObject, IRuleReturnScope) 2510 protected 2511 { IRuleReturnScope } 2512 function GetStart: IANTLRInterface; virtual; 2513 procedure SetStart(const Value: IANTLRInterface); virtual; 2514 function GetStop: IANTLRInterface; virtual; 2515 procedure SetStop(const Value: IANTLRInterface); virtual; 2516 function GetTree: IANTLRInterface; virtual; 2517 procedure SetTree(const Value: IANTLRInterface); virtual; 2518 function GetTemplate: IANTLRInterface; virtual; 2519 end; 2520 2521 TParserRuleReturnScope = class(TRuleReturnScope, IParserRuleReturnScope) 2522 strict private 2523 FStart: IToken; 2524 FStop: IToken; 2525 protected 2526 { IRuleReturnScope } 2527 function GetStart: IANTLRInterface; override; 2528 procedure SetStart(const Value: IANTLRInterface); override; 2529 function GetStop: IANTLRInterface; override; 2530 procedure SetStop(const Value: IANTLRInterface); override; 2531 end; 2532 2533 TTokenRewriteStream = class(TCommonTokenStream, ITokenRewriteStream) 2534 public 2535 const 2536 DEFAULT_PROGRAM_NAME = 'default'; 2537 PROGRAM_INIT_SIZE = 100; 2538 MIN_TOKEN_INDEX = 0; 2539 strict protected 2540 // Define the rewrite operation hierarchy 2541 type 2542 IRewriteOperation = interface(IANTLRInterface) 2543 ['{285A54ED-58FF-44B1-A268-2686476D4419}'] 2544 { Property accessors } 2545 function GetInstructionIndex: Integer; 2546 procedure SetInstructionIndex(const Value: Integer); 2547 function GetIndex: Integer; 2548 procedure SetIndex(const Value: Integer); 2549 function GetText: IANTLRInterface; 2550 procedure SetText(const Value: IANTLRInterface); 2551 function GetParent: ITokenRewriteStream; 2552 procedure SetParent(const Value: ITokenRewriteStream); 2553 2554 { Methods } 2555 2556 /// <summary>Execute the rewrite operation by possibly adding to the buffer. 2557 /// Return the index of the next token to operate on. 2558 /// </summary> 2559 function Execute(const Buf: TStringBuilder): Integer; 2560 2561 { Properties } 2562 property InstructionIndex: Integer read GetInstructionIndex write SetInstructionIndex; 2563 property Index: Integer read GetIndex write SetIndex; 2564 property Text: IANTLRInterface read GetText write SetText; 2565 property Parent: ITokenRewriteStream read GetParent write SetParent; 2566 end; 2567 2568 TRewriteOperation = class(TANTLRObject, IRewriteOperation) 2569 strict private 2570 // What index into rewrites List are we? 2571 FInstructionIndex: Integer; 2572 // Token buffer index 2573 FIndex: Integer; 2574 FText: IANTLRInterface; 2575 FParent: Pointer; {ITokenRewriteStream;} 2576 protected 2577 { IRewriteOperation } 2578 function GetInstructionIndex: Integer; 2579 procedure SetInstructionIndex(const Value: Integer); 2580 function GetIndex: Integer; 2581 procedure SetIndex(const Value: Integer); 2582 function GetText: IANTLRInterface; 2583 procedure SetText(const Value: IANTLRInterface); 2584 function GetParent: ITokenRewriteStream; 2585 procedure SetParent(const Value: ITokenRewriteStream); 2586 2587 function Execute(const Buf: TStringBuilder): Integer; virtual; 2588 protected 2589 constructor Create(const AIndex: Integer; const AText: IANTLRInterface; 2590 const AParent: ITokenRewriteStream); 2591 2592 property Index: Integer read FIndex write FIndex; 2593 property Text: IANTLRInterface read FText write FText; 2594 property Parent: ITokenRewriteStream read GetParent write SetParent; 2595 public 2596 function ToString: String; override; 2597 end; 2598 2599 IInsertBeforeOp = interface(IRewriteOperation) 2600 ['{BFB732E2-BE6A-4691-AE3B-5C8013DE924E}'] 2601 end; 2602 2603 TInsertBeforeOp = class(TRewriteOperation, IInsertBeforeOp) 2604 protected 2605 { IRewriteOperation } 2606 function Execute(const Buf: TStringBuilder): Integer; override; 2607 end; 2608 2609 /// <summary>I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp 2610 /// instructions. 2611 /// </summary> 2612 IReplaceOp = interface(IRewriteOperation) 2613 ['{630C434A-99EA-4589-A65D-64A7B3DAC407}'] 2614 { Property accessors } 2615 function GetLastIndex: Integer; 2616 procedure SetLastIndex(const Value: Integer); 2617 2618 { Properties } 2619 property LastIndex: Integer read GetLastIndex write SetLastIndex; 2620 end; 2621 2622 TReplaceOp = class(TRewriteOperation, IReplaceOp) 2623 private 2624 FLastIndex: Integer; 2625 protected 2626 { IRewriteOperation } 2627 function Execute(const Buf: TStringBuilder): Integer; override; 2628 protected 2629 { IReplaceOp } 2630 function GetLastIndex: Integer; 2631 procedure SetLastIndex(const Value: Integer); 2632 public 2633 constructor Create(const AStart, AStop: Integer; 2634 const AText: IANTLRInterface; const AParent: ITokenRewriteStream); 2635 2636 function ToString: String; override; 2637 end; 2638 2639 IDeleteOp = interface(IRewriteOperation) 2640 ['{C39345BC-F170-4C3A-A989-65E6B9F0712B}'] 2641 end; 2642 2643 TDeleteOp = class(TReplaceOp) 2644 public 2645 function ToString: String; override; 2646 end; 2647 strict private 2648 type 2649 TRewriteOpComparer<T: IRewriteOperation> = class(TComparer<T>) 2650 public 2651 function Compare(const Left, Right: T): Integer; override; 2652 end; 2653 strict private 2654 /// <summary>You may have multiple, named streams of rewrite operations. 2655 /// I'm calling these things "programs." 2656 /// Maps String (name) -> rewrite (IList) 2657 /// </summary> 2658 FPrograms: IDictionary<String, IList<IRewriteOperation>>; 2659 2660 /// <summary>Map String (program name) -> Integer index </summary> 2661 FLastRewriteTokenIndexes: IDictionary<String, Integer>; 2662 strict private 2663 function InitializeProgram(const Name: String): IList<IRewriteOperation>; 2664 protected 2665 { ITokenRewriteStream } 2666 procedure Rollback(const InstructionIndex: Integer); overload; virtual; 2667 procedure Rollback(const ProgramName: String; 2668 const InstructionIndex: Integer); overload; virtual; 2669 2670 procedure DeleteProgram; overload; virtual; 2671 procedure DeleteProgram(const ProgramName: String); overload; virtual; 2672 2673 procedure InsertAfter(const T: IToken; const Text: IANTLRInterface); overload; virtual; 2674 procedure InsertAfter(const Index: Integer; const Text: IANTLRInterface); overload; virtual; 2675 procedure InsertAfter(const ProgramName: String; const T: IToken; 2676 const Text: IANTLRInterface); overload; virtual; 2677 procedure InsertAfter(const ProgramName: String; const Index: Integer; 2678 const Text: IANTLRInterface); overload; virtual; 2679 procedure InsertAfter(const T: IToken; const Text: String); overload; 2680 procedure InsertAfter(const Index: Integer; const Text: String); overload; 2681 procedure InsertAfter(const ProgramName: String; const T: IToken; 2682 const Text: String); overload; 2683 procedure InsertAfter(const ProgramName: String; const Index: Integer; 2684 const Text: String); overload; 2685 2686 procedure InsertBefore(const T: IToken; const Text: IANTLRInterface); overload; virtual; 2687 procedure InsertBefore(const Index: Integer; const Text: IANTLRInterface); overload; virtual; 2688 procedure InsertBefore(const ProgramName: String; const T: IToken; 2689 const Text: IANTLRInterface); overload; virtual; 2690 procedure InsertBefore(const ProgramName: String; const Index: Integer; 2691 const Text: IANTLRInterface); overload; virtual; 2692 procedure InsertBefore(const T: IToken; const Text: String); overload; 2693 procedure InsertBefore(const Index: Integer; const Text: String); overload; 2694 procedure InsertBefore(const ProgramName: String; const T: IToken; 2695 const Text: String); overload; 2696 procedure InsertBefore(const ProgramName: String; const Index: Integer; 2697 const Text: String); overload; 2698 2699 procedure Replace(const Index: Integer; const Text: IANTLRInterface); overload; virtual; 2700 procedure Replace(const Start, Stop: Integer; const Text: IANTLRInterface); overload; virtual; 2701 procedure Replace(const IndexT: IToken; const Text: IANTLRInterface); overload; virtual; 2702 procedure Replace(const Start, Stop: IToken; const Text: IANTLRInterface); overload; virtual; 2703 procedure Replace(const ProgramName: String; const Start, Stop: Integer; 2704 const Text: IANTLRInterface); overload; virtual; 2705 procedure Replace(const ProgramName: String; const Start, Stop: IToken; 2706 const Text: IANTLRInterface); overload; virtual; 2707 procedure Replace(const Index: Integer; const Text: String); overload; 2708 procedure Replace(const Start, Stop: Integer; const Text: String); overload; 2709 procedure Replace(const IndexT: IToken; const Text: String); overload; 2710 procedure Replace(const Start, Stop: IToken; const Text: String); overload; 2711 procedure Replace(const ProgramName: String; const Start, Stop: Integer; 2712 const Text: String); overload; 2713 procedure Replace(const ProgramName: String; const Start, Stop: IToken; 2714 const Text: String); overload; 2715 2716 procedure Delete(const Index: Integer); overload; virtual; 2717 procedure Delete(const Start, Stop: Integer); overload; virtual; 2718 procedure Delete(const IndexT: IToken); overload; virtual; 2719 procedure Delete(const Start, Stop: IToken); overload; virtual; 2720 procedure Delete(const ProgramName: String; const Start, Stop: Integer); overload; virtual; 2721 procedure Delete(const ProgramName: String; const Start, Stop: IToken); overload; virtual; 2722 2723 function GetLastRewriteTokenIndex: Integer; overload; virtual; 2724 2725 function ToOriginalString: String; overload; virtual; 2726 function ToOriginalString(const Start, Stop: Integer): String; overload; virtual; 2727 2728 function ToString(const ProgramName: String): String; overload; virtual; 2729 function ToString(const ProgramName: String; 2730 const Start, Stop: Integer): String; overload; virtual; 2731 2732 function ToDebugString: String; overload; virtual; 2733 function ToDebugString(const Start, Stop: Integer): String; overload; virtual; 2734 protected 2735 { ITokenStream } 2736 function ToString(const Start, Stop: Integer): String; overload; override; 2737 strict protected 2738 procedure Init; virtual; 2739 function GetProgram(const Name: String): IList<IRewriteOperation>; virtual; 2740 function GetLastRewriteTokenIndex(const ProgramName: String): Integer; overload; virtual; 2741 procedure SetLastRewriteTokenIndex(const ProgramName: String; const I: Integer); overload; virtual; 2742 2743 /// <summary> 2744 /// Return a map from token index to operation. 2745 /// </summary> 2746 /// <remarks>We need to combine operations and report invalid operations (like 2747 /// overlapping replaces that are not completed nested). Inserts to 2748 /// same index need to be combined etc... Here are the cases: 2749 /// 2750 /// I.i.u I.j.v leave alone, nonoverlapping 2751 /// I.i.u I.i.v combine: Iivu 2752 /// 2753 /// R.i-j.u R.x-y.v | i-j in x-y delete first R 2754 /// R.i-j.u R.i-j.v delete first R 2755 /// R.i-j.u R.x-y.v | x-y in i-j ERROR 2756 /// R.i-j.u R.x-y.v | boundaries overlap ERROR 2757 /// 2758 /// I.i.u R.x-y.v | i in x-y delete I 2759 /// I.i.u R.x-y.v | i not in x-y leave alone, nonoverlapping 2760 /// R.x-y.v I.i.u | i in x-y ERROR 2761 /// R.x-y.v I.x.u R.x-y.uv (combine, delete I) 2762 /// R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping 2763 /// 2764 /// I.i.u = insert u before op @ index i 2765 /// R.x-y.u = replace x-y indexed tokens with u 2766 /// 2767 /// First we need to examine replaces. For any replace op: 2768 /// 2769 /// 1. wipe out any insertions before op within that range. 2770 /// 2. Drop any replace op before that is contained completely within 2771 /// that range. 2772 /// 3. Throw exception upon boundary overlap with any previous replace. 2773 /// 2774 /// Then we can deal with inserts: 2775 /// 2776 /// 1. for any inserts to same index, combine even if not adjacent. 2777 /// 2. for any prior replace with same left boundary, combine this 2778 /// insert with replace and delete this replace. 2779 /// 3. throw exception if index in same range as previous replace 2780 /// 2781 /// Don't actually delete; make op null in list. Easier to walk list. 2782 /// Later we can throw as we add to index -> op map. 2783 /// 2784 /// Note that I.2 R.2-2 will wipe out I.2 even though, technically, the 2785 /// inserted stuff would be before the replace range. But, if you 2786 /// add tokens in front of a method body '{' and then delete the method 2787 /// body, I think the stuff before the '{' you added should disappear too. 2788 /// </remarks> 2789 function ReduceToSingleOperationPerIndex( 2790 const Rewrites: IList<IRewriteOperation>): IDictionary<Integer, IRewriteOperation>; 2791 2792 function GetKindOfOps(const Rewrites: IList<IRewriteOperation>; 2793 const Kind: TGUID): IList<IRewriteOperation>; overload; 2794 /// <summary> 2795 /// Get all operations before an index of a particular kind 2796 /// </summary> 2797 function GetKindOfOps(const Rewrites: IList<IRewriteOperation>; 2798 const Kind: TGUID; const Before: Integer): IList<IRewriteOperation>; overload; 2799 2800 function CatOpText(const A, B: IANTLRInterface): IANTLRInterface; 2801 public 2802 constructor Create; overload; 2803 constructor Create(const ATokenSource: ITokenSource); overload; 2804 constructor Create(const ATokenSource: ITokenSource; 2805 const AChannel: Integer); overload; 2806 constructor Create(const ALexer: ILexer); overload; 2807 constructor Create(const ALexer: ILexer; 2808 const AChannel: Integer); overload; 2809 2810 function ToString: String; overload; override; 2811 end; 2812 2813{ These functions return X or, if X = nil, an empty default instance } 2814function Def(const X: IToken): IToken; overload; 2815function Def(const X: IRuleReturnScope): IRuleReturnScope; overload; 2816 2817implementation 2818 2819uses 2820 StrUtils, 2821 Math, 2822 Antlr.Runtime.Tree; 2823 2824{ ERecognitionException } 2825 2826constructor ERecognitionException.Create; 2827begin 2828 Create('', nil); 2829end; 2830 2831constructor ERecognitionException.Create(const AMessage: String); 2832begin 2833 Create(AMessage, nil); 2834end; 2835 2836constructor ERecognitionException.Create(const AInput: IIntStream); 2837begin 2838 Create('', AInput); 2839end; 2840 2841constructor ERecognitionException.Create(const AMessage: String; 2842 const AInput: IIntStream); 2843var 2844 TokenStream: ITokenStream; 2845 CharStream: ICharStream; 2846begin 2847 inherited Create(AMessage); 2848 FInput := AInput; 2849 FIndex := AInput.Index; 2850 2851 if Supports(AInput, ITokenStream, TokenStream) then 2852 begin 2853 FToken := TokenStream.LT(1); 2854 FLine := FToken.Line; 2855 FCharPositionInLine := FToken.CharPositionInLine; 2856 end; 2857 2858 if Supports(AInput, ITreeNodeStream) then 2859 ExtractInformationFromTreeNodeStream(AInput) 2860 else 2861 begin 2862 if Supports(AInput, ICharStream, CharStream) then 2863 begin 2864 FC := AInput.LA(1); 2865 FLine := CharStream.Line; 2866 FCharPositionInLine := CharStream.CharPositionInLine; 2867 end 2868 else 2869 FC := AInput.LA(1); 2870 end; 2871end; 2872 2873procedure ERecognitionException.ExtractInformationFromTreeNodeStream( 2874 const Input: IIntStream); 2875var 2876 Nodes: ITreeNodeStream; 2877 Adaptor: ITreeAdaptor; 2878 Payload, PriorPayload: IToken; 2879 I, NodeType: Integer; 2880 PriorNode: IANTLRInterface; 2881 Tree: ITree; 2882 Text: String; 2883 CommonTree: ICommonTree; 2884begin 2885 Nodes := Input as ITreeNodeStream; 2886 FNode := Nodes.LT(1); 2887 Adaptor := Nodes.TreeAdaptor; 2888 Payload := Adaptor.GetToken(FNode); 2889 2890 if Assigned(Payload) then 2891 begin 2892 FToken := Payload; 2893 if (Payload.Line <= 0) then 2894 begin 2895 // imaginary node; no line/pos info; scan backwards 2896 I := -1; 2897 PriorNode := Nodes.LT(I); 2898 while Assigned(PriorNode) do 2899 begin 2900 PriorPayload := Adaptor.GetToken(PriorNode); 2901 if Assigned(PriorPayload) and (PriorPayload.Line > 0) then 2902 begin 2903 // we found the most recent real line / pos info 2904 FLine := PriorPayload.Line; 2905 FCharPositionInLine := PriorPayload.CharPositionInLine; 2906 FApproximateLineInfo := True; 2907 Break; 2908 end; 2909 Dec(I); 2910 PriorNode := Nodes.LT(I) 2911 end; 2912 end 2913 else 2914 begin 2915 // node created from real token 2916 FLine := Payload.Line; 2917 FCharPositionInLine := Payload.CharPositionInLine; 2918 end; 2919 end else 2920 if Supports(FNode, ITree, Tree) then 2921 begin 2922 FLine := Tree.Line; 2923 FCharPositionInLine := Tree.CharPositionInLine; 2924 if Supports(FNode, ICommonTree, CommonTree) then 2925 FToken := CommonTree.Token; 2926 end 2927 else 2928 begin 2929 NodeType := Adaptor.GetNodeType(FNode); 2930 Text := Adaptor.GetNodeText(FNode); 2931 FToken := TCommonToken.Create(NodeType, Text); 2932 end; 2933end; 2934 2935function ERecognitionException.GetUnexpectedType: Integer; 2936var 2937 Nodes: ITreeNodeStream; 2938 Adaptor: ITreeAdaptor; 2939begin 2940 if Supports(FInput, ITokenStream) then 2941 Result := FToken.TokenType 2942 else 2943 if Supports(FInput, ITreeNodeStream, Nodes) then 2944 begin 2945 Adaptor := Nodes.TreeAdaptor; 2946 Result := Adaptor.GetNodeType(FNode); 2947 end else 2948 Result := FC; 2949end; 2950 2951{ EMismatchedTokenException } 2952 2953constructor EMismatchedTokenException.Create(const AExpecting: Integer; 2954 const AInput: IIntStream); 2955begin 2956 inherited Create(AInput); 2957 FExpecting := AExpecting; 2958end; 2959 2960function EMismatchedTokenException.ToString: String; 2961begin 2962 Result := 'MismatchedTokenException(' + IntToStr(UnexpectedType) 2963 + '!=' + IntToStr(Expecting) + ')'; 2964 2965end; 2966 2967{ EUnwantedTokenException } 2968 2969function EUnwantedTokenException.GetUnexpectedToken: IToken; 2970begin 2971 Result := FToken; 2972end; 2973 2974function EUnwantedTokenException.ToString: String; 2975var 2976 Exp: String; 2977begin 2978 if (Expecting = TToken.INVALID_TOKEN_TYPE) then 2979 Exp := '' 2980 else 2981 Exp := ', expected ' + IntToStr(Expecting); 2982 if (Token = nil) then 2983 Result := 'UnwantedTokenException(found=nil' + Exp + ')' 2984 else 2985 Result := 'UnwantedTokenException(found=' + Token.Text + Exp + ')' 2986end; 2987 2988{ EMissingTokenException } 2989 2990constructor EMissingTokenException.Create(const AExpecting: Integer; 2991 const AInput: IIntStream; const AInserted: IANTLRInterface); 2992begin 2993 inherited Create(AExpecting, AInput); 2994 FInserted := AInserted; 2995end; 2996 2997function EMissingTokenException.GetMissingType: Integer; 2998begin 2999 Result := Expecting; 3000end; 3001 3002function EMissingTokenException.ToString: String; 3003begin 3004 if Assigned(FInserted) and Assigned(FToken) then 3005 Result := 'MissingTokenException(inserted ' + FInserted.ToString 3006 + ' at ' + FToken.Text + ')' 3007 else 3008 if Assigned(FToken) then 3009 Result := 'MissingTokenException(at ' + FToken.Text + ')' 3010 else 3011 Result := 'MissingTokenException'; 3012end; 3013 3014{ EMismatchedTreeNodeException } 3015 3016constructor EMismatchedTreeNodeException.Create(const AExpecting: Integer; 3017 const AInput: IIntStream); 3018begin 3019 inherited Create(AInput); 3020 FExpecting := AExpecting; 3021end; 3022 3023function EMismatchedTreeNodeException.ToString: String; 3024begin 3025 Result := 'MismatchedTreeNodeException(' + IntToStr(UnexpectedType) 3026 + '!=' + IntToStr(Expecting) + ')'; 3027end; 3028 3029{ ENoViableAltException } 3030 3031constructor ENoViableAltException.Create( 3032 const AGrammarDecisionDescription: String; const ADecisionNumber, 3033 AStateNumber: Integer; const AInput: IIntStream); 3034begin 3035 inherited Create(AInput); 3036 FGrammarDecisionDescription := AGrammarDecisionDescription; 3037 FDecisionNumber := ADecisionNumber; 3038 FStateNumber := AStateNumber; 3039end; 3040 3041function ENoViableAltException.ToString: String; 3042begin 3043 if Supports(Input, ICharStream) then 3044 Result := 'NoViableAltException(''' + Char(UnexpectedType) + '''@[' 3045 + FGrammarDecisionDescription + '])' 3046 else 3047 Result := 'NoViableAltException(''' + IntToStr(UnexpectedType) + '''@[' 3048 + FGrammarDecisionDescription + '])' 3049end; 3050 3051{ EEarlyExitException } 3052 3053constructor EEarlyExitException.Create(const ADecisionNumber: Integer; 3054 const AInput: IIntStream); 3055begin 3056 inherited Create(AInput); 3057 FDecisionNumber := ADecisionNumber; 3058end; 3059 3060{ EMismatchedSetException } 3061 3062constructor EMismatchedSetException.Create(const AExpecting: IBitSet; 3063 const AInput: IIntStream); 3064begin 3065 inherited Create(AInput); 3066 FExpecting := AExpecting; 3067end; 3068 3069function EMismatchedSetException.ToString: String; 3070begin 3071 Result := 'MismatchedSetException(' + IntToStr(UnexpectedType) 3072 + '!=' + Expecting.ToString + ')'; 3073end; 3074 3075{ EMismatchedNotSetException } 3076 3077function EMismatchedNotSetException.ToString: String; 3078begin 3079 Result := 'MismatchedNotSetException(' + IntToStr(UnexpectedType) 3080 + '!=' + Expecting.ToString + ')'; 3081end; 3082 3083{ EFailedPredicateException } 3084 3085constructor EFailedPredicateException.Create(const AInput: IIntStream; 3086 const ARuleName, APredicateText: String); 3087begin 3088 inherited Create(AInput); 3089 FRuleName := ARuleName; 3090 FPredicateText := APredicateText; 3091end; 3092 3093function EFailedPredicateException.ToString: String; 3094begin 3095 Result := 'FailedPredicateException(' + FRuleName + ',{' + FPredicateText + '}?)'; 3096end; 3097 3098{ EMismatchedRangeException } 3099 3100constructor EMismatchedRangeException.Create(const AA, AB: Integer; 3101 const AInput: IIntStream); 3102begin 3103 inherited Create(FInput); 3104 FA := AA; 3105 FB := AB; 3106end; 3107 3108function EMismatchedRangeException.ToString: String; 3109begin 3110 Result := 'MismatchedNotSetException(' + IntToStr(UnexpectedType) 3111 + ' not in [' + IntToStr(FA)+ ',' + IntToStr(FB) + '])'; 3112end; 3113 3114{ TCharStreamState } 3115 3116function TCharStreamState.GetCharPositionInLine: Integer; 3117begin 3118 Result := FCharPositionInLine; 3119end; 3120 3121function TCharStreamState.GetLine: Integer; 3122begin 3123 Result := FLine; 3124end; 3125 3126function TCharStreamState.GetP: Integer; 3127begin 3128 Result := FP; 3129end; 3130 3131procedure TCharStreamState.SetCharPositionInLine(const Value: Integer); 3132begin 3133 FCharPositionInLine := Value; 3134end; 3135 3136procedure TCharStreamState.SetLine(const Value: Integer); 3137begin 3138 FLine := Value; 3139end; 3140 3141procedure TCharStreamState.SetP(const Value: Integer); 3142begin 3143 FP := Value; 3144end; 3145 3146{ TANTLRStringStream } 3147 3148constructor TANTLRStringStream.Create(const AInput: String); 3149begin 3150 inherited Create; 3151 FLine := 1; 3152 FOwnsData := True; 3153 FN := Length(AInput); 3154 if (FN > 0) then 3155 begin 3156 GetMem(FData,FN * SizeOf(Char)); 3157 Move(AInput[1],FData^,FN * SizeOf(Char)); 3158 end; 3159end; 3160 3161procedure TANTLRStringStream.Consume; 3162begin 3163 if (FP < FN) then 3164 begin 3165 Inc(FCharPositionInLine); 3166 if (FData[FP] = #10) then 3167 begin 3168 Inc(FLine); 3169 FCharPositionInLine := 0; 3170 end; 3171 Inc(FP); 3172 end; 3173end; 3174 3175constructor TANTLRStringStream.Create(const AData: PChar; 3176 const ANumberOfActualCharsInArray: Integer); 3177begin 3178 inherited Create; 3179 FLine := 1; 3180 FOwnsData := False; 3181 FData := AData; 3182 FN := ANumberOfActualCharsInArray; 3183end; 3184 3185constructor TANTLRStringStream.Create; 3186begin 3187 inherited Create; 3188 FLine := 1; 3189end; 3190 3191destructor TANTLRStringStream.Destroy; 3192begin 3193 if (FOwnsData) then 3194 FreeMem(FData); 3195 inherited; 3196end; 3197 3198function TANTLRStringStream.GetCharPositionInLine: Integer; 3199begin 3200 Result := FCharPositionInLine; 3201end; 3202 3203function TANTLRStringStream.GetLine: Integer; 3204begin 3205 Result := FLine; 3206end; 3207 3208function TANTLRStringStream.GetSourceName: String; 3209begin 3210 Result := FName; 3211end; 3212 3213function TANTLRStringStream.Index: Integer; 3214begin 3215 Result := FP; 3216end; 3217 3218function TANTLRStringStream.LA(I: Integer): Integer; 3219begin 3220 if (I = 0) then 3221 Result := 0 // undefined 3222 else begin 3223 if (I < 0) then 3224 begin 3225 Inc(I); // e.g., translate LA(-1) to use offset i=0; then data[p+0-1] 3226 if ((FP + I - 1) < 0) then 3227 begin 3228 Result := Integer(cscEOF); 3229 Exit; 3230 end; 3231 end; 3232 3233 if ((FP + I - 1) >= FN) then 3234 Result := Integer(cscEOF) 3235 else 3236 Result := Integer(FData[FP + I - 1]); 3237 end; 3238end; 3239 3240function TANTLRStringStream.LAChar(I: Integer): Char; 3241begin 3242 Result := Char(LA(I)); 3243end; 3244 3245function TANTLRStringStream.LT(const I: Integer): Integer; 3246begin 3247 Result := LA(I); 3248end; 3249 3250function TANTLRStringStream.Mark: Integer; 3251var 3252 State: ICharStreamState; 3253begin 3254 if (FMarkers = nil) then 3255 begin 3256 FMarkers := TList<ICharStreamState>.Create; 3257 FMarkers.Add(nil); // depth 0 means no backtracking, leave blank 3258 end; 3259 3260 Inc(FMarkDepth); 3261 if (FMarkDepth >= FMarkers.Count) then 3262 begin 3263 State := TCharStreamState.Create; 3264 FMarkers.Add(State); 3265 end 3266 else 3267 State := FMarkers[FMarkDepth]; 3268 3269 State.P := FP; 3270 State.Line := FLine; 3271 State.CharPositionInLine := FCharPositionInLine; 3272 FLastMarker := FMarkDepth; 3273 Result := FMarkDepth; 3274end; 3275 3276procedure TANTLRStringStream.Release(const Marker: Integer); 3277begin 3278 // unwind any other markers made after m and release m 3279 FMarkDepth := Marker; 3280 // release this marker 3281 Dec(FMarkDepth); 3282end; 3283 3284procedure TANTLRStringStream.Reset; 3285begin 3286 FP := 0; 3287 FLine := 1; 3288 FCharPositionInLine := 0; 3289 FMarkDepth := 0; 3290end; 3291 3292procedure TANTLRStringStream.Rewind(const Marker: Integer); 3293var 3294 State: ICharStreamState; 3295begin 3296 State := FMarkers[Marker]; 3297 // restore stream state 3298 Seek(State.P); 3299 FLine := State.Line; 3300 FCharPositionInLine := State.CharPositionInLine; 3301 Release(Marker); 3302end; 3303 3304procedure TANTLRStringStream.Rewind; 3305begin 3306 Rewind(FLastMarker); 3307end; 3308 3309procedure TANTLRStringStream.Seek(const Index: Integer); 3310begin 3311 if (Index <= FP) then 3312 FP := Index // just jump; don't update stream state (line, ...) 3313 else begin 3314 // seek forward, consume until p hits index 3315 while (FP < Index) do 3316 Consume; 3317 end; 3318end; 3319 3320procedure TANTLRStringStream.SetCharPositionInLine(const Value: Integer); 3321begin 3322 FCharPositionInLine := Value; 3323end; 3324 3325procedure TANTLRStringStream.SetLine(const Value: Integer); 3326begin 3327 FLine := Value; 3328end; 3329 3330function TANTLRStringStream.Size: Integer; 3331begin 3332 Result := FN; 3333end; 3334 3335function TANTLRStringStream.Substring(const Start, Stop: Integer): String; 3336begin 3337 Result := Copy(FData, Start + 1, Stop - Start + 1); 3338end; 3339 3340{ TANTLRFileStream } 3341 3342constructor TANTLRFileStream.Create(const AFileName: String); 3343begin 3344 Create(AFilename,TEncoding.Default); 3345end; 3346 3347constructor TANTLRFileStream.Create(const AFileName: String; 3348 const AEncoding: TEncoding); 3349begin 3350 inherited Create; 3351 FFileName := AFileName; 3352 Load(FFileName, AEncoding); 3353end; 3354 3355function TANTLRFileStream.GetSourceName: String; 3356begin 3357 Result := FFileName; 3358end; 3359 3360procedure TANTLRFileStream.Load(const FileName: String; 3361 const Encoding: TEncoding); 3362var 3363 FR: TStreamReader; 3364 S: String; 3365begin 3366 if (FFileName <> '') then 3367 begin 3368 if (Encoding = nil) then 3369 FR := TStreamReader.Create(FileName,TEncoding.Default) 3370 else 3371 FR := TStreamReader.Create(FileName,Encoding); 3372 3373 try 3374 if (FOwnsData) then 3375 begin 3376 FreeMem(FData); 3377 FData := nil; 3378 end; 3379 3380 FOwnsData := True; 3381 S := FR.ReadToEnd; 3382 FN := Length(S); 3383 if (FN > 0) then 3384 begin 3385 GetMem(FData,FN * SizeOf(Char)); 3386 Move(S[1],FData^,FN * SizeOf(Char)); 3387 end; 3388 finally 3389 FR.Free; 3390 end; 3391 end; 3392end; 3393 3394{ TBitSet } 3395 3396class function TBitSet.BitSetOf(const El: Integer): IBitSet; 3397begin 3398 Result := TBitSet.Create(El + 1); 3399 Result.Add(El); 3400end; 3401 3402class function TBitSet.BitSetOf(const A, B: Integer): IBitSet; 3403begin 3404 Result := TBitSet.Create(Max(A,B) + 1); 3405 Result.Add(A); 3406 Result.Add(B); 3407end; 3408 3409class function TBitSet.BitSetOf(const A, B, C: Integer): IBitSet; 3410begin 3411 Result := TBitSet.Create; 3412 Result.Add(A); 3413 Result.Add(B); 3414 Result.Add(C); 3415end; 3416 3417class function TBitSet.BitSetOf(const A, B, C, D: Integer): IBitSet; 3418begin 3419 Result := TBitSet.Create; 3420 Result.Add(A); 3421 Result.Add(B); 3422 Result.Add(C); 3423 Result.Add(D); 3424end; 3425 3426procedure TBitSet.Add(const El: Integer); 3427var 3428 N: Integer; 3429begin 3430 N := WordNumber(El); 3431 if (N >= Length(FBits)) then 3432 GrowToInclude(El); 3433 FBits[N] := FBits[N] or BitMask(El); 3434end; 3435 3436class function TBitSet.BitMask(const BitNumber: Integer): UInt64; 3437var 3438 BitPosition: Integer; 3439begin 3440 BitPosition := BitNumber and MOD_MASK; 3441 Result := UInt64(1) shl BitPosition; 3442end; 3443 3444function TBitSet.BitSetOr(const A: IBitSet): IBitSet; 3445begin 3446 Result := Clone as IBitSet; 3447 Result.OrInPlace(A); 3448end; 3449 3450function TBitSet.Clone: IANTLRInterface; 3451var 3452 BS: TBitSet; 3453begin 3454 BS := TBitSet.Create; 3455 Result := BS; 3456 SetLength(BS.FBits,Length(FBits)); 3457 if (Length(FBits) > 0) then 3458 Move(FBits[0],BS.FBits[0],Length(FBits) * SizeOf(UInt64)); 3459end; 3460 3461constructor TBitSet.Create; 3462begin 3463 Create(BITS); 3464end; 3465 3466constructor TBitSet.Create(const ABits: array of UInt64); 3467begin 3468 inherited Create; 3469 SetLength(FBits, Length(ABits)); 3470 if (Length(ABits) > 0) then 3471 Move(ABits[0], FBits[0], Length(ABits) * SizeOf(UInt64)); 3472end; 3473 3474constructor TBitSet.Create(const AItems: IList<Integer>); 3475var 3476 V: Integer; 3477begin 3478 Create(BITS); 3479 for V in AItems do 3480 Add(V); 3481end; 3482 3483constructor TBitSet.Create(const ANBits: Integer); 3484begin 3485 inherited Create; 3486 SetLength(FBits,((ANBits - 1) shr LOG_BITS) + 1); 3487end; 3488 3489function TBitSet.Equals(Obj: TObject): Boolean; 3490var 3491 OtherSet: TBitSet absolute Obj; 3492 I, N: Integer; 3493begin 3494 Result := False; 3495 if (Obj = nil) or (not (Obj is TBitSet)) then 3496 Exit; 3497 3498 N := Min(Length(FBits), Length(OtherSet.FBits)); 3499 3500 // for any bits in common, compare 3501 for I := 0 to N - 1 do 3502 begin 3503 if (FBits[I] <> OtherSet.FBits[I]) then 3504 Exit; 3505 end; 3506 3507 // make sure any extra bits are off 3508 if (Length(FBits) > N) then 3509 begin 3510 for I := N + 1 to Length(FBits) - 1 do 3511 begin 3512 if (FBits[I] <> 0) then 3513 Exit; 3514 end; 3515 end 3516 else 3517 if (Length(OtherSet.FBits) > N) then 3518 begin 3519 for I := N + 1 to Length(OtherSet.FBits) - 1 do 3520 begin 3521 if (OtherSet.FBits[I] <> 0) then 3522 Exit; 3523 end; 3524 end; 3525 3526 Result := True; 3527end; 3528 3529function TBitSet.GetIsNil: Boolean; 3530var 3531 I: Integer; 3532begin 3533 for I := Length(FBits) - 1 downto 0 do 3534 if (FBits[I] <> 0) then 3535 begin 3536 Result := False; 3537 Exit; 3538 end; 3539 Result := True; 3540end; 3541 3542procedure TBitSet.GrowToInclude(const Bit: Integer); 3543var 3544 NewSize: Integer; 3545begin 3546 NewSize := Max(Length(FBits) shl 1,NumWordsToHold(Bit)); 3547 SetLength(FBits,NewSize); 3548end; 3549 3550function TBitSet.LengthInLongWords: Integer; 3551begin 3552 Result := Length(FBits); 3553end; 3554 3555function TBitSet.Member(const El: Integer): Boolean; 3556var 3557 N: Integer; 3558begin 3559 if (El < 0) then 3560 Result := False 3561 else 3562 begin 3563 N := WordNumber(El); 3564 if (N >= Length(FBits)) then 3565 Result := False 3566 else 3567 Result := ((FBits[N] and BitMask(El)) <> 0); 3568 end; 3569end; 3570 3571function TBitSet.NumBits: Integer; 3572begin 3573 Result := Length(FBits) shl LOG_BITS; 3574end; 3575 3576class function TBitSet.NumWordsToHold(const El: Integer): Integer; 3577begin 3578 Result := (El shr LOG_BITS) + 1; 3579end; 3580 3581procedure TBitSet.OrInPlace(const A: IBitSet); 3582var 3583 I, M: Integer; 3584 ABits: TUInt64Array; 3585begin 3586 if Assigned(A) then 3587 begin 3588 // If this is smaller than a, grow this first 3589 if (A.LengthInLongWords > Length(FBits)) then 3590 SetLength(FBits,A.LengthInLongWords); 3591 M := Min(Length(FBits), A.LengthInLongWords); 3592 ABits := A.ToPackedArray; 3593 for I := M - 1 downto 0 do 3594 FBits[I] := FBits[I] or ABits[I]; 3595 end; 3596end; 3597 3598procedure TBitSet.Remove(const El: Integer); 3599var 3600 N: Integer; 3601begin 3602 N := WordNumber(El); 3603 if (N < Length(FBits)) then 3604 FBits[N] := (FBits[N] and not BitMask(El)); 3605end; 3606 3607function TBitSet.Size: Integer; 3608var 3609 I, Bit: Integer; 3610 W: UInt64; 3611begin 3612 Result := 0; 3613 for I := Length(FBits) - 1 downto 0 do 3614 begin 3615 W := FBits[I]; 3616 if (W <> 0) then 3617 begin 3618 for Bit := BITS - 1 downto 0 do 3619 begin 3620 if ((W and (UInt64(1) shl Bit)) <> 0) then 3621 Inc(Result); 3622 end; 3623 end; 3624 end; 3625end; 3626 3627function TBitSet.ToArray: TIntegerArray; 3628var 3629 I, En: Integer; 3630begin 3631 SetLength(Result,Size); 3632 En := 0; 3633 for I := 0 to (Length(FBits) shl LOG_BITS) - 1 do 3634 begin 3635 if Member(I) then 3636 begin 3637 Result[En] := I; 3638 Inc(En); 3639 end; 3640 end; 3641end; 3642 3643function TBitSet.ToPackedArray: TUInt64Array; 3644begin 3645 Result := FBits; 3646end; 3647 3648function TBitSet.ToString: String; 3649begin 3650 Result := ToString(nil); 3651end; 3652 3653function TBitSet.ToString(const TokenNames: TStringArray): String; 3654var 3655 Buf: TStringBuilder; 3656 I: Integer; 3657 HavePrintedAnElement: Boolean; 3658begin 3659 HavePrintedAnElement := False; 3660 Buf := TStringBuilder.Create; 3661 try 3662 Buf.Append('{'); 3663 for I := 0 to (Length(FBits) shl LOG_BITS) - 1 do 3664 begin 3665 if Member(I) then 3666 begin 3667 if (I > 0) and HavePrintedAnElement then 3668 Buf.Append(','); 3669 if Assigned(TokenNames) then 3670 Buf.Append(TokenNames[I]) 3671 else 3672 Buf.Append(I); 3673 HavePrintedAnElement := True; 3674 end; 3675 end; 3676 Buf.Append('}'); 3677 Result := Buf.ToString; 3678 finally 3679 Buf.Free; 3680 end; 3681end; 3682 3683class function TBitSet.WordNumber(const Bit: Integer): Integer; 3684begin 3685 Result := Bit shr LOG_BITS; // Bit / BITS 3686end; 3687 3688{ TRecognizerSharedState } 3689 3690constructor TRecognizerSharedState.Create; 3691var 3692 I: Integer; 3693begin 3694 inherited; 3695 SetLength(FFollowing,TBaseRecognizer.INITIAL_FOLLOW_STACK_SIZE); 3696 for I := 0 to TBaseRecognizer.INITIAL_FOLLOW_STACK_SIZE - 1 do 3697 FFollowing[I] := TBitSet.Create; 3698 FFollowingStackPointer := -1; 3699 FLastErrorIndex := -1; 3700 FTokenStartCharIndex := -1; 3701end; 3702 3703function TRecognizerSharedState.GetBacktracking: Integer; 3704begin 3705 Result := FBacktracking; 3706end; 3707 3708function TRecognizerSharedState.GetChannel: Integer; 3709begin 3710 Result := FChannel; 3711end; 3712 3713function TRecognizerSharedState.GetErrorRecovery: Boolean; 3714begin 3715 Result := FErrorRecovery; 3716end; 3717 3718function TRecognizerSharedState.GetFailed: Boolean; 3719begin 3720 Result := FFailed; 3721end; 3722 3723function TRecognizerSharedState.GetFollowing: TBitSetArray; 3724begin 3725 Result := FFollowing; 3726end; 3727 3728function TRecognizerSharedState.GetFollowingStackPointer: Integer; 3729begin 3730 Result := FFollowingStackPointer; 3731end; 3732 3733function TRecognizerSharedState.GetLastErrorIndex: Integer; 3734begin 3735 Result := FLastErrorIndex; 3736end; 3737 3738function TRecognizerSharedState.GetRuleMemo: TDictionaryArray<Integer, Integer>; 3739begin 3740 Result := FRuleMemo; 3741end; 3742 3743function TRecognizerSharedState.GetRuleMemoCount: Integer; 3744begin 3745 Result := Length(FRuleMemo); 3746end; 3747 3748function TRecognizerSharedState.GetSyntaxErrors: Integer; 3749begin 3750 Result := FSyntaxErrors; 3751end; 3752 3753function TRecognizerSharedState.GetText: String; 3754begin 3755 Result := FText; 3756end; 3757 3758function TRecognizerSharedState.GetToken: IToken; 3759begin 3760 Result := FToken; 3761end; 3762 3763function TRecognizerSharedState.GetTokenStartCharIndex: Integer; 3764begin 3765 Result := FTokenStartCharIndex; 3766end; 3767 3768function TRecognizerSharedState.GetTokenStartCharPositionInLine: Integer; 3769begin 3770 Result := FTokenStartCharPositionInLine; 3771end; 3772 3773function TRecognizerSharedState.GetTokenStartLine: Integer; 3774begin 3775 Result := FTokenStartLine; 3776end; 3777 3778function TRecognizerSharedState.GetTokenType: Integer; 3779begin 3780 Result := FTokenType; 3781end; 3782 3783procedure TRecognizerSharedState.SetBacktracking(const Value: Integer); 3784begin 3785 FBacktracking := Value; 3786end; 3787 3788procedure TRecognizerSharedState.SetChannel(const Value: Integer); 3789begin 3790 FChannel := Value; 3791end; 3792 3793procedure TRecognizerSharedState.SetErrorRecovery(const Value: Boolean); 3794begin 3795 FErrorRecovery := Value; 3796end; 3797 3798procedure TRecognizerSharedState.SetFailed(const Value: Boolean); 3799begin 3800 FFailed := Value; 3801end; 3802 3803procedure TRecognizerSharedState.SetFollowing(const Value: TBitSetArray); 3804begin 3805 FFollowing := Value; 3806end; 3807 3808procedure TRecognizerSharedState.SetFollowingStackPointer(const Value: Integer); 3809begin 3810 FFollowingStackPointer := Value; 3811end; 3812 3813procedure TRecognizerSharedState.SetLastErrorIndex(const Value: Integer); 3814begin 3815 FLastErrorIndex := Value; 3816end; 3817 3818procedure TRecognizerSharedState.SetRuleMemoCount(const Value: Integer); 3819begin 3820 SetLength(FRuleMemo, Value); 3821end; 3822 3823procedure TRecognizerSharedState.SetSyntaxErrors(const Value: Integer); 3824begin 3825 FSyntaxErrors := Value; 3826end; 3827 3828procedure TRecognizerSharedState.SetText(const Value: String); 3829begin 3830 FText := Value; 3831end; 3832 3833procedure TRecognizerSharedState.SetToken(const Value: IToken); 3834begin 3835 FToken := Value; 3836end; 3837 3838procedure TRecognizerSharedState.SetTokenStartCharIndex(const Value: Integer); 3839begin 3840 FTokenStartCharIndex := Value; 3841end; 3842 3843procedure TRecognizerSharedState.SetTokenStartCharPositionInLine( 3844 const Value: Integer); 3845begin 3846 FTokenStartCharPositionInLine := Value; 3847end; 3848 3849procedure TRecognizerSharedState.SetTokenStartLine(const Value: Integer); 3850begin 3851 FTokenStartLine := Value; 3852end; 3853 3854procedure TRecognizerSharedState.SetTokenType(const Value: Integer); 3855begin 3856 FTokenType := Value; 3857end; 3858 3859{ TCommonToken } 3860 3861constructor TCommonToken.Create; 3862begin 3863 inherited; 3864 FChannel := TToken.DEFAULT_CHANNEL; 3865 FCharPositionInLine := -1; 3866 FIndex := -1; 3867end; 3868 3869constructor TCommonToken.Create(const ATokenType: Integer); 3870begin 3871 Create; 3872 FTokenType := ATokenType; 3873end; 3874 3875constructor TCommonToken.Create(const AInput: ICharStream; const ATokenType, 3876 AChannel, AStart, AStop: Integer); 3877begin 3878 Create; 3879 FInput := AInput; 3880 FTokenType := ATokenType; 3881 FChannel := AChannel; 3882 FStart := AStart; 3883 FStop := AStop; 3884end; 3885 3886constructor TCommonToken.Create(const ATokenType: Integer; const AText: String); 3887begin 3888 Create; 3889 FTokenType := ATokenType; 3890 FChannel := TToken.DEFAULT_CHANNEL; 3891 FText := AText; 3892end; 3893 3894function TCommonToken.GetChannel: Integer; 3895begin 3896 Result := FChannel; 3897end; 3898 3899function TCommonToken.GetCharPositionInLine: Integer; 3900begin 3901 Result := FCharPositionInLine; 3902end; 3903 3904function TCommonToken.GetInputStream: ICharStream; 3905begin 3906 Result := FInput; 3907end; 3908 3909function TCommonToken.GetLine: Integer; 3910begin 3911 Result := FLine; 3912end; 3913 3914function TCommonToken.GetStartIndex: Integer; 3915begin 3916 Result := FStart; 3917end; 3918 3919function TCommonToken.GetStopIndex: Integer; 3920begin 3921 Result := FStop; 3922end; 3923 3924function TCommonToken.GetText: String; 3925begin 3926 if (FText <> '') then 3927 Result := FText 3928 else 3929 if (FInput = nil) then 3930 Result := '' 3931 else 3932 Result := FInput.Substring(FStart, FStop); 3933end; 3934 3935function TCommonToken.GetTokenIndex: Integer; 3936begin 3937 Result := FIndex; 3938end; 3939 3940function TCommonToken.GetTokenType: Integer; 3941begin 3942 Result := FTokenType; 3943end; 3944 3945procedure TCommonToken.SetChannel(const Value: Integer); 3946begin 3947 FChannel := Value; 3948end; 3949 3950procedure TCommonToken.SetCharPositionInLine(const Value: Integer); 3951begin 3952 FCharPositionInLine := Value; 3953end; 3954 3955procedure TCommonToken.SetInputStream(const Value: ICharStream); 3956begin 3957 FInput := Value; 3958end; 3959 3960procedure TCommonToken.SetLine(const Value: Integer); 3961begin 3962 FLine := Value; 3963end; 3964 3965procedure TCommonToken.SetStartIndex(const Value: Integer); 3966begin 3967 FStart := Value; 3968end; 3969 3970procedure TCommonToken.SetStopIndex(const Value: Integer); 3971begin 3972 FStop := Value; 3973end; 3974 3975procedure TCommonToken.SetText(const Value: String); 3976begin 3977 (* Override the text for this token. The property getter 3978 * will return this text rather than pulling from the buffer. 3979 * Note that this does not mean that start/stop indexes are 3980 * not valid. It means that the input was converted to a new 3981 * string in the token object. 3982 *) 3983 FText := Value; 3984end; 3985 3986procedure TCommonToken.SetTokenIndex(const Value: Integer); 3987begin 3988 FIndex := Value; 3989end; 3990 3991procedure TCommonToken.SetTokenType(const Value: Integer); 3992begin 3993 FTokenType := Value; 3994end; 3995 3996function TCommonToken.ToString: String; 3997var 3998 ChannelStr, Txt: String; 3999begin 4000 if (FChannel > 0) then 4001 ChannelStr := ',channel=' + IntToStr(FChannel) 4002 else 4003 ChannelStr := ''; 4004 4005 Txt := GetText; 4006 if (Txt <> '') then 4007 begin 4008 Txt := ReplaceStr(Txt,#10,'\n'); 4009 Txt := ReplaceStr(Txt,#13,'\r'); 4010 Txt := ReplaceStr(Txt,#9,'\t'); 4011 end else 4012 Txt := '<no text>'; 4013 4014 Result := Format('[@%d,%d:%d=''%s'',<%d>%s,%d:%d]', 4015 [FIndex,FStart,FStop,Txt,FTokenType,ChannelStr,FLine,FCharPositionInLine]); 4016end; 4017 4018constructor TCommonToken.Create(const AOldToken: IToken); 4019var 4020 OldCommonToken: ICommonToken; 4021begin 4022 Create; 4023 FText := AOldToken.Text; 4024 FTokenType := AOldToken.TokenType; 4025 FLine := AOldToken.Line; 4026 FIndex := AOldToken.TokenIndex; 4027 FCharPositionInLine := AOldToken.CharPositionInLine; 4028 FChannel := AOldToken.Channel; 4029 if Supports(AOldToken, ICommonToken, OldCommonToken) then 4030 begin 4031 FStart := OldCommonToken.StartIndex; 4032 FStop := OldCommonToken.StopIndex; 4033 end; 4034end; 4035 4036{ TClassicToken } 4037 4038constructor TClassicToken.Create(const AOldToken: IToken); 4039begin 4040 inherited Create; 4041 FText := AOldToken.Text; 4042 FTokenType := AOldToken.TokenType; 4043 FLine := AOldToken.Line; 4044 FCharPositionInLine := AOldToken.CharPositionInLine; 4045 FChannel := AOldToken.Channel; 4046end; 4047 4048constructor TClassicToken.Create(const ATokenType: Integer); 4049begin 4050 inherited Create; 4051 FTokenType := ATokenType; 4052end; 4053 4054constructor TClassicToken.Create(const ATokenType: Integer; const AText: String; 4055 const AChannel: Integer); 4056begin 4057 inherited Create; 4058 FTokenType := ATokenType; 4059 FText := AText; 4060 FChannel := AChannel; 4061end; 4062 4063constructor TClassicToken.Create(const ATokenType: Integer; 4064 const AText: String); 4065begin 4066 inherited Create; 4067 FTokenType := ATokenType; 4068 FText := AText; 4069end; 4070 4071function TClassicToken.GetChannel: Integer; 4072begin 4073 Result := FChannel; 4074end; 4075 4076function TClassicToken.GetCharPositionInLine: Integer; 4077begin 4078 Result := FCharPositionInLine; 4079end; 4080 4081function TClassicToken.GetInputStream: ICharStream; 4082begin 4083 // No default implementation 4084 Result := nil; 4085end; 4086 4087function TClassicToken.GetLine: Integer; 4088begin 4089 Result := FLine; 4090end; 4091 4092function TClassicToken.GetText: String; 4093begin 4094 Result := FText; 4095end; 4096 4097function TClassicToken.GetTokenIndex: Integer; 4098begin 4099 Result := FIndex; 4100end; 4101 4102function TClassicToken.GetTokenType: Integer; 4103begin 4104 Result := FTokenType; 4105end; 4106 4107procedure TClassicToken.SetChannel(const Value: Integer); 4108begin 4109 FChannel := Value; 4110end; 4111 4112procedure TClassicToken.SetCharPositionInLine(const Value: Integer); 4113begin 4114 FCharPositionInLine := Value; 4115end; 4116 4117procedure TClassicToken.SetInputStream(const Value: ICharStream); 4118begin 4119 // No default implementation 4120end; 4121 4122procedure TClassicToken.SetLine(const Value: Integer); 4123begin 4124 FLine := Value; 4125end; 4126 4127procedure TClassicToken.SetText(const Value: String); 4128begin 4129 FText := Value; 4130end; 4131 4132procedure TClassicToken.SetTokenIndex(const Value: Integer); 4133begin 4134 FIndex := Value; 4135end; 4136 4137procedure TClassicToken.SetTokenType(const Value: Integer); 4138begin 4139 FTokenType := Value; 4140end; 4141 4142function TClassicToken.ToString: String; 4143var 4144 ChannelStr, Txt: String; 4145begin 4146 if (FChannel > 0) then 4147 ChannelStr := ',channel=' + IntToStr(FChannel) 4148 else 4149 ChannelStr := ''; 4150 Txt := FText; 4151 if (Txt <> '') then 4152 begin 4153 Txt := ReplaceStr(Txt,#10,'\n'); 4154 Txt := ReplaceStr(Txt,#13,'\r'); 4155 Txt := ReplaceStr(Txt,#9,'\t'); 4156 end else 4157 Txt := '<no text>'; 4158 4159 Result := Format('[@%d,''%s'',<%d>%s,%d:%d]', 4160 [FIndex,Txt,FTokenType,ChannelStr,FLine,FCharPositionInLine]); 4161end; 4162 4163{ TToken } 4164 4165class procedure TToken.Initialize; 4166begin 4167 EOF_TOKEN := TCommonToken.Create(EOF); 4168 INVALID_TOKEN := TCommonToken.Create(INVALID_TOKEN_TYPE); 4169 SKIP_TOKEN := TCommonToken.Create(INVALID_TOKEN_TYPE); 4170end; 4171 4172{ TBaseRecognizer } 4173 4174constructor TBaseRecognizer.Create; 4175begin 4176 inherited; 4177 FState := TRecognizerSharedState.Create; 4178end; 4179 4180function TBaseRecognizer.AlreadyParsedRule(const Input: IIntStream; 4181 const RuleIndex: Integer): Boolean; 4182var 4183 StopIndex: Integer; 4184begin 4185 StopIndex := GetRuleMemoization(RuleIndex, Input.Index); 4186 Result := (StopIndex <> MEMO_RULE_UNKNOWN); 4187 if Result then 4188 begin 4189 if (StopIndex = MEMO_RULE_FAILED) then 4190 FState.Failed := True 4191 else 4192 Input.Seek(StopIndex + 1); // jump to one past stop token 4193 end; 4194end; 4195 4196procedure TBaseRecognizer.BeginBacktrack(const Level: Integer); 4197begin 4198 // No defeault implementation 4199end; 4200 4201procedure TBaseRecognizer.BeginResync; 4202begin 4203 // No defeault implementation 4204end; 4205 4206procedure TBaseRecognizer.ConsumeUntil(const Input: IIntStream; 4207 const TokenType: Integer); 4208var 4209 TType: Integer; 4210begin 4211 TType := Input.LA(1); 4212 while (TType <> TToken.EOF) and (TType <> TokenType) do 4213 begin 4214 Input.Consume; 4215 TType := Input.LA(1); 4216 end; 4217end; 4218 4219function TBaseRecognizer.CombineFollows(const Exact: Boolean): IBitSet; 4220var 4221 I, Top: Integer; 4222 LocalFollowSet: IBitSet; 4223begin 4224 Top := FState.FollowingStackPointer; 4225 Result := TBitSet.Create; 4226 for I := Top downto 0 do 4227 begin 4228 LocalFollowSet := FState.Following[I]; 4229 Result.OrInPlace(LocalFollowSet); 4230 if (Exact) then 4231 begin 4232 // can we see end of rule? 4233 if LocalFollowSet.Member(TToken.EOR_TOKEN_TYPE) then 4234 begin 4235 // Only leave EOR in set if at top (start rule); this lets 4236 // us know if have to include follow(start rule); i.e., EOF 4237 if (I > 0) then 4238 Result.Remove(TToken.EOR_TOKEN_TYPE); 4239 end 4240 else 4241 // can't see end of rule, quit 4242 Break; 4243 end; 4244 end; 4245end; 4246 4247function TBaseRecognizer.ComputeContextSensitiveRuleFOLLOW: IBitSet; 4248begin 4249 Result := CombineFollows(True); 4250end; 4251 4252function TBaseRecognizer.ComputeErrorRecoverySet: IBitSet; 4253begin 4254 Result := CombineFollows(False); 4255end; 4256 4257procedure TBaseRecognizer.ConsumeUntil(const Input: IIntStream; 4258 const BitSet: IBitSet); 4259var 4260 TType: Integer; 4261begin 4262 TType := Input.LA(1); 4263 while (TType <> TToken.EOF) and (not BitSet.Member(TType)) do 4264 begin 4265 Input.Consume; 4266 TType := Input.LA(1); 4267 end; 4268end; 4269 4270constructor TBaseRecognizer.Create(const AState: IRecognizerSharedState); 4271begin 4272 if (AState = nil) then 4273 Create 4274 else 4275 begin 4276 inherited Create; 4277 FState := AState; 4278 end; 4279end; 4280 4281procedure TBaseRecognizer.DisplayRecognitionError( 4282 const TokenNames: TStringArray; const E: ERecognitionException); 4283var 4284 Hdr, Msg: String; 4285begin 4286 Hdr := GetErrorHeader(E); 4287 Msg := GetErrorMessage(E, TokenNames); 4288 EmitErrorMessage(Hdr + ' ' + Msg); 4289end; 4290 4291procedure TBaseRecognizer.EmitErrorMessage(const Msg: String); 4292begin 4293 WriteLn(Msg); 4294end; 4295 4296procedure TBaseRecognizer.EndBacktrack(const Level: Integer; 4297 const Successful: Boolean); 4298begin 4299 // No defeault implementation 4300end; 4301 4302procedure TBaseRecognizer.EndResync; 4303begin 4304 // No defeault implementation 4305end; 4306 4307function TBaseRecognizer.GetBacktrackingLevel: Integer; 4308begin 4309 Result := FState.Backtracking; 4310end; 4311 4312function TBaseRecognizer.GetCurrentInputSymbol( 4313 const Input: IIntStream): IANTLRInterface; 4314begin 4315 // No defeault implementation 4316 Result := nil; 4317end; 4318 4319function TBaseRecognizer.GetErrorHeader(const E: ERecognitionException): String; 4320begin 4321 Result := 'line ' + IntToStr(E.Line) + ':' + IntToStr(E.CharPositionInLine); 4322end; 4323 4324function TBaseRecognizer.GetErrorMessage(const E: ERecognitionException; 4325 const TokenNames: TStringArray): String; 4326var 4327 UTE: EUnwantedTokenException absolute E; 4328 MTE: EMissingTokenException absolute E; 4329 MMTE: EMismatchedTokenException absolute E; 4330 MTNE: EMismatchedTreeNodeException absolute E; 4331 NVAE: ENoViableAltException absolute E; 4332 EEE: EEarlyExitException absolute E; 4333 MSE: EMismatchedSetException absolute E; 4334 MNSE: EMismatchedNotSetException absolute E; 4335 FPE: EFailedPredicateException absolute E; 4336 TokenName: String; 4337begin 4338 Result := E.Message; 4339 if (E is EUnwantedTokenException) then 4340 begin 4341 if (UTE.Expecting = TToken.EOF) then 4342 TokenName := 'EOF' 4343 else 4344 TokenName := TokenNames[UTE.Expecting]; 4345 Result := 'extraneous input ' + GetTokenErrorDisplay(UTE.UnexpectedToken) 4346 + ' expecting ' + TokenName; 4347 end 4348 else 4349 if (E is EMissingTokenException) then 4350 begin 4351 if (MTE.Expecting = TToken.EOF) then 4352 TokenName := 'EOF' 4353 else 4354 TokenName := TokenNames[MTE.Expecting]; 4355 Result := 'missing ' + TokenName + ' at ' + GetTokenErrorDisplay(E.Token); 4356 end 4357 else 4358 if (E is EMismatchedTokenException) then 4359 begin 4360 if (MMTE.Expecting = TToken.EOF) then 4361 TokenName := 'EOF' 4362 else 4363 TokenName := TokenNames[MMTE.Expecting]; 4364 Result := 'mismatched input ' + GetTokenErrorDisplay(E.Token) 4365 + ' expecting ' + TokenName; 4366 end 4367 else 4368 if (E is EMismatchedTreeNodeException) then 4369 begin 4370 if (MTNE.Expecting = TToken.EOF) then 4371 Result := 'EOF' 4372 else 4373 Result := TokenNames[MTNE.Expecting]; 4374 // The ternary operator is only necessary because of a bug in the .NET framework 4375 Result := 'mismatched tree node: '; 4376 if (MTNE.Node <> nil) and (MTNE.Node.ToString <> '') then 4377 Result := Result + MTNE.Node.ToString; 4378 Result := Result + ' expecting ' + TokenName; 4379 end 4380 else 4381 if (E is ENoViableAltException) then 4382 begin 4383 // for development, can add "decision=<<"+nvae.grammarDecisionDescription+">>" 4384 // and "(decision="+nvae.decisionNumber+") and 4385 // "state "+nvae.stateNumber 4386 Result := 'no viable alternative at input ' + GetTokenErrorDisplay(E.Token); 4387 end 4388 else 4389 if (E is EEarlyExitException) then 4390 begin 4391 // for development, can add "(decision="+eee.decisionNumber+")" 4392 Result := 'required (...)+ loop did not match anyting at input ' 4393 + GetTokenErrorDisplay(E.Token); 4394 end else 4395 if (E is EMismatchedSetException) then 4396 begin 4397 Result := 'mismatched input ' + GetTokenErrorDisplay(E.Token) 4398 + ' expecting set ' + MSE.Expecting.ToString; 4399 end 4400 else 4401 if (E is EMismatchedNotSetException) then 4402 begin 4403 Result := 'mismatched input ' + GetTokenErrorDisplay(E.Token) 4404 + ' expecting set ' + MSE.Expecting.ToString; 4405 end 4406 else 4407 if (E is EFailedPredicateException) then 4408 begin 4409 Result := 'rule ' + FPE.RuleName 4410 + ' failed predicate: {' + FPE.PredicateText + '}?'; 4411 end; 4412end; 4413 4414function TBaseRecognizer.GetGrammarFileName: String; 4415begin 4416 // No defeault implementation 4417 Result := ''; 4418end; 4419 4420function TBaseRecognizer.GetMissingSymbol(const Input: IIntStream; 4421 const E: ERecognitionException; const ExpectedTokenType: Integer; 4422 const Follow: IBitSet): IANTLRInterface; 4423begin 4424 // No defeault implementation 4425 Result := nil; 4426end; 4427 4428function TBaseRecognizer.GetNumberOfSyntaxErrors: Integer; 4429begin 4430 Result := FState.SyntaxErrors; 4431end; 4432 4433function TBaseRecognizer.GetRuleMemoization(const RuleIndex, 4434 RuleStartIndex: Integer): Integer; 4435var 4436 Dict: IDictionary<Integer, Integer>; 4437begin 4438 Dict := FState.RuleMemo[RuleIndex]; 4439 if (Dict = nil) then 4440 begin 4441 Dict := TDictionary<Integer, Integer>.Create; 4442 FState.RuleMemo[RuleIndex] := Dict; 4443 end; 4444 if (not Dict.TryGetValue(RuleStartIndex, Result)) then 4445 Result := MEMO_RULE_UNKNOWN; 4446end; 4447 4448function TBaseRecognizer.GetRuleMemoizationChaceSize: Integer; 4449var 4450 RuleMap: IDictionary<Integer, Integer>; 4451begin 4452 Result := 0; 4453 if Assigned(FState.RuleMemo) then 4454 begin 4455 for RuleMap in FState.RuleMemo do 4456 if Assigned(RuleMap) then 4457 Inc(Result,RuleMap.Count); // how many input indexes are recorded? 4458 end; 4459end; 4460 4461function TBaseRecognizer.GetState: IRecognizerSharedState; 4462begin 4463 Result := FState; 4464end; 4465 4466function TBaseRecognizer.GetTokenErrorDisplay(const T: IToken): String; 4467begin 4468 Result := T.Text; 4469 if (Result = '') then 4470 begin 4471 if (T.TokenType = TToken.EOF) then 4472 Result := '<EOF>' 4473 else 4474 Result := '<' + IntToStr(T.TokenType) + '>'; 4475 end; 4476 Result := ReplaceStr(Result,#10,'\n'); 4477 Result := ReplaceStr(Result,#13,'\r'); 4478 Result := ReplaceStr(Result,#9,'\t'); 4479 Result := '''' + Result + ''''; 4480end; 4481 4482function TBaseRecognizer.GetTokenNames: TStringArray; 4483begin 4484 // no default implementation 4485 Result := nil; 4486end; 4487 4488function TBaseRecognizer.Match(const Input: IIntStream; 4489 const TokenType: Integer; const Follow: IBitSet): IANTLRInterface; 4490begin 4491 Result := GetCurrentInputSymbol(Input); 4492 if (Input.LA(1) = TokenType) then 4493 begin 4494 Input.Consume; 4495 FState.ErrorRecovery := False; 4496 FState.Failed := False; 4497 end else 4498 begin 4499 if (FState.Backtracking > 0) then 4500 FState.Failed := True 4501 else 4502 begin 4503 Mismatch(Input, TokenType, Follow); 4504 Result := RecoverFromMismatchedToken(Input, TokenType, Follow); 4505 end; 4506 end; 4507end; 4508 4509procedure TBaseRecognizer.MatchAny(const Input: IIntStream); 4510begin 4511 FState.ErrorRecovery := False; 4512 FState.Failed := False; 4513 Input.Consume; 4514end; 4515 4516procedure TBaseRecognizer.Memoize(const Input: IIntStream; const RuleIndex, 4517 RuleStartIndex: Integer); 4518var 4519 StopTokenIndex: Integer; 4520 Dict: IDictionary<Integer, Integer>; 4521begin 4522 Dict := FState.RuleMemo[RuleIndex]; 4523 if Assigned(Dict) then 4524 begin 4525 if FState.Failed then 4526 StopTokenIndex := MEMO_RULE_FAILED 4527 else 4528 StopTokenIndex := Input.Index - 1; 4529 Dict.AddOrSetValue(RuleStartIndex, StopTokenIndex); 4530 end; 4531end; 4532 4533procedure TBaseRecognizer.Mismatch(const Input: IIntStream; 4534 const TokenType: Integer; const Follow: IBitSet); 4535begin 4536 if MismatchIsUnwantedToken(Input, TokenType) then 4537 raise EUnwantedTokenException.Create(TokenType, Input) 4538 else 4539 if MismatchIsMissingToken(Input, Follow) then 4540 raise EMissingTokenException.Create(TokenType, Input, nil) 4541 else 4542 raise EMismatchedTokenException.Create(TokenType, Input); 4543end; 4544 4545function TBaseRecognizer.MismatchIsMissingToken(const Input: IIntStream; 4546 const Follow: IBitSet): Boolean; 4547var 4548 ViableTokensFollowingThisRule, Follow2: IBitSet; 4549begin 4550 if (Follow = nil) then 4551 // we have no information about the follow; we can only consume 4552 // a single token and hope for the best 4553 Result := False 4554 else 4555 begin 4556 Follow2 := Follow; 4557 // compute what can follow this grammar element reference 4558 if (Follow.Member(TToken.EOR_TOKEN_TYPE)) then 4559 begin 4560 ViableTokensFollowingThisRule := ComputeContextSensitiveRuleFOLLOW(); 4561 Follow2 := Follow.BitSetOr(ViableTokensFollowingThisRule); 4562 if (FState.FollowingStackPointer >= 0) then 4563 // remove EOR if we're not the start symbol 4564 Follow2.Remove(TToken.EOR_TOKEN_TYPE); 4565 end; 4566 4567 // if current token is consistent with what could come after set 4568 // then we know we're missing a token; error recovery is free to 4569 // "insert" the missing token 4570 4571 // BitSet cannot handle negative numbers like -1 (EOF) so I leave EOR 4572 // in follow set to indicate that the fall of the start symbol is 4573 // in the set (EOF can follow). 4574 if (Follow2.Member(Input.LA(1)) or Follow2.Member(TToken.EOR_TOKEN_TYPE)) then 4575 Result := True 4576 else 4577 Result := False; 4578 end; 4579end; 4580 4581function TBaseRecognizer.MismatchIsUnwantedToken(const Input: IIntStream; 4582 const TokenType: Integer): Boolean; 4583begin 4584 Result := (Input.LA(2) = TokenType); 4585end; 4586 4587procedure TBaseRecognizer.PushFollow(const FSet: IBitSet); 4588var 4589 F: TBitSetArray; 4590 I: Integer; 4591begin 4592 if ((FState.FollowingStackPointer + 1) >= Length(FState.Following)) then 4593 begin 4594 SetLength(F, Length(FState.Following) * 2); 4595 FillChar(F[0], Length(F) * SizeOf(IBitSet), 0); 4596 for I := 0 to Length(FState.Following) - 1 do 4597 F[I] := FState.Following[I]; 4598 FState.Following := F; 4599 end; 4600 FState.FollowingStackPointer := FState.FollowingStackPointer + 1; 4601 FState.Following[FState.FollowingStackPointer] := FSet; 4602end; 4603 4604procedure TBaseRecognizer.Recover(const Input: IIntStream; 4605 const RE: ERecognitionException); 4606var 4607 FollowSet: IBitSet; 4608begin 4609 if (FState.LastErrorIndex = Input.Index) then 4610 // uh oh, another error at same token index; must be a case 4611 // where LT(1) is in the recovery token set so nothing is 4612 // consumed; consume a single token so at least to prevent 4613 // an infinite loop; this is a failsafe. 4614 Input.Consume; 4615 FState.LastErrorIndex := Input.Index; 4616 FollowSet := ComputeErrorRecoverySet; 4617 BeginResync; 4618 ConsumeUntil(Input,FollowSet); 4619 EndResync; 4620end; 4621 4622function TBaseRecognizer.RecoverFromMismatchedSet(const Input: IIntStream; 4623 const E: ERecognitionException; const Follow: IBitSet): IANTLRInterface; 4624begin 4625 if MismatchIsMissingToken(Input, Follow) then 4626 begin 4627 ReportError(E); 4628 // we don't know how to conjure up a token for sets yet 4629 Result := GetMissingSymbol(Input, E, TToken.INVALID_TOKEN_TYPE, Follow); 4630 end 4631 else 4632 begin 4633 // TODO do single token deletion like above for Token mismatch 4634 Result := nil; 4635 raise E; 4636 end; 4637end; 4638 4639function TBaseRecognizer.RecoverFromMismatchedToken(const Input: IIntStream; 4640 const TokenType: Integer; const Follow: IBitSet): IANTLRInterface; 4641var 4642 E: ERecognitionException; 4643begin 4644 // if next token is what we are looking for then "delete" this token 4645 if MismatchIsUnwantedToken(Input, TokenType) then 4646 begin 4647 E := EUnwantedTokenException.Create(TokenType, Input); 4648 BeginResync; 4649 Input.Consume; // simply delete extra token 4650 EndResync; 4651 ReportError(E); // report after consuming so AW sees the token in the exception 4652 // we want to return the token we're actually matching 4653 Result := GetCurrentInputSymbol(Input); 4654 Input.Consume; // move past ttype token as if all were ok 4655 end 4656 else 4657 begin 4658 // can't recover with single token deletion, try insertion 4659 if MismatchIsMissingToken(Input, Follow) then 4660 begin 4661 E := nil; 4662 Result := GetMissingSymbol(Input, E, TokenType, Follow); 4663 E := EMissingTokenException.Create(TokenType, Input, Result); 4664 ReportError(E); // report after inserting so AW sees the token in the exception 4665 end 4666 else 4667 begin 4668 // even that didn't work; must throw the exception 4669 raise EMismatchedTokenException.Create(TokenType, Input); 4670 end; 4671 end; 4672end; 4673 4674procedure TBaseRecognizer.ReportError(const E: ERecognitionException); 4675begin 4676 // if we've already reported an error and have not matched a token 4677 // yet successfully, don't report any errors. 4678 if (not FState.ErrorRecovery) then 4679 begin 4680 FState.SyntaxErrors := FState.SyntaxErrors + 1; // don't count spurious 4681 FState.ErrorRecovery := True; 4682 DisplayRecognitionError(GetTokenNames, E); 4683 end; 4684end; 4685 4686procedure TBaseRecognizer.Reset; 4687var 4688 I: Integer; 4689begin 4690 // wack everything related to error recovery 4691 if (FState = nil) then 4692 Exit; // no shared state work to do 4693 4694 FState.FollowingStackPointer := -1; 4695 FState.ErrorRecovery := False; 4696 FState.LastErrorIndex := -1; 4697 FState.Failed := False; 4698 FState.SyntaxErrors := 0; 4699 4700 // wack everything related to backtracking and memoization 4701 FState.Backtracking := 0; 4702 if Assigned(FState.RuleMemo) then 4703 for I := 0 to Length(FState.RuleMemo) - 1 do 4704 begin 4705 // wipe cache 4706 FState.RuleMemo[I] := nil; 4707 end; 4708end; 4709 4710function TBaseRecognizer.ToStrings(const Tokens: IList<IToken>): IList<String>; 4711var 4712 Token: IToken; 4713begin 4714 if (Tokens = nil) then 4715 Result := nil 4716 else 4717 begin 4718 Result := TList<String>.Create; 4719 for Token in Tokens do 4720 Result.Add(Token.Text); 4721 end; 4722end; 4723 4724procedure TBaseRecognizer.TraceIn(const RuleName: String; 4725 const RuleIndex: Integer; const InputSymbol: String); 4726begin 4727 Write('enter ' + RuleName + ' ' + InputSymbol); 4728 if (FState.Failed) then 4729 WriteLn(' failed=True'); 4730 if (FState.Backtracking > 0) then 4731 Write(' backtracking=' + IntToStr(FState.Backtracking)); 4732 WriteLn; 4733end; 4734 4735procedure TBaseRecognizer.TraceOut(const RuleName: String; 4736 const RuleIndex: Integer; const InputSymbol: String); 4737begin 4738 Write('exit ' + RuleName + ' ' + InputSymbol); 4739 if (FState.Failed) then 4740 WriteLn(' failed=True'); 4741 if (FState.Backtracking > 0) then 4742 Write(' backtracking=' + IntToStr(FState.Backtracking)); 4743 WriteLn; 4744end; 4745 4746{ TCommonTokenStream } 4747 4748procedure TCommonTokenStream.Consume; 4749begin 4750 if (FP < FTokens.Count) then 4751 begin 4752 Inc(FP); 4753 FP := SkipOffTokenChannels(FP); // leave p on valid token 4754 end; 4755end; 4756 4757constructor TCommonTokenStream.Create; 4758begin 4759 inherited; 4760 FP := -1; 4761 FChannel := TToken.DEFAULT_CHANNEL; 4762 FTokens := TList<IToken>.Create; 4763 FTokens.Capacity := 500; 4764end; 4765 4766constructor TCommonTokenStream.Create(const ATokenSource: ITokenSource); 4767begin 4768 Create; 4769 FTokenSource := ATokenSource; 4770end; 4771 4772procedure TCommonTokenStream.DiscardOffChannelTokens(const Discard: Boolean); 4773begin 4774 FDiscardOffChannelTokens := Discard; 4775end; 4776 4777procedure TCommonTokenStream.DiscardTokenType(const TType: Integer); 4778begin 4779 if (FDiscardSet = nil) then 4780 FDiscardSet := THashList<Integer, Integer>.Create; 4781 FDiscardSet.Add(TType, TType); 4782end; 4783 4784procedure TCommonTokenStream.FillBuffer; 4785var 4786 Index: Integer; 4787 T: IToken; 4788 Discard: Boolean; 4789begin 4790 Index := 0; 4791 T := FTokenSource.NextToken; 4792 while Assigned(T) and (T.TokenType <> Integer(cscEOF)) do 4793 begin 4794 Discard := False; 4795 // is there a channel override for token type? 4796 if Assigned(FChannelOverrideMap) then 4797 if FChannelOverrideMap.ContainsKey(T.TokenType) then 4798 T.Channel := FChannelOverrideMap[T.TokenType]; 4799 4800 if Assigned(FDiscardSet) and FDiscardSet.ContainsKey(T.TokenType) then 4801 Discard := True 4802 else 4803 if FDiscardOffChannelTokens and (T.Channel <> FChannel) then 4804 Discard := True; 4805 4806 if (not Discard) then 4807 begin 4808 T.TokenIndex := Index; 4809 FTokens.Add(T); 4810 Inc(Index); 4811 end; 4812 4813 T := FTokenSource.NextToken; 4814 end; 4815 // leave p pointing at first token on channel 4816 FP := 0; 4817 FP := SkipOffTokenChannels(FP); 4818end; 4819 4820function TCommonTokenStream.Get(const I: Integer): IToken; 4821begin 4822 Result := FTokens[I]; 4823end; 4824 4825function TCommonTokenStream.GetSourceName: String; 4826begin 4827 Result := FTokenSource.SourceName; 4828end; 4829 4830function TCommonTokenStream.GetTokens(const Start, Stop: Integer; 4831 const Types: IList<Integer>): IList<IToken>; 4832begin 4833 Result := GetTokens(Start, Stop, TBitSet.Create(Types)); 4834end; 4835 4836function TCommonTokenStream.GetTokens(const Start, Stop, 4837 TokenType: Integer): IList<IToken>; 4838begin 4839 Result := GetTokens(Start, Stop, TBitSet.BitSetOf(TokenType)); 4840end; 4841 4842function TCommonTokenStream.GetTokens(const Start, Stop: Integer; 4843 const Types: IBitSet): IList<IToken>; 4844var 4845 I, StartIndex, StopIndex: Integer; 4846 T: IToken; 4847begin 4848 if (FP = -1) then 4849 FillBuffer; 4850 StopIndex := Min(Stop,FTokens.Count - 1); 4851 StartIndex := Max(Start,0); 4852 if (StartIndex > StopIndex) then 4853 Result := nil 4854 else 4855 begin 4856 Result := TList<IToken>.Create; 4857 for I := StartIndex to StopIndex do 4858 begin 4859 T := FTokens[I]; 4860 if (Types = nil) or Types.Member(T.TokenType) then 4861 Result.Add(T); 4862 end; 4863 if (Result.Count = 0) then 4864 Result := nil; 4865 end; 4866end; 4867 4868function TCommonTokenStream.GetTokens: IList<IToken>; 4869begin 4870 if (FP = -1) then 4871 FillBuffer; 4872 Result := FTokens; 4873end; 4874 4875function TCommonTokenStream.GetTokens(const Start, 4876 Stop: Integer): IList<IToken>; 4877begin 4878 Result := GetTokens(Start, Stop, IBitSet(nil)); 4879end; 4880 4881function TCommonTokenStream.GetTokenSource: ITokenSource; 4882begin 4883 Result := FTokenSource; 4884end; 4885 4886function TCommonTokenStream.Index: Integer; 4887begin 4888 Result := FP; 4889end; 4890 4891function TCommonTokenStream.LA(I: Integer): Integer; 4892begin 4893 Result := LT(I).TokenType; 4894end; 4895 4896function TCommonTokenStream.LAChar(I: Integer): Char; 4897begin 4898 Result := Char(LA(I)); 4899end; 4900 4901function TCommonTokenStream.LB(const K: Integer): IToken; 4902var 4903 I, N: Integer; 4904begin 4905 if (FP = -1) then 4906 FillBuffer; 4907 if (K = 0) then 4908 Result := nil 4909 else 4910 if ((FP - K) < 0) then 4911 Result := nil 4912 else 4913 begin 4914 I := FP; 4915 N := 1; 4916 // find k good tokens looking backwards 4917 while (N <= K) do 4918 begin 4919 // skip off-channel tokens 4920 I := SkipOffTokenChannelsReverse(I - 1); // leave p on valid token 4921 Inc(N); 4922 end; 4923 if (I < 0) then 4924 Result := nil 4925 else 4926 Result := FTokens[I]; 4927 end; 4928end; 4929 4930function TCommonTokenStream.LT(const K: Integer): IToken; 4931var 4932 I, N: Integer; 4933begin 4934 if (FP = -1) then 4935 FillBuffer; 4936 if (K = 0) then 4937 Result := nil 4938 else 4939 if (K < 0) then 4940 Result := LB(-K) 4941 else 4942 if ((FP + K - 1) >= FTokens.Count) then 4943 Result := TToken.EOF_TOKEN 4944 else 4945 begin 4946 I := FP; 4947 N := 1; 4948 // find k good tokens 4949 while (N < K) do 4950 begin 4951 // skip off-channel tokens 4952 I := SkipOffTokenChannels(I + 1); // leave p on valid token 4953 Inc(N); 4954 end; 4955 if (I >= FTokens.Count) then 4956 Result := TToken.EOF_TOKEN 4957 else 4958 Result := FTokens[I]; 4959 end; 4960end; 4961 4962function TCommonTokenStream.Mark: Integer; 4963begin 4964 if (FP = -1) then 4965 FillBuffer; 4966 FLastMarker := Index; 4967 Result := FLastMarker; 4968end; 4969 4970procedure TCommonTokenStream.Release(const Marker: Integer); 4971begin 4972 // no resources to release 4973end; 4974 4975procedure TCommonTokenStream.Reset; 4976begin 4977 FP := 0; 4978 FLastMarker := 0; 4979end; 4980 4981procedure TCommonTokenStream.Rewind(const Marker: Integer); 4982begin 4983 Seek(Marker); 4984end; 4985 4986procedure TCommonTokenStream.Rewind; 4987begin 4988 Seek(FLastMarker); 4989end; 4990 4991procedure TCommonTokenStream.Seek(const Index: Integer); 4992begin 4993 FP := Index; 4994end; 4995 4996procedure TCommonTokenStream.SetTokenSource(const Value: ITokenSource); 4997begin 4998 FTokenSource := Value; 4999 FTokens.Clear; 5000 FP := -1; 5001 FChannel := TToken.DEFAULT_CHANNEL; 5002end; 5003 5004procedure TCommonTokenStream.SetTokenTypeChannel(const TType, Channel: Integer); 5005begin 5006 if (FChannelOverrideMap = nil) then 5007 FChannelOverrideMap := TDictionary<Integer, Integer>.Create; 5008 FChannelOverrideMap[TType] := Channel; 5009end; 5010 5011function TCommonTokenStream.Size: Integer; 5012begin 5013 Result := FTokens.Count; 5014end; 5015 5016function TCommonTokenStream.SkipOffTokenChannels(const I: Integer): Integer; 5017var 5018 N: Integer; 5019begin 5020 Result := I; 5021 N := FTokens.Count; 5022 while (Result < N) and (FTokens[Result].Channel <> FChannel) do 5023 Inc(Result); 5024end; 5025 5026function TCommonTokenStream.SkipOffTokenChannelsReverse( 5027 const I: Integer): Integer; 5028begin 5029 Result := I; 5030 while (Result >= 0) and (FTokens[Result].Channel <> FChannel) do 5031 Dec(Result); 5032end; 5033 5034function TCommonTokenStream.ToString: String; 5035begin 5036 if (FP = -1) then 5037 FillBuffer; 5038 Result := ToString(0, FTokens.Count - 1); 5039end; 5040 5041function TCommonTokenStream.ToString(const Start, Stop: Integer): String; 5042var 5043 I, Finish: Integer; 5044 Buf: TStringBuilder; 5045 T: IToken; 5046begin 5047 if (Start < 0) or (Stop < 0) then 5048 Result := '' 5049 else 5050 begin 5051 if (FP = -1) then 5052 FillBuffer; 5053 if (Stop >= FTokens.Count) then 5054 Finish := FTokens.Count - 1 5055 else 5056 Finish := Stop; 5057 Buf := TStringBuilder.Create; 5058 try 5059 for I := Start to Finish do 5060 begin 5061 T := FTokens[I]; 5062 Buf.Append(T.Text); 5063 end; 5064 Result := Buf.ToString; 5065 finally 5066 Buf.Free; 5067 end; 5068 end; 5069end; 5070 5071function TCommonTokenStream.ToString(const Start, Stop: IToken): String; 5072begin 5073 if Assigned(Start) and Assigned(Stop) then 5074 Result := ToString(Start.TokenIndex, Stop.TokenIndex) 5075 else 5076 Result := ''; 5077end; 5078 5079constructor TCommonTokenStream.Create(const ATokenSource: ITokenSource; 5080 const AChannel: Integer); 5081begin 5082 Create(ATokenSource); 5083 FChannel := AChannel; 5084end; 5085 5086constructor TCommonTokenStream.Create(const ALexer: ILexer); 5087begin 5088 Create(ALexer as ITokenSource); 5089end; 5090 5091constructor TCommonTokenStream.Create(const ALexer: ILexer; 5092 const AChannel: Integer); 5093begin 5094 Create(ALexer as ITokenSource, AChannel); 5095end; 5096 5097{ TDFA } 5098 5099function TDFA.Description: String; 5100begin 5101 Result := 'n/a'; 5102end; 5103 5104procedure TDFA.Error(const NVAE: ENoViableAltException); 5105begin 5106 // No default implementation 5107end; 5108 5109function TDFA.GetRecognizer: IBaseRecognizer; 5110begin 5111 Result := IBaseRecognizer(FRecognizer); 5112end; 5113 5114function TDFA.GetSpecialStateTransitionHandler: TSpecialStateTransitionHandler; 5115begin 5116 Result := FSpecialStateTransitionHandler; 5117end; 5118 5119procedure TDFA.NoViableAlt(const S: Integer; const Input: IIntStream); 5120var 5121 NVAE: ENoViableAltException; 5122begin 5123 if (Recognizer.State.Backtracking > 0) then 5124 Recognizer.State.Failed := True 5125 else 5126 begin 5127 NVAE := ENoViableAltException.Create(Description, FDecisionNumber, S, Input); 5128 Error(NVAE); 5129 raise NVAE; 5130 end; 5131end; 5132 5133function TDFA.Predict(const Input: IIntStream): Integer; 5134var 5135 Mark, S, SNext, SpecialState: Integer; 5136 C: Char; 5137begin 5138 Result := 0; 5139 Mark := Input.Mark; // remember where decision started in input 5140 S := 0; // we always start at s0 5141 try 5142 while True do 5143 begin 5144 SpecialState := FSpecial[S]; 5145 if (SpecialState >= 0) then 5146 begin 5147 S := FSpecialStateTransitionHandler(Self, SpecialState, Input); 5148 if (S = -1) then 5149 begin 5150 NoViableAlt(S, Input); 5151 Exit; 5152 end; 5153 Input.Consume; 5154 Continue; 5155 end; 5156 5157 if (FAccept[S] >= 1) then 5158 begin 5159 Result := FAccept[S]; 5160 Exit; 5161 end; 5162 5163 // look for a normal char transition 5164 C := Char(Input.LA(1)); // -1 == \uFFFF, all tokens fit in 65000 space 5165 if (C >= FMin[S]) and (C <= FMax[S]) then 5166 begin 5167 SNext := FTransition[S,Integer(C) - Integer(FMin[S])]; // move to next state 5168 if (SNext < 0) then 5169 begin 5170 // was in range but not a normal transition 5171 // must check EOT, which is like the else clause. 5172 // eot[s]>=0 indicates that an EOT edge goes to another 5173 // state. 5174 if (FEOT[S] >= 0) then // EOT Transition to accept state? 5175 begin 5176 S := FEOT[S]; 5177 Input.Consume; 5178 // TODO: I had this as return accept[eot[s]] 5179 // which assumed here that the EOT edge always 5180 // went to an accept...faster to do this, but 5181 // what about predicated edges coming from EOT 5182 // target? 5183 Continue; 5184 end; 5185 5186 NoViableAlt(S, Input); 5187 Exit; 5188 end; 5189 S := SNext; 5190 Input.Consume; 5191 Continue; 5192 end; 5193 5194 if (FEOT[S] >= 0) then 5195 begin 5196 // EOT Transition? 5197 S := FEOT[S]; 5198 Input.Consume; 5199 Continue; 5200 end; 5201 5202 if (C = Char(TToken.EOF)) and (FEOF[S] >= 0) then 5203 begin 5204 // EOF Transition to accept state? 5205 Result := FAccept[FEOF[S]]; 5206 Exit; 5207 end; 5208 5209 // not in range and not EOF/EOT, must be invalid symbol 5210 NoViableAlt(S, Input); 5211 Exit; 5212 end; 5213 finally 5214 Input.Rewind(Mark); 5215 end; 5216end; 5217 5218procedure TDFA.SetRecognizer(const Value: IBaseRecognizer); 5219begin 5220 FRecognizer := Pointer(Value); 5221end; 5222 5223procedure TDFA.SetSpecialStateTransitionHandler( 5224 const Value: TSpecialStateTransitionHandler); 5225begin 5226 FSpecialStateTransitionHandler := Value; 5227end; 5228 5229function TDFA.SpecialStateTransition(const S: Integer; 5230 const Input: IIntStream): Integer; 5231begin 5232 // No default implementation 5233 Result := -1; 5234end; 5235 5236function TDFA.SpecialTransition(const State, Symbol: Integer): Integer; 5237begin 5238 Result := 0; 5239end; 5240 5241class function TDFA.UnpackEncodedString( 5242 const EncodedString: String): TSmallintArray; 5243var 5244 I, J, DI, Size: Integer; 5245 N, V: Char; 5246begin 5247 Size := 0; 5248 I := 1; 5249 while (I <= Length(EncodedString)) do 5250 begin 5251 Inc(Size,Integer(EncodedString[I])); 5252 Inc(I,2); 5253 end; 5254 5255 SetLength(Result,Size); 5256 DI := 0; 5257 I := 1; 5258 while (I <= Length(EncodedString)) do 5259 begin 5260 N := EncodedString[I]; 5261 V := EncodedString[I + 1]; 5262 // add v n times to data 5263 for J := 1 to Integer(N) do 5264 begin 5265 Result[DI] := Smallint(V); 5266 Inc(DI); 5267 end; 5268 Inc(I,2); 5269 end; 5270end; 5271 5272class function TDFA.UnpackEncodedStringArray( 5273 const EncodedStrings: array of String): TSmallintMatrix; 5274var 5275 I: Integer; 5276begin 5277 SetLength(Result,Length(EncodedStrings)); 5278 for I := 0 to Length(EncodedStrings) - 1 do 5279 Result[I] := UnpackEncodedString(EncodedStrings[I]); 5280end; 5281 5282class function TDFA.UnpackEncodedStringArray( 5283 const EncodedStrings: TStringArray): TSmallintMatrix; 5284var 5285 I: Integer; 5286begin 5287 SetLength(Result,Length(EncodedStrings)); 5288 for I := 0 to Length(EncodedStrings) - 1 do 5289 Result[I] := UnpackEncodedString(EncodedStrings[I]); 5290end; 5291 5292class function TDFA.UnpackEncodedStringToUnsignedChars( 5293 const EncodedString: String): TCharArray; 5294var 5295 I, J, DI, Size: Integer; 5296 N, V: Char; 5297begin 5298 Size := 0; 5299 I := 1; 5300 while (I <= Length(EncodedString)) do 5301 begin 5302 Inc(Size,Integer(EncodedString[I])); 5303 Inc(I,2); 5304 end; 5305 5306 SetLength(Result,Size); 5307 DI := 0; 5308 I := 1; 5309 while (I <= Length(EncodedString)) do 5310 begin 5311 N := EncodedString[I]; 5312 V := EncodedString[I + 1]; 5313 // add v n times to data 5314 for J := 1 to Integer(N) do 5315 begin 5316 Result[DI] := V; 5317 Inc(DI); 5318 end; 5319 Inc(I,2); 5320 end; 5321end; 5322 5323{ TLexer } 5324 5325constructor TLexer.Create; 5326begin 5327 inherited; 5328end; 5329 5330constructor TLexer.Create(const AInput: ICharStream); 5331begin 5332 inherited Create; 5333 FInput := AInput; 5334end; 5335 5336constructor TLexer.Create(const AInput: ICharStream; 5337 const AState: IRecognizerSharedState); 5338begin 5339 inherited Create(AState); 5340 FInput := AInput; 5341end; 5342 5343function TLexer.Emit: IToken; 5344begin 5345 Result := TCommonToken.Create(FInput, FState.TokenType, FState.Channel, 5346 FState.TokenStartCharIndex, GetCharIndex - 1); 5347 Result.Line := FState.TokenStartLine; 5348 Result.Text := FState.Text; 5349 Result.CharPositionInLine := FState.TokenStartCharPositionInLine; 5350 Emit(Result); 5351end; 5352 5353procedure TLexer.Emit(const Token: IToken); 5354begin 5355 FState.Token := Token; 5356end; 5357 5358function TLexer.GetCharErrorDisplay(const C: Integer): String; 5359begin 5360 case C of 5361 // TToken.EOF 5362 TOKEN_dot_EOF: 5363 Result := '<EOF>'; 5364 10: 5365 Result := '\n'; 5366 9: 5367 Result := '\t'; 5368 13: 5369 Result := '\r'; 5370 else 5371 Result := Char(C); 5372 end; 5373 Result := '''' + Result + ''''; 5374end; 5375 5376function TLexer.GetCharIndex: Integer; 5377begin 5378 Result := FInput.Index; 5379end; 5380 5381function TLexer.GetCharPositionInLine: Integer; 5382begin 5383 Result := FInput.CharPositionInLine; 5384end; 5385 5386function TLexer.GetCharStream: ICharStream; 5387begin 5388 Result := FInput; 5389end; 5390 5391function TLexer.GetErrorMessage(const E: ERecognitionException; 5392 const TokenNames: TStringArray): String; 5393var 5394 MTE: EMismatchedTokenException absolute E; 5395 NVAE: ENoViableAltException absolute E; 5396 EEE: EEarlyExitException absolute E; 5397 MNSE: EMismatchedNotSetException absolute E; 5398 MSE: EMismatchedSetException absolute E; 5399 MRE: EMismatchedRangeException absolute E; 5400begin 5401 if (E is EMismatchedTokenException) then 5402 Result := 'mismatched character ' + GetCharErrorDisplay(E.Character) 5403 + ' expecting ' + GetCharErrorDisplay(MTE.Expecting) 5404 else 5405 if (E is ENoViableAltException) then 5406 // for development, can add "decision=<<"+nvae.grammarDecisionDescription+">>" 5407 // and "(decision="+nvae.decisionNumber+") and 5408 // "state "+nvae.stateNumber 5409 Result := 'no viable alternative at character ' + GetCharErrorDisplay(NVAE.Character) 5410 else 5411 if (E is EEarlyExitException) then 5412 // for development, can add "(decision="+eee.decisionNumber+")" 5413 Result := 'required (...)+ loop did not match anything at character ' 5414 + GetCharErrorDisplay(EEE.Character) 5415 else 5416 if (E is EMismatchedNotSetException) then 5417 Result := 'mismatched character ' + GetCharErrorDisplay(MNSE.Character) 5418 + ' expecting set ' + MNSE.Expecting.ToString 5419 else 5420 if (E is EMismatchedSetException) then 5421 Result := 'mismatched character ' + GetCharErrorDisplay(MSE.Character) 5422 + ' expecting set ' + MSE.Expecting.ToString 5423 else 5424 if (E is EMismatchedRangeException) then 5425 Result := 'mismatched character ' + GetCharErrorDisplay(MRE.Character) 5426 + ' expecting set ' + GetCharErrorDisplay(MRE.A) + '..' 5427 + GetCharErrorDisplay(MRE.B) 5428 else 5429 Result := inherited GetErrorMessage(E, TokenNames); 5430end; 5431 5432function TLexer.GetInput: IIntStream; 5433begin 5434 Result := FInput; 5435end; 5436 5437function TLexer.GetLine: Integer; 5438begin 5439 Result := FInput.Line; 5440end; 5441 5442function TLexer.GetSourceName: String; 5443begin 5444 Result := FInput.SourceName; 5445end; 5446 5447function TLexer.GetText: String; 5448begin 5449 if (FState.Text <> '') then 5450 Result := FState.Text 5451 else 5452 Result := FInput.Substring(FState.TokenStartCharIndex, GetCharIndex - 1) 5453end; 5454 5455procedure TLexer.Match(const S: String); 5456var 5457 I: Integer; 5458 MTE: EMismatchedTokenException; 5459begin 5460 for I := 1 to Length(S) do 5461 begin 5462 if (FInput.LA(1) <> Integer(S[I])) then 5463 begin 5464 if (FState.Backtracking > 0) then 5465 begin 5466 FState.Failed := True; 5467 Exit; 5468 end; 5469 MTE := EMismatchedTokenException.Create(Integer(S[I]), FInput); 5470 Recover(MTE); // don't really recover; just consume in lexer 5471 raise MTE; 5472 end; 5473 FInput.Consume; 5474 FState.Failed := False; 5475 end; 5476end; 5477 5478procedure TLexer.Match(const C: Integer); 5479var 5480 MTE: EMismatchedTokenException; 5481begin 5482 if (FInput.LA(1) <> C) then 5483 begin 5484 if (FState.Backtracking > 0) then 5485 begin 5486 FState.Failed := True; 5487 Exit; 5488 end; 5489 MTE := EMismatchedTokenException.Create(C, FInput); 5490 Recover(MTE); 5491 raise MTE; 5492 end; 5493 FInput.Consume; 5494 FState.Failed := False; 5495end; 5496 5497procedure TLexer.MatchAny; 5498begin 5499 FInput.Consume; 5500end; 5501 5502procedure TLexer.MatchRange(const A, B: Integer); 5503var 5504 MRE: EMismatchedRangeException; 5505begin 5506 if (FInput.LA(1) < A) or (FInput.LA(1) > B) then 5507 begin 5508 if (FState.Backtracking > 0) then 5509 begin 5510 FState.Failed := True; 5511 Exit; 5512 end; 5513 MRE := EMismatchedRangeException.Create(A, B, FInput); 5514 Recover(MRE); 5515 raise MRE; 5516 end; 5517 FInput.Consume; 5518 FState.Failed := False; 5519end; 5520 5521function TLexer.NextToken: IToken; 5522begin 5523 while True do 5524 begin 5525 FState.Token := nil; 5526 FState.Channel := TToken.DEFAULT_CHANNEL; 5527 FState.TokenStartCharIndex := FInput.Index; 5528 FState.TokenStartCharPositionInLine := FInput.CharPositionInLine; 5529 FState.TokenStartLine := Finput.Line; 5530 FState.Text := ''; 5531 if (FInput.LA(1) = Integer(cscEOF)) then 5532 begin 5533 Result := TToken.EOF_TOKEN; 5534 Exit; 5535 end; 5536 5537 try 5538 DoTokens; 5539 if (FState.Token = nil) then 5540 Emit 5541 else 5542 if (FState.Token = TToken.SKIP_TOKEN) then 5543 Continue; 5544 Exit(FState.Token); 5545 except 5546 on NVA: ENoViableAltException do 5547 begin 5548 ReportError(NVA); 5549 Recover(NVA); // throw out current char and try again 5550 end; 5551 5552 on RE: ERecognitionException do 5553 begin 5554 ReportError(RE); 5555 // Match() routine has already called Recover() 5556 end; 5557 end; 5558 end; 5559end; 5560 5561procedure TLexer.Recover(const RE: ERecognitionException); 5562begin 5563 FInput.Consume; 5564end; 5565 5566procedure TLexer.ReportError(const E: ERecognitionException); 5567begin 5568 DisplayRecognitionError(GetTokenNames, E); 5569end; 5570 5571procedure TLexer.Reset; 5572begin 5573 inherited; // reset all recognizer state variables 5574 // wack Lexer state variables 5575 if Assigned(FInput) then 5576 FInput.Seek(0); // rewind the input 5577 if (FState = nil) then 5578 Exit; // no shared state work to do 5579 FState.Token := nil; 5580 FState.TokenType := TToken.INVALID_TOKEN_TYPE; 5581 FState.Channel := TToken.DEFAULT_CHANNEL; 5582 FState.TokenStartCharIndex := -1; 5583 FState.TokenStartCharPositionInLine := -1; 5584 FState.TokenStartLine := -1; 5585 FState.Text := ''; 5586end; 5587 5588procedure TLexer.SetCharStream(const Value: ICharStream); 5589begin 5590 FInput := nil; 5591 Reset; 5592 FInput := Value; 5593end; 5594 5595procedure TLexer.SetText(const Value: String); 5596begin 5597 FState.Text := Value; 5598end; 5599 5600procedure TLexer.Skip; 5601begin 5602 FState.Token := TToken.SKIP_TOKEN; 5603end; 5604 5605procedure TLexer.TraceIn(const RuleName: String; const RuleIndex: Integer); 5606var 5607 InputSymbol: String; 5608begin 5609 InputSymbol := Char(FInput.LT(1)) + ' line=' + IntToStr(GetLine) + ':' 5610 + IntToStr(GetCharPositionInLine); 5611 inherited TraceIn(RuleName, RuleIndex, InputSymbol); 5612end; 5613 5614procedure TLexer.TraceOut(const RuleName: String; const RuleIndex: Integer); 5615var 5616 InputSymbol: String; 5617begin 5618 InputSymbol := Char(FInput.LT(1)) + ' line=' + IntToStr(GetLine) + ':' 5619 + IntToStr(GetCharPositionInLine); 5620 inherited TraceOut(RuleName, RuleIndex, InputSymbol); 5621end; 5622 5623{ TParser } 5624 5625constructor TParser.Create(const AInput: ITokenStream); 5626begin 5627 inherited Create; // highlight that we go to base class to set state object 5628 SetTokenStream(AInput); 5629end; 5630 5631constructor TParser.Create(const AInput: ITokenStream; 5632 const AState: IRecognizerSharedState); 5633begin 5634 inherited Create(AState); // share the state object with another parser 5635 SetTokenStream(AInput); 5636end; 5637 5638function TParser.GetCurrentInputSymbol( 5639 const Input: IIntStream): IANTLRInterface; 5640begin 5641 Result := FInput.LT(1) 5642end; 5643 5644function TParser.GetInput: IIntStream; 5645begin 5646 Result := FInput; 5647end; 5648 5649function TParser.GetMissingSymbol(const Input: IIntStream; 5650 const E: ERecognitionException; const ExpectedTokenType: Integer; 5651 const Follow: IBitSet): IANTLRInterface; 5652var 5653 TokenText: String; 5654 T: ICommonToken; 5655 Current: IToken; 5656begin 5657 if (ExpectedTokenType = TToken.EOF) then 5658 TokenText := '<missing EOF>' 5659 else 5660 TokenText := '<missing ' + GetTokenNames[ExpectedTokenType] + '>'; 5661 T := TCommonToken.Create(ExpectedTokenType, TokenText); 5662 Current := FInput.LT(1); 5663 if (Current.TokenType = TToken.EOF) then 5664 Current := FInput.LT(-1); 5665 T.Line := Current.Line; 5666 T.CharPositionInLine := Current.CharPositionInLine; 5667 T.Channel := DEFAULT_TOKEN_CHANNEL; 5668 Result := T; 5669end; 5670 5671function TParser.GetSourceName: String; 5672begin 5673 Result := FInput.SourceName; 5674end; 5675 5676function TParser.GetTokenStream: ITokenStream; 5677begin 5678 Result := FInput; 5679end; 5680 5681procedure TParser.Reset; 5682begin 5683 inherited; // reset all recognizer state variables 5684 if Assigned(FInput) then 5685 FInput.Seek(0); // rewind the input 5686end; 5687 5688procedure TParser.SetTokenStream(const Value: ITokenStream); 5689begin 5690 FInput := nil; 5691 Reset; 5692 FInput := Value; 5693end; 5694 5695procedure TParser.TraceIn(const RuleName: String; const RuleIndex: Integer); 5696begin 5697 inherited TraceIn(RuleName, RuleIndex, FInput.LT(1).ToString); 5698end; 5699 5700procedure TParser.TraceOut(const RuleName: String; const RuleIndex: Integer); 5701begin 5702 inherited TraceOut(RuleName, RuleIndex, FInput.LT(1).ToString); 5703end; 5704 5705{ TRuleReturnScope } 5706 5707function TRuleReturnScope.GetStart: IANTLRInterface; 5708begin 5709 Result := nil; 5710end; 5711 5712function TRuleReturnScope.GetStop: IANTLRInterface; 5713begin 5714 Result := nil; 5715end; 5716 5717function TRuleReturnScope.GetTemplate: IANTLRInterface; 5718begin 5719 Result := nil; 5720end; 5721 5722function TRuleReturnScope.GetTree: IANTLRInterface; 5723begin 5724 Result := nil; 5725end; 5726 5727procedure TRuleReturnScope.SetStart(const Value: IANTLRInterface); 5728begin 5729 raise EInvalidOperation.Create('Setter has not been defined for this property.'); 5730end; 5731 5732procedure TRuleReturnScope.SetStop(const Value: IANTLRInterface); 5733begin 5734 raise EInvalidOperation.Create('Setter has not been defined for this property.'); 5735end; 5736 5737procedure TRuleReturnScope.SetTree(const Value: IANTLRInterface); 5738begin 5739 raise EInvalidOperation.Create('Setter has not been defined for this property.'); 5740end; 5741 5742{ TParserRuleReturnScope } 5743 5744function TParserRuleReturnScope.GetStart: IANTLRInterface; 5745begin 5746 Result := FStart; 5747end; 5748 5749function TParserRuleReturnScope.GetStop: IANTLRInterface; 5750begin 5751 Result := FStop; 5752end; 5753 5754procedure TParserRuleReturnScope.SetStart(const Value: IANTLRInterface); 5755begin 5756 FStart := Value as IToken; 5757end; 5758 5759procedure TParserRuleReturnScope.SetStop(const Value: IANTLRInterface); 5760begin 5761 FStop := Value as IToken; 5762end; 5763 5764{ TTokenRewriteStream } 5765 5766procedure TTokenRewriteStream.Delete(const Start, Stop: IToken); 5767begin 5768 Delete(DEFAULT_PROGRAM_NAME, Start, Stop); 5769end; 5770 5771procedure TTokenRewriteStream.Delete(const IndexT: IToken); 5772begin 5773 Delete(DEFAULT_PROGRAM_NAME, IndexT, IndexT); 5774end; 5775 5776constructor TTokenRewriteStream.Create; 5777begin 5778 inherited; 5779 Init; 5780end; 5781 5782constructor TTokenRewriteStream.Create(const ATokenSource: ITokenSource); 5783begin 5784 inherited Create(ATokenSource); 5785 Init; 5786end; 5787 5788constructor TTokenRewriteStream.Create(const ALexer: ILexer); 5789begin 5790 Create(ALexer as ITokenSource); 5791end; 5792 5793constructor TTokenRewriteStream.Create(const ALexer: ILexer; 5794 const AChannel: Integer); 5795begin 5796 Create(ALexer as ITokenSource, AChannel); 5797end; 5798 5799function TTokenRewriteStream.CatOpText(const A, B: IANTLRInterface): IANTLRInterface; 5800var 5801 X, Y: String; 5802begin 5803 if Assigned(A) then 5804 X := A.ToString 5805 else 5806 X := ''; 5807 5808 if Assigned(B) then 5809 Y := B.ToString 5810 else 5811 Y := ''; 5812 5813 Result := TANTLRString.Create(X + Y); 5814end; 5815 5816constructor TTokenRewriteStream.Create(const ATokenSource: ITokenSource; 5817 const AChannel: Integer); 5818begin 5819 inherited Create(ATokenSource, AChannel); 5820 Init; 5821end; 5822 5823procedure TTokenRewriteStream.Delete(const ProgramName: String; const Start, 5824 Stop: IToken); 5825begin 5826 Replace(ProgramName, Start, Stop, nil); 5827end; 5828 5829procedure TTokenRewriteStream.Delete(const ProgramName: String; const Start, 5830 Stop: Integer); 5831begin 5832 Replace(ProgramName, Start, Stop, nil); 5833end; 5834 5835procedure TTokenRewriteStream.Delete(const Start, Stop: Integer); 5836begin 5837 Delete(DEFAULT_PROGRAM_NAME, Start, Stop); 5838end; 5839 5840procedure TTokenRewriteStream.Delete(const Index: Integer); 5841begin 5842 Delete(DEFAULT_PROGRAM_NAME, Index, Index); 5843end; 5844 5845procedure TTokenRewriteStream.DeleteProgram(const ProgramName: String); 5846begin 5847 Rollback(ProgramName, MIN_TOKEN_INDEX); 5848end; 5849 5850procedure TTokenRewriteStream.DeleteProgram; 5851begin 5852 DeleteProgram(DEFAULT_PROGRAM_NAME); 5853end; 5854 5855function TTokenRewriteStream.GetLastRewriteTokenIndex: Integer; 5856begin 5857 Result := GetLastRewriteTokenIndex(DEFAULT_PROGRAM_NAME); 5858end; 5859 5860function TTokenRewriteStream.GetKindOfOps( 5861 const Rewrites: IList<IRewriteOperation>; 5862 const Kind: TGUID): IList<IRewriteOperation>; 5863begin 5864 Result := GetKindOfOps(Rewrites, Kind, Rewrites.Count); 5865end; 5866 5867function TTokenRewriteStream.GetKindOfOps( 5868 const Rewrites: IList<IRewriteOperation>; const Kind: TGUID; 5869 const Before: Integer): IList<IRewriteOperation>; 5870var 5871 I: Integer; 5872 Op: IRewriteOperation; 5873 Obj: IInterface; 5874begin 5875 Result := TList<IRewriteOperation>.Create; 5876 I := 0; 5877 while (I < Before) and (I < Rewrites.Count) do 5878 begin 5879 Op := Rewrites[I]; 5880 if Assigned(Op) and (Op.QueryInterface(Kind, Obj) = 0) then 5881 Result.Add(Op); 5882 Inc(I); 5883 end; 5884end; 5885 5886function TTokenRewriteStream.GetLastRewriteTokenIndex( 5887 const ProgramName: String): Integer; 5888begin 5889 if (not FLastRewriteTokenIndexes.TryGetValue(ProgramName, Result)) then 5890 Result := -1; 5891end; 5892 5893function TTokenRewriteStream.GetProgram( 5894 const Name: String): IList<IRewriteOperation>; 5895var 5896 InstructionStream: IList<IRewriteOperation>; 5897begin 5898 InstructionStream := FPrograms[Name]; 5899 if (InstructionStream = nil) then 5900 InstructionStream := InitializeProgram(Name); 5901 Result := InstructionStream; 5902end; 5903 5904procedure TTokenRewriteStream.InsertAfter(const ProgramName: String; 5905 const T: IToken; const Text: IANTLRInterface); 5906begin 5907 InsertAfter(ProgramName, T.TokenIndex, Text); 5908end; 5909 5910procedure TTokenRewriteStream.Init; 5911var 5912 List: IList<IRewriteOperation>; 5913begin 5914 FPrograms := TDictionary<String, IList<IRewriteOperation>>.Create; 5915 List := TList<IRewriteOperation>.Create; 5916 List.Capacity := PROGRAM_INIT_SIZE; 5917 FPrograms.Add(DEFAULT_PROGRAM_NAME, List); 5918 FLastRewriteTokenIndexes := TDictionary<String, Integer>.Create; 5919end; 5920 5921function TTokenRewriteStream.InitializeProgram( 5922 const Name: String): IList<IRewriteOperation>; 5923begin 5924 Result := TList<IRewriteOperation>.Create; 5925 Result.Capacity := PROGRAM_INIT_SIZE; 5926 FPrograms[Name] := Result; 5927end; 5928 5929procedure TTokenRewriteStream.InsertAfter(const ProgramName: String; 5930 const Index: Integer; const Text: IANTLRInterface); 5931begin 5932 // to insert after, just insert before next index (even if past end) 5933 InsertBefore(ProgramName, Index + 1, Text); 5934end; 5935 5936procedure TTokenRewriteStream.InsertAfter(const T: IToken; 5937 const Text: IANTLRInterface); 5938begin 5939 InsertAfter(DEFAULT_PROGRAM_NAME, T, Text); 5940end; 5941 5942procedure TTokenRewriteStream.InsertAfter(const Index: Integer; 5943 const Text: IANTLRInterface); 5944begin 5945 InsertAfter(DEFAULT_PROGRAM_NAME, Index, Text); 5946end; 5947 5948procedure TTokenRewriteStream.InsertBefore(const Index: Integer; 5949 const Text: IANTLRInterface); 5950begin 5951 InsertBefore(DEFAULT_PROGRAM_NAME, Index, Text); 5952end; 5953 5954procedure TTokenRewriteStream.InsertBefore(const ProgramName: String; 5955 const T: IToken; const Text: IANTLRInterface); 5956begin 5957 InsertBefore(ProgramName, T.TokenIndex, Text); 5958end; 5959 5960procedure TTokenRewriteStream.InsertBefore(const ProgramName: String; 5961 const Index: Integer; const Text: IANTLRInterface); 5962var 5963 Op: IRewriteOperation; 5964begin 5965 Op := TInsertBeforeOp.Create(Index, Text, Self); 5966 GetProgram(ProgramName).Add(Op); 5967end; 5968 5969procedure TTokenRewriteStream.InsertBefore(const T: IToken; 5970 const Text: IANTLRInterface); 5971begin 5972 InsertBefore(DEFAULT_PROGRAM_NAME, T, Text); 5973end; 5974 5975procedure TTokenRewriteStream.Replace(const Start, Stop: IToken; 5976 const Text: IANTLRInterface); 5977begin 5978 Replace(DEFAULT_PROGRAM_NAME, Stop, Stop, Text); 5979end; 5980 5981procedure TTokenRewriteStream.Replace(const IndexT: IToken; 5982 const Text: IANTLRInterface); 5983begin 5984 Replace(DEFAULT_PROGRAM_NAME, IndexT, IndexT, Text); 5985end; 5986 5987procedure TTokenRewriteStream.Replace(const ProgramName: String; const Start, 5988 Stop: Integer; const Text: IANTLRInterface); 5989var 5990 Op: IRewriteOperation; 5991 Rewrites: IList<IRewriteOperation>; 5992begin 5993 if (Start > Stop) or (Start < 0) or (Stop < 0) or (Stop >= GetTokens.Count) then 5994 raise EArgumentOutOfRangeException.Create('replace: range invalid: ' 5995 + IntToStr(Start) + '..' + IntToStr(Stop) + '(size=' 5996 + IntToStr(GetTokens.Count) + ')'); 5997 5998 Op := TReplaceOp.Create(Start, Stop, Text, Self); 5999 Rewrites := GetProgram(ProgramName); 6000 Op.InstructionIndex := Rewrites.Count; 6001 Rewrites.Add(Op); 6002end; 6003 6004function TTokenRewriteStream.ReduceToSingleOperationPerIndex( 6005 const Rewrites: IList<IRewriteOperation>): IDictionary<Integer, IRewriteOperation>; 6006var 6007 I, J: Integer; 6008 Op: IRewriteOperation; 6009 ROp, PrevROp: IReplaceOp; 6010 IOp, PrevIOp: IInsertBeforeOp; 6011 Inserts, PrevInserts, PrevReplaces: IList<IRewriteOperation>; 6012 Disjoint, Same: Boolean; 6013begin 6014 // WALK REPLACES 6015 for I := 0 to Rewrites.Count - 1 do 6016 begin 6017 Op := Rewrites[I]; 6018 if (Op = nil) then 6019 Continue; 6020 if (not Supports(Op, IReplaceOp, ROp)) then 6021 Continue; 6022 6023 // Wipe prior inserts within range 6024 Inserts := GetKindOfOps(Rewrites, IInsertBeforeOp, I); 6025 for J := 0 to Inserts.Count - 1 do 6026 begin 6027 IOp := Inserts[J] as IInsertBeforeOp; 6028 if (IOp.Index >= ROp.Index) and (IOp.Index <= ROp.LastIndex) then 6029 begin 6030 // delete insert as it's a no-op. 6031 Rewrites[IOp.InstructionIndex] := nil; 6032 end; 6033 end; 6034 6035 // Drop any prior replaces contained within 6036 PrevReplaces := GetKindOfOps(Rewrites, IReplaceOp, I); 6037 for J := 0 to PrevReplaces.Count - 1 do 6038 begin 6039 PrevROp := PrevReplaces[J] as IReplaceOp; 6040 if (PrevROp.Index >= ROp.Index) and (PrevROp.LastIndex <= ROp.LastIndex) then 6041 begin 6042 // delete replace as it's a no-op. 6043 Rewrites[PrevROp.InstructionIndex] := nil; 6044 Continue; 6045 end; 6046 // throw exception unless disjoint or identical 6047 Disjoint := (PrevROp.LastIndex < ROp.Index) or (PrevROp.Index > ROp.LastIndex); 6048 Same := (PrevROp.Index = ROp.Index) and (PrevROp.LastIndex = ROp.LastIndex); 6049 if (not Disjoint) and (not Same) then 6050 raise EArgumentOutOfRangeException.Create('replace of boundaries of ' 6051 + ROp.ToString + ' overlap with previous ' + PrevROp.ToString); 6052 end; 6053 end; 6054 6055 // WALK INSERTS 6056 for I := 0 to Rewrites.Count - 1 do 6057 begin 6058 Op := Rewrites[I]; 6059 if (Op = nil) then 6060 Continue; 6061 if (not Supports(Op, IInsertBeforeOp, IOp)) then 6062 Continue; 6063 6064 // combine current insert with prior if any at same index 6065 PrevInserts := GetKindOfOps(Rewrites, IInsertBeforeOp, I); 6066 for J := 0 to PrevInserts.Count - 1 do 6067 begin 6068 PrevIOp := PrevInserts[J] as IInsertBeforeOp; 6069 if (PrevIOp.Index = IOp.Index) then 6070 begin 6071 // combine objects 6072 // convert to strings...we're in process of toString'ing 6073 // whole token buffer so no lazy eval issue with any templates 6074 IOp.Text := CatOpText(IOp.Text, PrevIOp.Text); 6075 // delete redundant prior insert 6076 Rewrites[PrevIOp.InstructionIndex] := nil; 6077 end; 6078 end; 6079 6080 // look for replaces where iop.index is in range; error 6081 PrevReplaces := GetKindOfOps(Rewrites, IReplaceOp, I); 6082 for J := 0 to PrevReplaces.Count - 1 do 6083 begin 6084 Rop := PrevReplaces[J] as IReplaceOp; 6085 if (IOp.Index = ROp.Index) then 6086 begin 6087 ROp.Text := CatOpText(IOp.Text, ROp.Text); 6088 Rewrites[I] := nil; // delete current insert 6089 Continue; 6090 end; 6091 if (IOp.Index >= ROp.Index) and (IOp.Index <= ROp.LastIndex) then 6092 raise EArgumentOutOfRangeException.Create('insert op ' 6093 + IOp.ToString + ' within boundaries of previous ' + ROp.ToString); 6094 end; 6095 end; 6096 6097 Result := TDictionary<Integer, IRewriteOperation>.Create; 6098 for Op in Rewrites do 6099 begin 6100 if (Op = nil) then 6101 Continue; // ignore deleted ops 6102 if (Result.ContainsKey(Op.Index)) then 6103 raise Exception.Create('should only be one op per index'); 6104 Result.Add(Op.Index, Op); 6105 end; 6106end; 6107 6108procedure TTokenRewriteStream.Replace(const ProgramName: String; const Start, 6109 Stop: IToken; const Text: IANTLRInterface); 6110begin 6111 Replace(ProgramName, Start.TokenIndex, Stop.TokenIndex, Text); 6112end; 6113 6114procedure TTokenRewriteStream.Replace(const Index: Integer; 6115 const Text: IANTLRInterface); 6116begin 6117 Replace(DEFAULT_PROGRAM_NAME, Index, Index, Text); 6118end; 6119 6120procedure TTokenRewriteStream.Replace(const Start, Stop: Integer; 6121 const Text: IANTLRInterface); 6122begin 6123 Replace(DEFAULT_PROGRAM_NAME, Start, Stop, Text); 6124end; 6125 6126procedure TTokenRewriteStream.Rollback(const InstructionIndex: Integer); 6127begin 6128 Rollback(DEFAULT_PROGRAM_NAME, InstructionIndex); 6129end; 6130 6131procedure TTokenRewriteStream.Rollback(const ProgramName: String; 6132 const InstructionIndex: Integer); 6133var 6134 InstructionStream: IList<IRewriteOperation>; 6135begin 6136 InstructionStream := FPrograms[ProgramName]; 6137 if Assigned(InstructionStream) then 6138 FPrograms[ProgramName] := InstructionStream.GetRange(MIN_TOKEN_INDEX, 6139 InstructionIndex - MIN_TOKEN_INDEX); 6140end; 6141 6142procedure TTokenRewriteStream.SetLastRewriteTokenIndex( 6143 const ProgramName: String; const I: Integer); 6144begin 6145 FLastRewriteTokenIndexes[ProgramName] := I; 6146end; 6147 6148function TTokenRewriteStream.ToDebugString: String; 6149begin 6150 Result := ToDebugString(MIN_TOKEN_INDEX, Size - 1); 6151end; 6152 6153function TTokenRewriteStream.ToDebugString(const Start, Stop: Integer): String; 6154var 6155 Buf: TStringBuilder; 6156 I: Integer; 6157begin 6158 Buf := TStringBuilder.Create; 6159 try 6160 if (Start >= MIN_TOKEN_INDEX) then 6161 for I := Start to Min(Stop,GetTokens.Count - 1) do 6162 Buf.Append(Get(I).ToString); 6163 finally 6164 Buf.Free; 6165 end; 6166end; 6167 6168function TTokenRewriteStream.ToOriginalString: String; 6169begin 6170 Result := ToOriginalString(MIN_TOKEN_INDEX, Size - 1); 6171end; 6172 6173function TTokenRewriteStream.ToOriginalString(const Start, 6174 Stop: Integer): String; 6175var 6176 Buf: TStringBuilder; 6177 I: Integer; 6178begin 6179 Buf := TStringBuilder.Create; 6180 try 6181 if (Start >= MIN_TOKEN_INDEX) then 6182 for I := Start to Min(Stop, GetTokens.Count - 1) do 6183 Buf.Append(Get(I).Text); 6184 Result := Buf.ToString; 6185 finally 6186 Buf.Free; 6187 end; 6188end; 6189 6190function TTokenRewriteStream.ToString: String; 6191begin 6192 Result := ToString(MIN_TOKEN_INDEX, Size - 1); 6193end; 6194 6195function TTokenRewriteStream.ToString(const ProgramName: String): String; 6196begin 6197 Result := ToString(ProgramName, MIN_TOKEN_INDEX, Size - 1); 6198end; 6199 6200function TTokenRewriteStream.ToString(const ProgramName: String; const Start, 6201 Stop: Integer): String; 6202var 6203 Rewrites: IList<IRewriteOperation>; 6204 I, StartIndex, StopIndex: Integer; 6205 IndexToOp: IDictionary<Integer, IRewriteOperation>; 6206 Buf: TStringBuilder; 6207 Tokens: IList<IToken>; 6208 T: IToken; 6209 Op: IRewriteOperation; 6210 Pair: TPair<Integer, IRewriteOperation>; 6211begin 6212 Rewrites := FPrograms[ProgramName]; 6213 Tokens := GetTokens; 6214 // ensure start/end are in range 6215 StopIndex := Min(Stop,Tokens.Count - 1); 6216 StartIndex := Max(Start,0); 6217 6218 if (Rewrites = nil) or (Rewrites.Count = 0) then 6219 begin 6220 // no instructions to execute 6221 Result := ToOriginalString(StartIndex, StopIndex); 6222 Exit; 6223 end; 6224 6225 Buf := TStringBuilder.Create; 6226 try 6227 // First, optimize instruction stream 6228 IndexToOp := ReduceToSingleOperationPerIndex(Rewrites); 6229 6230 // Walk buffer, executing instructions and emitting tokens 6231 I := StartIndex; 6232 while (I <= StopIndex) and (I < Tokens.Count) do 6233 begin 6234 if (not IndexToOp.TryGetValue(I, Op)) then 6235 Op := nil; 6236 IndexToOp.Remove(I); // remove so any left have index size-1 6237 T := Tokens[I]; 6238 if (Op = nil) then 6239 begin 6240 // no operation at that index, just dump token 6241 Buf.Append(T.Text); 6242 Inc(I); // move to next token 6243 end 6244 else 6245 I := Op.Execute(Buf); // execute operation and skip 6246 end; 6247 6248 // include stuff after end if it's last index in buffer 6249 // So, if they did an insertAfter(lastValidIndex, "foo"), include 6250 // foo if end==lastValidIndex. 6251 if (StopIndex = Tokens.Count - 1) then 6252 begin 6253 // Scan any remaining operations after last token 6254 // should be included (they will be inserts). 6255 for Pair in IndexToOp do 6256 begin 6257 if (Pair.Value.Index >= Tokens.Count - 1) then 6258 Buf.Append(Pair.Value.Text.ToString); 6259 end; 6260 end; 6261 Result := Buf.ToString; 6262 finally 6263 Buf.Free; 6264 end; 6265end; 6266 6267function TTokenRewriteStream.ToString(const Start, Stop: Integer): String; 6268begin 6269 Result := ToString(DEFAULT_PROGRAM_NAME, Start, Stop); 6270end; 6271 6272procedure TTokenRewriteStream.InsertBefore(const Index: Integer; 6273 const Text: String); 6274var 6275 S: IANTLRString; 6276begin 6277 S := TANTLRString.Create(Text); 6278 InsertBefore(Index, S); 6279end; 6280 6281procedure TTokenRewriteStream.InsertBefore(const T: IToken; const Text: String); 6282var 6283 S: IANTLRString; 6284begin 6285 S := TANTLRString.Create(Text); 6286 InsertBefore(T, S); 6287end; 6288 6289procedure TTokenRewriteStream.InsertBefore(const ProgramName: String; 6290 const Index: Integer; const Text: String); 6291var 6292 S: IANTLRString; 6293begin 6294 S := TANTLRString.Create(Text); 6295 InsertBefore(ProgramName, Index, S); 6296end; 6297 6298procedure TTokenRewriteStream.InsertBefore(const ProgramName: String; 6299 const T: IToken; const Text: String); 6300var 6301 S: IANTLRString; 6302begin 6303 S := TANTLRString.Create(Text); 6304 InsertBefore(ProgramName, T, S); 6305end; 6306 6307procedure TTokenRewriteStream.InsertAfter(const Index: Integer; 6308 const Text: String); 6309var 6310 S: IANTLRString; 6311begin 6312 S := TANTLRString.Create(Text); 6313 InsertAfter(Index,S); 6314end; 6315 6316procedure TTokenRewriteStream.InsertAfter(const T: IToken; const Text: String); 6317var 6318 S: IANTLRString; 6319begin 6320 S := TANTLRString.Create(Text); 6321 InsertAfter(T,S); 6322end; 6323 6324procedure TTokenRewriteStream.InsertAfter(const ProgramName: String; 6325 const Index: Integer; const Text: String); 6326var 6327 S: IANTLRString; 6328begin 6329 S := TANTLRString.Create(Text); 6330 InsertAfter(ProgramName,Index,S); 6331end; 6332 6333procedure TTokenRewriteStream.InsertAfter(const ProgramName: String; 6334 const T: IToken; const Text: String); 6335var 6336 S: IANTLRString; 6337begin 6338 S := TANTLRString.Create(Text); 6339 InsertAfter(ProgramName,T,S); 6340end; 6341 6342procedure TTokenRewriteStream.Replace(const IndexT: IToken; const Text: String); 6343var 6344 S: IANTLRString; 6345begin 6346 S := TANTLRString.Create(Text); 6347 Replace(IndexT, S); 6348end; 6349 6350procedure TTokenRewriteStream.Replace(const Start, Stop: Integer; 6351 const Text: String); 6352var 6353 S: IANTLRString; 6354begin 6355 S := TANTLRString.Create(Text); 6356 Replace(Start, Stop, S); 6357end; 6358 6359procedure TTokenRewriteStream.Replace(const Index: Integer; const Text: String); 6360var 6361 S: IANTLRString; 6362begin 6363 S := TANTLRString.Create(Text); 6364 Replace(Index, S); 6365end; 6366 6367procedure TTokenRewriteStream.Replace(const ProgramName: String; const Start, 6368 Stop: IToken; const Text: String); 6369var 6370 S: IANTLRString; 6371begin 6372 S := TANTLRString.Create(Text); 6373 Replace(ProgramName, Start, Stop, S); 6374end; 6375 6376procedure TTokenRewriteStream.Replace(const ProgramName: String; const Start, 6377 Stop: Integer; const Text: String); 6378var 6379 S: IANTLRString; 6380begin 6381 S := TANTLRString.Create(Text); 6382 Replace(ProgramName, Start, Stop, S); 6383end; 6384 6385procedure TTokenRewriteStream.Replace(const Start, Stop: IToken; 6386 const Text: String); 6387var 6388 S: IANTLRString; 6389begin 6390 S := TANTLRString.Create(Text); 6391 Replace(Start, Stop, S); 6392end; 6393 6394{ TTokenRewriteStream.TRewriteOperation } 6395 6396constructor TTokenRewriteStream.TRewriteOperation.Create(const AIndex: Integer; 6397 const AText: IANTLRInterface; const AParent: ITokenRewriteStream); 6398begin 6399 inherited Create; 6400 FIndex := AIndex; 6401 FText := AText; 6402 FParent := Pointer(AParent); 6403end; 6404 6405function TTokenRewriteStream.TRewriteOperation.Execute( 6406 const Buf: TStringBuilder): Integer; 6407begin 6408 Result := FIndex; 6409end; 6410 6411function TTokenRewriteStream.TRewriteOperation.GetIndex: Integer; 6412begin 6413 Result := FIndex; 6414end; 6415 6416function TTokenRewriteStream.TRewriteOperation.GetInstructionIndex: Integer; 6417begin 6418 Result := FInstructionIndex; 6419end; 6420 6421function TTokenRewriteStream.TRewriteOperation.GetParent: ITokenRewriteStream; 6422begin 6423 Result := ITokenRewriteStream(FParent); 6424end; 6425 6426function TTokenRewriteStream.TRewriteOperation.GetText: IANTLRInterface; 6427begin 6428 Result := FText; 6429end; 6430 6431procedure TTokenRewriteStream.TRewriteOperation.SetIndex(const Value: Integer); 6432begin 6433 FIndex := Value; 6434end; 6435 6436procedure TTokenRewriteStream.TRewriteOperation.SetInstructionIndex( 6437 const Value: Integer); 6438begin 6439 FInstructionIndex := Value; 6440end; 6441 6442procedure TTokenRewriteStream.TRewriteOperation.SetParent( 6443 const Value: ITokenRewriteStream); 6444begin 6445 FParent := Pointer(Value); 6446end; 6447 6448procedure TTokenRewriteStream.TRewriteOperation.SetText( 6449 const Value: IANTLRInterface); 6450begin 6451 FText := Value; 6452end; 6453 6454function TTokenRewriteStream.TRewriteOperation.ToString: String; 6455var 6456 OpName: String; 6457 DollarIndex: Integer; 6458begin 6459 OpName := ClassName; 6460 DollarIndex := Pos('$',OpName) - 1; // Delphi strings are 1-based 6461 if (DollarIndex >= 0) then 6462 OpName := Copy(OpName,DollarIndex + 1,Length(OpName) - (DollarIndex + 1)); 6463 Result := '<' + OpName + '@' + IntToStr(FIndex) + ':"' + FText.ToString + '">'; 6464end; 6465 6466{ TTokenRewriteStream.TRewriteOpComparer<T> } 6467 6468function TTokenRewriteStream.TRewriteOpComparer<T>.Compare(const Left, 6469 Right: T): Integer; 6470begin 6471 if (Left.GetIndex < Right.GetIndex) then 6472 Result := -1 6473 else 6474 if (Left.GetIndex > Right.GetIndex) then 6475 Result := 1 6476 else 6477 Result := 0; 6478end; 6479 6480{ TTokenRewriteStream.TInsertBeforeOp } 6481 6482function TTokenRewriteStream.TInsertBeforeOp.Execute( 6483 const Buf: TStringBuilder): Integer; 6484begin 6485 Buf.Append(Text.ToString); 6486 Buf.Append(Parent.Get(Index).Text); 6487 Result := Index + 1; 6488end; 6489 6490{ TTokenRewriteStream.TReplaceOp } 6491 6492constructor TTokenRewriteStream.TReplaceOp.Create(const AStart, AStop: Integer; 6493 const AText: IANTLRInterface; const AParent: ITokenRewriteStream); 6494begin 6495 inherited Create(AStart, AText, AParent); 6496 FLastIndex := AStop; 6497end; 6498 6499function TTokenRewriteStream.TReplaceOp.Execute( 6500 const Buf: TStringBuilder): Integer; 6501begin 6502 if (Text <> nil) then 6503 Buf.Append(Text.ToString); 6504 Result := FLastIndex + 1; 6505end; 6506 6507function TTokenRewriteStream.TReplaceOp.GetLastIndex: Integer; 6508begin 6509 Result := FLastIndex; 6510end; 6511 6512procedure TTokenRewriteStream.TReplaceOp.SetLastIndex(const Value: Integer); 6513begin 6514 FLastIndex := Value; 6515end; 6516 6517function TTokenRewriteStream.TReplaceOp.ToString: String; 6518begin 6519 Result := '<ReplaceOp@' + IntToStr(Index) + '..' + IntToStr(FLastIndex) 6520 + ':"' + Text.ToString + '">'; 6521end; 6522 6523{ TTokenRewriteStream.TDeleteOp } 6524 6525function TTokenRewriteStream.TDeleteOp.ToString: String; 6526begin 6527 Result := '<DeleteOp@' + IntToStr(Index) + '..' + IntToStr(FLastIndex) + '>'; 6528end; 6529 6530{ Utilities } 6531 6532var 6533 EmptyToken: IToken = nil; 6534 EmptyRuleReturnScope: IRuleReturnScope = nil; 6535 6536function Def(const X: IToken): IToken; overload; 6537begin 6538 if Assigned(X) then 6539 Result := X 6540 else 6541 begin 6542 if (EmptyToken = nil) then 6543 EmptyToken := TCommonToken.Create; 6544 Result := EmptyToken; 6545 end; 6546end; 6547 6548function Def(const X: IRuleReturnScope): IRuleReturnScope; 6549begin 6550 if Assigned(X) then 6551 Result := X 6552 else 6553 begin 6554 if (EmptyRuleReturnScope = nil) then 6555 EmptyRuleReturnScope := TRuleReturnScope.Create; 6556 Result := EmptyRuleReturnScope; 6557 end; 6558end; 6559 6560initialization 6561 TToken.Initialize; 6562 6563end. 6564