Home | History | Annotate | Download | only in runtime
      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