001: /*
002: [The "BSD licence"]
003: Copyright (c) 2005-2006 Terence Parr
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009: 1. Redistributions of source code must retain the above copyright
010: notice, this list of conditions and the following disclaimer.
011: 2. Redistributions in binary form must reproduce the above copyright
012: notice, this list of conditions and the following disclaimer in the
013: documentation and/or other materials provided with the distribution.
014: 3. The name of the author may not be used to endorse or promote products
015: derived from this software without specific prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
018: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
019: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
020: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
021: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028: package org.antlr.runtime;
029:
030: import java.util.ArrayList;
031: import java.util.List;
032:
033: /** A pretty quick CharStream that pulls all data from an array
034: * directly. Every method call counts in the lexer. Java's
035: * strings aren't very good so I'm avoiding.
036: */
037: public class ANTLRStringStream implements CharStream {
038: /** The data being scanned */
039: protected char[] data;
040:
041: /** How many characters are actually in the buffer */
042: protected int n;
043:
044: /** 0..n-1 index into string of next char */
045: protected int p = 0;
046:
047: /** line number 1..n within the input */
048: protected int line = 1;
049:
050: /** The index of the character relative to the beginning of the line 0..n-1 */
051: protected int charPositionInLine = 0;
052:
053: /** tracks how deep mark() calls are nested */
054: protected int markDepth = 0;
055:
056: /** A list of CharStreamState objects that tracks the stream state
057: * values line, charPositionInLine, and p that can change as you
058: * move through the input stream. Indexed from 1..markDepth.
059: * A null is kept @ index 0. Create upon first call to mark().
060: */
061: protected List markers;
062:
063: /** Track the last mark() call result value for use in rewind(). */
064: protected int lastMarker;
065:
066: public ANTLRStringStream() {
067: }
068:
069: /** Copy data in string to a local char array */
070: public ANTLRStringStream(String input) {
071: this ();
072: this .data = input.toCharArray();
073: this .n = input.length();
074: }
075:
076: /** This is the preferred constructor as no data is copied */
077: public ANTLRStringStream(char[] data, int numberOfActualCharsInArray) {
078: this ();
079: this .data = data;
080: this .n = numberOfActualCharsInArray;
081: }
082:
083: /** Reset the stream so that it's in the same state it was
084: * when the object was created *except* the data array is not
085: * touched.
086: */
087: public void reset() {
088: p = 0;
089: line = 1;
090: charPositionInLine = 0;
091: markDepth = 0;
092: }
093:
094: public void consume() {
095: //System.out.println("prev p="+p+", c="+(char)data[p]);
096: if (p < n) {
097: charPositionInLine++;
098: if (data[p] == '\n') {
099: /*
100: System.out.println("newline char found on line: "+line+
101: "@ pos="+charPositionInLine);
102: */
103: line++;
104: charPositionInLine = 0;
105: }
106: p++;
107: //System.out.println("p moves to "+p+" (c='"+(char)data[p]+"')");
108: }
109: }
110:
111: public int LA(int i) {
112: if (i == 0) {
113: return 0; // undefined
114: }
115: if (i < 0) {
116: i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1]
117: if ((p + i - 1) < 0) {
118: return CharStream.EOF; // invalid; no char before first char
119: }
120: }
121:
122: if ((p + i - 1) >= n) {
123: //System.out.println("char LA("+i+")=EOF; p="+p);
124: return CharStream.EOF;
125: }
126: //System.out.println("char LA("+i+")="+(char)data[p+i-1]+"; p="+p);
127: //System.out.println("LA("+i+"); p="+p+" n="+n+" data.length="+data.length);
128: return data[p + i - 1];
129: }
130:
131: public int LT(int i) {
132: return LA(i);
133: }
134:
135: /** Return the current input symbol index 0..n where n indicates the
136: * last symbol has been read. The index is the index of char to
137: * be returned from LA(1).
138: */
139: public int index() {
140: return p;
141: }
142:
143: public int size() {
144: return n;
145: }
146:
147: public int mark() {
148: if (markers == null) {
149: markers = new ArrayList();
150: markers.add(null); // depth 0 means no backtracking, leave blank
151: }
152: markDepth++;
153: CharStreamState state = null;
154: if (markDepth >= markers.size()) {
155: state = new CharStreamState();
156: markers.add(state);
157: } else {
158: state = (CharStreamState) markers.get(markDepth);
159: }
160: state.p = p;
161: state.line = line;
162: state.charPositionInLine = charPositionInLine;
163: lastMarker = markDepth;
164: return markDepth;
165: }
166:
167: public void rewind(int m) {
168: CharStreamState state = (CharStreamState) markers.get(m);
169: // restore stream state
170: seek(state.p);
171: line = state.line;
172: charPositionInLine = state.charPositionInLine;
173: release(m);
174: }
175:
176: public void rewind() {
177: rewind(lastMarker);
178: }
179:
180: public void release(int marker) {
181: // unwind any other markers made after m and release m
182: markDepth = marker;
183: // release this marker
184: markDepth--;
185: }
186:
187: /** consume() ahead until p==index; can't just set p=index as we must
188: * update line and charPositionInLine.
189: */
190: public void seek(int index) {
191: if (index <= p) {
192: p = index; // just jump; don't update stream state (line, ...)
193: return;
194: }
195: // seek forward, consume until p hits index
196: while (p < index) {
197: consume();
198: }
199: }
200:
201: public String substring(int start, int stop) {
202: return new String(data, start, stop - start + 1);
203: }
204:
205: public int getLine() {
206: return line;
207: }
208:
209: public int getCharPositionInLine() {
210: return charPositionInLine;
211: }
212:
213: public void setLine(int line) {
214: this .line = line;
215: }
216:
217: public void setCharPositionInLine(int pos) {
218: this.charPositionInLine = pos;
219: }
220: }
|