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.ArrayList;
     31 import java.util.List;
     32 
     33 /** A pretty quick CharStream that pulls all data from an array
     34  *  directly.  Every method call counts in the lexer.  Java's
     35  *  strings aren't very good so I'm avoiding.
     36  */
     37 public class ANTLRStringStream implements CharStream {
     38 	/** The data being scanned */
     39 	protected char[] data;
     40 
     41 	/** How many characters are actually in the buffer */
     42 	protected int n;
     43 
     44 	/** 0..n-1 index into string of next char */
     45 	protected int p=0;
     46 
     47 	/** line number 1..n within the input */
     48 	protected int line = 1;
     49 
     50 	/** The index of the character relative to the beginning of the line 0..n-1 */
     51 	protected int charPositionInLine = 0;
     52 
     53 	/** tracks how deep mark() calls are nested */
     54 	protected int markDepth = 0;
     55 
     56 	/** A list of CharStreamState objects that tracks the stream state
     57 	 *  values line, charPositionInLine, and p that can change as you
     58 	 *  move through the input stream.  Indexed from 1..markDepth.
     59      *  A null is kept @ index 0.  Create upon first call to mark().
     60 	 */
     61 	protected List markers;
     62 
     63 	/** Track the last mark() call result value for use in rewind(). */
     64 	protected int lastMarker;
     65 
     66 	/** What is name or source of this char stream? */
     67 	public String name;
     68 
     69 	public ANTLRStringStream() {
     70 	}
     71 
     72 	/** Copy data in string to a local char array */
     73 	public ANTLRStringStream(String input) {
     74 		this();
     75 		this.data = input.toCharArray();
     76 		this.n = input.length();
     77 	}
     78 
     79 	/** This is the preferred constructor as no data is copied */
     80 	public ANTLRStringStream(char[] data, int numberOfActualCharsInArray) {
     81 		this();
     82 		this.data = data;
     83 		this.n = numberOfActualCharsInArray;
     84 	}
     85 
     86 	/** Reset the stream so that it's in the same state it was
     87 	 *  when the object was created *except* the data array is not
     88 	 *  touched.
     89 	 */
     90 	public void reset() {
     91 		p = 0;
     92 		line = 1;
     93 		charPositionInLine = 0;
     94 		markDepth = 0;
     95 	}
     96 
     97     public void consume() {
     98 		//System.out.println("prev p="+p+", c="+(char)data[p]);
     99         if ( p < n ) {
    100 			charPositionInLine++;
    101 			if ( data[p]=='\n' ) {
    102 				/*
    103 				System.out.println("newline char found on line: "+line+
    104 								   "@ pos="+charPositionInLine);
    105 				*/
    106 				line++;
    107 				charPositionInLine=0;
    108 			}
    109             p++;
    110 			//System.out.println("p moves to "+p+" (c='"+(char)data[p]+"')");
    111         }
    112     }
    113 
    114     public int LA(int i) {
    115 		if ( i==0 ) {
    116 			return 0; // undefined
    117 		}
    118 		if ( i<0 ) {
    119 			i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1]
    120 			if ( (p+i-1) < 0 ) {
    121 				return CharStream.EOF; // invalid; no char before first char
    122 			}
    123 		}
    124 
    125 		if ( (p+i-1) >= n ) {
    126             //System.out.println("char LA("+i+")=EOF; p="+p);
    127             return CharStream.EOF;
    128         }
    129         //System.out.println("char LA("+i+")="+(char)data[p+i-1]+"; p="+p);
    130 		//System.out.println("LA("+i+"); p="+p+" n="+n+" data.length="+data.length);
    131 		return data[p+i-1];
    132     }
    133 
    134 	public int LT(int i) {
    135 		return LA(i);
    136 	}
    137 
    138 	/** Return the current input symbol index 0..n where n indicates the
    139      *  last symbol has been read.  The index is the index of char to
    140 	 *  be returned from LA(1).
    141      */
    142     public int index() {
    143         return p;
    144     }
    145 
    146 	public int size() {
    147 		return n;
    148 	}
    149 
    150 	public int mark() {
    151         if ( markers==null ) {
    152             markers = new ArrayList();
    153             markers.add(null); // depth 0 means no backtracking, leave blank
    154         }
    155         markDepth++;
    156 		CharStreamState state = null;
    157 		if ( markDepth>=markers.size() ) {
    158 			state = new CharStreamState();
    159 			markers.add(state);
    160 		}
    161 		else {
    162 			state = (CharStreamState)markers.get(markDepth);
    163 		}
    164 		state.p = p;
    165 		state.line = line;
    166 		state.charPositionInLine = charPositionInLine;
    167 		lastMarker = markDepth;
    168 		return markDepth;
    169     }
    170 
    171     public void rewind(int m) {
    172 		CharStreamState state = (CharStreamState)markers.get(m);
    173 		// restore stream state
    174 		seek(state.p);
    175 		line = state.line;
    176 		charPositionInLine = state.charPositionInLine;
    177 		release(m);
    178 	}
    179 
    180 	public void rewind() {
    181 		rewind(lastMarker);
    182 	}
    183 
    184 	public void release(int marker) {
    185 		// unwind any other markers made after m and release m
    186 		markDepth = marker;
    187 		// release this marker
    188 		markDepth--;
    189 	}
    190 
    191 	/** consume() ahead until p==index; can't just set p=index as we must
    192 	 *  update line and charPositionInLine.
    193 	 */
    194 	public void seek(int index) {
    195 		if ( index<=p ) {
    196 			p = index; // just jump; don't update stream state (line, ...)
    197 			return;
    198 		}
    199 		// seek forward, consume until p hits index
    200 		while ( p<index ) {
    201 			consume();
    202 		}
    203 	}
    204 
    205 	public String substring(int start, int stop) {
    206 		return new String(data,start,stop-start+1);
    207 	}
    208 
    209 	public int getLine() {
    210 		return line;
    211 	}
    212 
    213 	public int getCharPositionInLine() {
    214 		return charPositionInLine;
    215 	}
    216 
    217 	public void setLine(int line) {
    218 		this.line = line;
    219 	}
    220 
    221 	public void setCharPositionInLine(int pos) {
    222 		this.charPositionInLine = pos;
    223 	}
    224 
    225 	public String getSourceName() {
    226 		return name;
    227 	}
    228 
    229     public String toString() { return new String(data); }
    230 }
    231