1 /* 2 [The "BSD license"] 3 Copyright (c) 2005-2009 Terence Parr 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions 8 are met: 9 1. Redistributions of source code must retain the above copyright 10 notice, this list of conditions and the following disclaimer. 11 2. Redistributions in binary form must reproduce the above copyright 12 notice, this list of conditions and the following disclaimer in the 13 documentation and/or other materials provided with the distribution. 14 3. The name of the author may not be used to endorse or promote products 15 derived from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 package org.antlr.runtime; 29 30 import java.util.*; 31 32 /** The most common stream of tokens is one where every token is buffered up 33 * and tokens are prefiltered for a certain channel (the parser will only 34 * see these tokens and cannot change the filter channel number during the 35 * parse). 36 * 37 * TODO: how to access the full token stream? How to track all tokens matched per rule? 38 */ 39 public class LegacyCommonTokenStream implements TokenStream { 40 protected TokenSource tokenSource; 41 42 /** Record every single token pulled from the source so we can reproduce 43 * chunks of it later. 44 */ 45 protected List tokens; 46 47 /** Map<tokentype, channel> to override some Tokens' channel numbers */ 48 protected Map channelOverrideMap; 49 50 /** Set<tokentype>; discard any tokens with this type */ 51 protected Set discardSet; 52 53 /** Skip tokens on any channel but this one; this is how we skip whitespace... */ 54 protected int channel = Token.DEFAULT_CHANNEL; 55 56 /** By default, track all incoming tokens */ 57 protected boolean discardOffChannelTokens = false; 58 59 /** Track the last mark() call result value for use in rewind(). */ 60 protected int lastMarker; 61 62 protected int range = -1; // how deep have we gone? 63 64 /** The index into the tokens list of the current token (next token 65 * to consume). p==-1 indicates that the tokens list is empty 66 */ 67 protected int p = -1; 68 69 public LegacyCommonTokenStream() { 70 tokens = new ArrayList(500); 71 } 72 73 public LegacyCommonTokenStream(TokenSource tokenSource) { 74 this(); 75 this.tokenSource = tokenSource; 76 } 77 78 public LegacyCommonTokenStream(TokenSource tokenSource, int channel) { 79 this(tokenSource); 80 this.channel = channel; 81 } 82 83 /** Reset this token stream by setting its token source. */ 84 public void setTokenSource(TokenSource tokenSource) { 85 this.tokenSource = tokenSource; 86 tokens.clear(); 87 p = -1; 88 channel = Token.DEFAULT_CHANNEL; 89 } 90 91 /** Load all tokens from the token source and put in tokens. 92 * This is done upon first LT request because you might want to 93 * set some token type / channel overrides before filling buffer. 94 */ 95 protected void fillBuffer() { 96 int index = 0; 97 Token t = tokenSource.nextToken(); 98 while ( t!=null && t.getType()!=CharStream.EOF ) { 99 boolean discard = false; 100 // is there a channel override for token type? 101 if ( channelOverrideMap!=null ) { 102 Integer channelI = (Integer) 103 channelOverrideMap.get(new Integer(t.getType())); 104 if ( channelI!=null ) { 105 t.setChannel(channelI.intValue()); 106 } 107 } 108 if ( discardSet!=null && 109 discardSet.contains(new Integer(t.getType())) ) 110 { 111 discard = true; 112 } 113 else if ( discardOffChannelTokens && t.getChannel()!=this.channel ) { 114 discard = true; 115 } 116 if ( !discard ) { 117 t.setTokenIndex(index); 118 tokens.add(t); 119 index++; 120 } 121 t = tokenSource.nextToken(); 122 } 123 // leave p pointing at first token on channel 124 p = 0; 125 p = skipOffTokenChannels(p); 126 } 127 128 /** Move the input pointer to the next incoming token. The stream 129 * must become active with LT(1) available. consume() simply 130 * moves the input pointer so that LT(1) points at the next 131 * input symbol. Consume at least one token. 132 * 133 * Walk past any token not on the channel the parser is listening to. 134 */ 135 public void consume() { 136 if ( p<tokens.size() ) { 137 p++; 138 p = skipOffTokenChannels(p); // leave p on valid token 139 } 140 } 141 142 /** Given a starting index, return the index of the first on-channel 143 * token. 144 */ 145 protected int skipOffTokenChannels(int i) { 146 int n = tokens.size(); 147 while ( i<n && ((Token)tokens.get(i)).getChannel()!=channel ) { 148 i++; 149 } 150 return i; 151 } 152 153 protected int skipOffTokenChannelsReverse(int i) { 154 while ( i>=0 && ((Token)tokens.get(i)).getChannel()!=channel ) { 155 i--; 156 } 157 return i; 158 } 159 160 /** A simple filter mechanism whereby you can tell this token stream 161 * to force all tokens of type ttype to be on channel. For example, 162 * when interpreting, we cannot exec actions so we need to tell 163 * the stream to force all WS and NEWLINE to be a different, ignored 164 * channel. 165 */ 166 public void setTokenTypeChannel(int ttype, int channel) { 167 if ( channelOverrideMap==null ) { 168 channelOverrideMap = new HashMap(); 169 } 170 channelOverrideMap.put(new Integer(ttype), new Integer(channel)); 171 } 172 173 public void discardTokenType(int ttype) { 174 if ( discardSet==null ) { 175 discardSet = new HashSet(); 176 } 177 discardSet.add(new Integer(ttype)); 178 } 179 180 public void discardOffChannelTokens(boolean discardOffChannelTokens) { 181 this.discardOffChannelTokens = discardOffChannelTokens; 182 } 183 184 public List getTokens() { 185 if ( p == -1 ) { 186 fillBuffer(); 187 } 188 return tokens; 189 } 190 191 public List getTokens(int start, int stop) { 192 return getTokens(start, stop, (BitSet)null); 193 } 194 195 /** Given a start and stop index, return a List of all tokens in 196 * the token type BitSet. Return null if no tokens were found. This 197 * method looks at both on and off channel tokens. 198 */ 199 public List getTokens(int start, int stop, BitSet types) { 200 if ( p == -1 ) { 201 fillBuffer(); 202 } 203 if ( stop>=tokens.size() ) { 204 stop=tokens.size()-1; 205 } 206 if ( start<0 ) { 207 start=0; 208 } 209 if ( start>stop ) { 210 return null; 211 } 212 213 // list = tokens[start:stop]:{Token t, t.getType() in types} 214 List filteredTokens = new ArrayList(); 215 for (int i=start; i<=stop; i++) { 216 Token t = (Token)tokens.get(i); 217 if ( types==null || types.member(t.getType()) ) { 218 filteredTokens.add(t); 219 } 220 } 221 if ( filteredTokens.size()==0 ) { 222 filteredTokens = null; 223 } 224 return filteredTokens; 225 } 226 227 public List getTokens(int start, int stop, List types) { 228 return getTokens(start,stop,new BitSet(types)); 229 } 230 231 public List getTokens(int start, int stop, int ttype) { 232 return getTokens(start,stop,BitSet.of(ttype)); 233 } 234 235 /** Get the ith token from the current position 1..n where k=1 is the 236 * first symbol of lookahead. 237 */ 238 public Token LT(int k) { 239 if ( p == -1 ) { 240 fillBuffer(); 241 } 242 if ( k==0 ) { 243 return null; 244 } 245 if ( k<0 ) { 246 return LB(-k); 247 } 248 //System.out.print("LT(p="+p+","+k+")="); 249 if ( (p+k-1) >= tokens.size() ) { 250 return (Token)tokens.get(tokens.size()-1); 251 } 252 //System.out.println(tokens.get(p+k-1)); 253 int i = p; 254 int n = 1; 255 // find k good tokens 256 while ( n<k ) { 257 // skip off-channel tokens 258 i = skipOffTokenChannels(i+1); // leave p on valid token 259 n++; 260 } 261 if ( i>=tokens.size() ) { 262 return (Token)tokens.get(tokens.size()-1); // must be EOF 263 } 264 265 if ( i>range ) range = i; 266 return (Token)tokens.get(i); 267 } 268 269 /** Look backwards k tokens on-channel tokens */ 270 protected Token LB(int k) { 271 //System.out.print("LB(p="+p+","+k+") "); 272 if ( p == -1 ) { 273 fillBuffer(); 274 } 275 if ( k==0 ) { 276 return null; 277 } 278 if ( (p-k)<0 ) { 279 return null; 280 } 281 282 int i = p; 283 int n = 1; 284 // find k good tokens looking backwards 285 while ( n<=k ) { 286 // skip off-channel tokens 287 i = skipOffTokenChannelsReverse(i-1); // leave p on valid token 288 n++; 289 } 290 if ( i<0 ) { 291 return null; 292 } 293 return (Token)tokens.get(i); 294 } 295 296 /** Return absolute token i; ignore which channel the tokens are on; 297 * that is, count all tokens not just on-channel tokens. 298 */ 299 public Token get(int i) { 300 return (Token)tokens.get(i); 301 } 302 303 /** Get all tokens from start..stop inclusively */ 304 public List get(int start, int stop) { 305 if ( p == -1 ) fillBuffer(); 306 if ( start<0 || stop<0 ) return null; 307 return tokens.subList(start, stop); 308 } 309 310 public int LA(int i) { 311 return LT(i).getType(); 312 } 313 314 public int mark() { 315 if ( p == -1 ) { 316 fillBuffer(); 317 } 318 lastMarker = index(); 319 return lastMarker; 320 } 321 322 public void release(int marker) { 323 // no resources to release 324 } 325 326 public int size() { 327 return tokens.size(); 328 } 329 330 public int index() { 331 return p; 332 } 333 334 public int range() { 335 return range; 336 } 337 338 public void rewind(int marker) { 339 seek(marker); 340 } 341 342 public void rewind() { 343 seek(lastMarker); 344 } 345 346 public void reset() { 347 p = 0; 348 lastMarker = 0; 349 } 350 351 public void seek(int index) { 352 p = index; 353 } 354 355 public TokenSource getTokenSource() { 356 return tokenSource; 357 } 358 359 public String getSourceName() { 360 return getTokenSource().getSourceName(); 361 } 362 363 public String toString() { 364 if ( p == -1 ) { 365 fillBuffer(); 366 } 367 return toString(0, tokens.size()-1); 368 } 369 370 public String toString(int start, int stop) { 371 if ( start<0 || stop<0 ) { 372 return null; 373 } 374 if ( p == -1 ) { 375 fillBuffer(); 376 } 377 if ( stop>=tokens.size() ) { 378 stop = tokens.size()-1; 379 } 380 StringBuffer buf = new StringBuffer(); 381 for (int i = start; i <= stop; i++) { 382 Token t = (Token)tokens.get(i); 383 buf.append(t.getText()); 384 } 385 return buf.toString(); 386 } 387 388 public String toString(Token start, Token stop) { 389 if ( start!=null && stop!=null ) { 390 return toString(start.getTokenIndex(), stop.getTokenIndex()); 391 } 392 return null; 393 } 394 } 395