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 */ 28package org.antlr.runtime; 29 30import java.util.ArrayList; 31import 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 */ 37public 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