1 /* 2 * [The "BSD license"] 3 * Copyright (c) 2011 Terence Parr 4 * All rights reserved. 5 * 6 * Conversion to C#: 7 * Copyright (c) 2011 Sam Harwell, Pixel Mine, Inc. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 namespace Antlr.Runtime 34 { 35 using System.Collections.Generic; 36 using System; 37 using System.Text; 38 39 /** <summary> 40 * A pretty quick CharStream that pulls all data from an array 41 * directly. Every method call counts in the lexer. Java's 42 * strings aren't very good so I'm avoiding. 43 * </summary> 44 */ 45 [System.Serializable] 46 public class FastTokenStream 47 : ITokenStream<SlimToken> 48 { 49 [System.NonSerialized] 50 ITokenSource<SlimToken> _tokenSource; 51 52 /** <summary> 53 * Record every single token pulled from the source so we can reproduce 54 * chunks of it later. 55 * </summary> 56 */ 57 protected List<SlimToken> tokens; 58 59 /** <summary>Skip tokens on any channel but this one; this is how we skip whitespace...</summary> */ 60 protected int channel = TokenChannels.Default; 61 62 /** <summary>Track the last mark() call result value for use in rewind().</summary> */ 63 protected int lastMarker; 64 65 /** <summary> 66 * The index into the tokens list of the current token (next token 67 * to consume). p==-1 indicates that the tokens list is empty 68 * </summary> 69 */ 70 protected int p = -1; 71 FastTokenStream()72 public FastTokenStream() 73 { 74 tokens = new List<SlimToken>( 500 ); 75 } 76 FastTokenStream( ITokenSource<SlimToken> tokenSource )77 public FastTokenStream( ITokenSource<SlimToken> tokenSource ) 78 : this() 79 { 80 this._tokenSource = tokenSource; 81 } 82 FastTokenStream( ITokenSource<SlimToken> tokenSource, int channel )83 public FastTokenStream( ITokenSource<SlimToken> tokenSource, int channel ) 84 : this( tokenSource ) 85 { 86 this.channel = channel; 87 } 88 89 public int Index 90 { 91 get 92 { 93 return p; 94 } 95 } 96 97 /** <summary>Reset this token stream by setting its token source.</summary> */ SetTokenSource( ITokenSource<SlimToken> tokenSource )98 public void SetTokenSource( ITokenSource<SlimToken> tokenSource ) 99 { 100 this._tokenSource = tokenSource; 101 tokens.Clear(); 102 p = -1; 103 channel = TokenChannels.Default; 104 } 105 106 /** <summary> 107 * Load all tokens from the token source and put in tokens. 108 * This is done upon first LT request because you might want to 109 * set some token type / channel overrides before filling buffer. 110 * </summary> 111 */ FillBuffer()112 public void FillBuffer() 113 { 114 // fast return if the buffer is already full 115 if ( p != -1 ) 116 return; 117 118 int index = 0; 119 SlimToken t = _tokenSource.NextToken(); 120 while ( t.Type != CharStreamConstants.EndOfFile ) 121 { 122 //t.TokenIndex = index; 123 tokens.Add( t ); 124 index++; 125 126 t = _tokenSource.NextToken(); 127 } 128 // leave p pointing at first token on channel 129 p = 0; 130 p = SkipOffTokenChannels( p ); 131 } 132 133 /** <summary> 134 * Move the input pointer to the next incoming token. The stream 135 * must become active with LT(1) available. consume() simply 136 * moves the input pointer so that LT(1) points at the next 137 * input symbol. Consume at least one token. 138 * </summary> 139 * 140 * <remarks> 141 * Walk past any token not on the channel the parser is listening to. 142 * </remarks> 143 */ Consume()144 public void Consume() 145 { 146 if ( p < tokens.Count ) 147 { 148 p++; 149 p = SkipOffTokenChannels( p ); // leave p on valid token 150 } 151 } 152 153 /** <summary>Given a starting index, return the index of the first on-channel token.</summary> */ SkipOffTokenChannels( int i )154 protected int SkipOffTokenChannels( int i ) 155 { 156 int n = tokens.Count; 157 while ( i < n && tokens[i].Channel != channel ) 158 { 159 i++; 160 } 161 return i; 162 } 163 SkipOffTokenChannelsReverse( int i )164 protected int SkipOffTokenChannelsReverse( int i ) 165 { 166 while ( i >= 0 && tokens[i].Channel != channel ) 167 { 168 i--; 169 } 170 return i; 171 } 172 GetTokens()173 public IList<SlimToken> GetTokens() 174 { 175 if ( p == -1 ) 176 { 177 FillBuffer(); 178 } 179 return tokens; 180 } 181 GetTokens( int start, int stop )182 public IList<SlimToken> GetTokens( int start, int stop ) 183 { 184 return GetTokens( start, stop, (BitSet)null ); 185 } 186 187 /** <summary> 188 * Given a start and stop index, return a List of all tokens in 189 * the token type BitSet. Return null if no tokens were found. This 190 * method looks at both on and off channel tokens. 191 * </summary> 192 */ GetTokens( int start, int stop, BitSet types )193 public IList<SlimToken> GetTokens( int start, int stop, BitSet types ) 194 { 195 if ( p == -1 ) 196 { 197 FillBuffer(); 198 } 199 if ( stop >= tokens.Count ) 200 { 201 stop = tokens.Count - 1; 202 } 203 if ( start < 0 ) 204 { 205 start = 0; 206 } 207 if ( start > stop ) 208 { 209 return null; 210 } 211 212 // list = tokens[start:stop]:{Token t, t.getType() in types} 213 List<SlimToken> filteredTokens = new List<SlimToken>(); 214 for ( int i = start; i <= stop; i++ ) 215 { 216 SlimToken t = tokens[i]; 217 if ( types == null || types.Member( t.Type ) ) 218 { 219 filteredTokens.Add( t ); 220 } 221 } 222 if ( filteredTokens.Count == 0 ) 223 { 224 filteredTokens = null; 225 } 226 return filteredTokens; 227 } 228 GetTokens( int start, int stop, IList<int> types )229 public IList<SlimToken> GetTokens( int start, int stop, IList<int> types ) 230 { 231 return GetTokens( start, stop, new BitSet( types ) ); 232 } 233 GetTokens( int start, int stop, int ttype )234 public IList<SlimToken> GetTokens( int start, int stop, int ttype ) 235 { 236 return GetTokens( start, stop, BitSet.Of( ttype ) ); 237 } 238 239 /** <summary> 240 * Get the ith token from the current position 1..n where k=1 is the 241 * first symbol of lookahead. 242 * </summary> 243 */ LT( int k )244 public SlimToken LT( int k ) 245 { 246 if ( p == -1 ) 247 { 248 FillBuffer(); 249 } 250 if ( k == 0 ) 251 { 252 return default( SlimToken ); 253 } 254 if ( k < 0 ) 255 { 256 return LB( -k ); 257 } 258 //System.out.print("LT(p="+p+","+k+")="); 259 if ( ( p + k - 1 ) >= tokens.Count ) 260 { 261 return new SlimToken(TokenTypes.EndOfFile); 262 } 263 //System.out.println(tokens.get(p+k-1)); 264 int i = p; 265 int n = 1; 266 // find k good tokens 267 while ( n < k ) 268 { 269 // skip off-channel tokens 270 i = SkipOffTokenChannels( i + 1 ); // leave p on valid token 271 n++; 272 } 273 if ( i >= tokens.Count ) 274 { 275 return new SlimToken(TokenTypes.EndOfFile); 276 } 277 return tokens[i]; 278 } 279 280 /** <summary>Look backwards k tokens on-channel tokens</summary> */ LB( int k )281 protected SlimToken LB( int k ) 282 { 283 //System.out.print("LB(p="+p+","+k+") "); 284 if ( p == -1 ) 285 { 286 FillBuffer(); 287 } 288 if ( k == 0 ) 289 { 290 return default( SlimToken ); 291 } 292 if ( ( p - k ) < 0 ) 293 { 294 return default( SlimToken ); 295 } 296 297 int i = p; 298 int n = 1; 299 // find k good tokens looking backwards 300 while ( n <= k ) 301 { 302 // skip off-channel tokens 303 i = SkipOffTokenChannelsReverse( i - 1 ); // leave p on valid token 304 n++; 305 } 306 if ( i < 0 ) 307 { 308 return default( SlimToken ); 309 } 310 return tokens[i]; 311 } 312 313 /** <summary> 314 * Return absolute token i; ignore which channel the tokens are on; 315 * that is, count all tokens not just on-channel tokens. 316 * </summary> 317 */ Get( int i )318 public SlimToken Get( int i ) 319 { 320 return tokens[i]; 321 } 322 LA( int i )323 public int LA( int i ) 324 { 325 return LT( i ).Type; 326 } 327 Mark()328 public int Mark() 329 { 330 if ( p == -1 ) 331 { 332 FillBuffer(); 333 } 334 lastMarker = Index; 335 return lastMarker; 336 } 337 Release( int marker )338 public void Release( int marker ) 339 { 340 // no resources to release 341 } 342 343 public int Count 344 { 345 get 346 { 347 return tokens.Count; 348 } 349 } 350 Rewind( int marker )351 public void Rewind( int marker ) 352 { 353 Seek( marker ); 354 } 355 Rewind()356 public void Rewind() 357 { 358 Seek( lastMarker ); 359 } 360 Reset()361 public void Reset() 362 { 363 p = 0; 364 lastMarker = 0; 365 } 366 Seek( int index )367 public void Seek( int index ) 368 { 369 p = index; 370 } 371 372 public ITokenSource<SlimToken> TokenSource 373 { 374 get 375 { 376 return _tokenSource; 377 } 378 } 379 380 public string SourceName 381 { 382 get 383 { 384 return TokenSource.SourceName; 385 } 386 } 387 ToString()388 public override string ToString() 389 { 390 if ( p == -1 ) 391 { 392 throw new InvalidOperationException( "Buffer is not yet filled." ); 393 } 394 return ToString( 0, tokens.Count - 1 ); 395 } 396 ToString( int start, int stop )397 public virtual string ToString( int start, int stop ) 398 { 399 if ( start < 0 || stop < 0 ) 400 { 401 return null; 402 } 403 if ( p == -1 ) 404 { 405 throw new InvalidOperationException( "Buffer is not yet filled." ); 406 } 407 if ( stop >= tokens.Count ) 408 { 409 stop = tokens.Count - 1; 410 } 411 StringBuilder buf = new StringBuilder(); 412 for ( int i = start; i <= stop; i++ ) 413 { 414 SlimToken t = tokens[i]; 415 SlimLexer lexer = _tokenSource as SlimLexer; 416 if ( lexer != null ) 417 { 418 SlimStringStream input = lexer.CharStream as SlimStringStream; 419 if ( input != null ) 420 { 421 string text = input.Substring( t.StartIndex, t.StopIndex - t.StartIndex + 1 ); 422 buf.Append( text ); 423 } 424 } 425 } 426 return buf.ToString(); 427 } 428 ToString( IToken start, IToken stop )429 public virtual string ToString( IToken start, IToken stop ) 430 { 431 if ( start != null && stop != null ) 432 { 433 return ToString( start.TokenIndex, stop.TokenIndex ); 434 } 435 return null; 436 } 437 } 438 } 439