1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2005-2008 Terence Parr 4 * All rights reserved. 5 * 6 * Conversion to C#: 7 * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33namespace Antlr.Runtime { 34 using System.Collections.Generic; 35 using ArgumentException = System.ArgumentException; 36 using ArgumentOutOfRangeException = System.ArgumentOutOfRangeException; 37 using ArgumentNullException = System.ArgumentNullException; 38 39 /** <summary> 40 * A pretty quick CharStream that pulls all data from an array 41 * directly. Every method call counts in the lexer. Java's 42 * strings aren't very good so I'm avoiding. 43 * </summary> 44 */ 45 [System.Serializable] 46 public class ANTLRStringStream : ICharStream { 47 /** <summary>The data being scanned</summary> */ 48 protected char[] data; 49 50 /** <summary>How many characters are actually in the buffer</summary> */ 51 protected int n; 52 53 /** <summary>0..n-1 index into string of next char</summary> */ 54 protected int p = 0; 55 56 /** <summary>line number 1..n within the input</summary> */ 57 int line = 1; 58 59 /** <summary>The index of the character relative to the beginning of the line 0..n-1</summary> */ 60 int charPositionInLine = 0; 61 62 /** <summary>tracks how deep mark() calls are nested</summary> */ 63 protected int markDepth = 0; 64 65 /** <summary> 66 * A list of CharStreamState objects that tracks the stream state 67 * values line, charPositionInLine, and p that can change as you 68 * move through the input stream. Indexed from 1..markDepth. 69 * A null is kept @ index 0. Create upon first call to mark(). 70 * </summary> 71 */ 72 protected IList<CharStreamState> markers; 73 74 /** <summary>Track the last mark() call result value for use in rewind().</summary> */ 75 protected int lastMarker; 76 77 /** <summary>What is name or source of this char stream?</summary> */ 78 public string name; 79 80 /** <summary>Copy data in string to a local char array</summary> */ 81 public ANTLRStringStream(string input) 82 : this(input, null) { 83 } 84 85 public ANTLRStringStream(string input, string sourceName) 86 : this(input.ToCharArray(), input.Length, sourceName) { 87 } 88 89 /** <summary>This is the preferred constructor as no data is copied</summary> */ 90 public ANTLRStringStream(char[] data, int numberOfActualCharsInArray) 91 : this(data, numberOfActualCharsInArray, null) { 92 } 93 94 public ANTLRStringStream(char[] data, int numberOfActualCharsInArray, string sourceName) { 95 if (data == null) 96 throw new ArgumentNullException("data"); 97 if (numberOfActualCharsInArray < 0) 98 throw new ArgumentOutOfRangeException(); 99 if (numberOfActualCharsInArray > data.Length) 100 throw new ArgumentException(); 101 102 this.data = data; 103 this.n = numberOfActualCharsInArray; 104 this.name = sourceName; 105 } 106 107 protected ANTLRStringStream() { 108 this.data = new char[0]; 109 } 110 111 /** <summary> 112 * Return the current input symbol index 0..n where n indicates the 113 * last symbol has been read. The index is the index of char to 114 * be returned from LA(1). 115 * </summary> 116 */ 117 public virtual int Index { 118 get { 119 return p; 120 } 121 } 122 public virtual int Line { 123 get { 124 return line; 125 } 126 set { 127 line = value; 128 } 129 } 130 public virtual int CharPositionInLine { 131 get { 132 return charPositionInLine; 133 } 134 set { 135 charPositionInLine = value; 136 } 137 } 138 139 /** <summary> 140 * Reset the stream so that it's in the same state it was 141 * when the object was created *except* the data array is not 142 * touched. 143 * </summary> 144 */ 145 public virtual void Reset() { 146 p = 0; 147 line = 1; 148 charPositionInLine = 0; 149 markDepth = 0; 150 } 151 152 public virtual void Consume() { 153 //System.out.println("prev p="+p+", c="+(char)data[p]); 154 if (p < n) { 155 charPositionInLine++; 156 if (data[p] == '\n') { 157 /* 158 System.out.println("newline char found on line: "+line+ 159 "@ pos="+charPositionInLine); 160 */ 161 line++; 162 charPositionInLine = 0; 163 } 164 p++; 165 //System.out.println("p moves to "+p+" (c='"+(char)data[p]+"')"); 166 } 167 } 168 169 public virtual int LA(int i) { 170 if (i == 0) { 171 return 0; // undefined 172 } 173 if (i < 0) { 174 i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1] 175 if ((p + i - 1) < 0) { 176 return CharStreamConstants.EndOfFile; // invalid; no char before first char 177 } 178 } 179 180 if ((p + i - 1) >= n) { 181 //System.out.println("char LA("+i+")=EOF; p="+p); 182 return CharStreamConstants.EndOfFile; 183 } 184 //System.out.println("char LA("+i+")="+(char)data[p+i-1]+"; p="+p); 185 //System.out.println("LA("+i+"); p="+p+" n="+n+" data.length="+data.length); 186 return data[p + i - 1]; 187 } 188 189 public virtual int LT(int i) { 190 return LA(i); 191 } 192 193 public virtual int Count { 194 get { 195 return n; 196 } 197 } 198 199 public virtual int Mark() { 200 if (markers == null) { 201 markers = new List<CharStreamState>(); 202 markers.Add(null); // depth 0 means no backtracking, leave blank 203 } 204 markDepth++; 205 CharStreamState state = null; 206 if (markDepth >= markers.Count) { 207 state = new CharStreamState(); 208 markers.Add(state); 209 } else { 210 state = markers[markDepth]; 211 } 212 state.p = p; 213 state.line = line; 214 state.charPositionInLine = charPositionInLine; 215 lastMarker = markDepth; 216 return markDepth; 217 } 218 219 public virtual void Rewind(int m) { 220 if (m < 0) 221 throw new ArgumentOutOfRangeException(); 222 223 //if (m > markDepth) 224 // throw new ArgumentException(); 225 226 CharStreamState state = markers[m]; 227 // restore stream state 228 Seek(state.p); 229 line = state.line; 230 charPositionInLine = state.charPositionInLine; 231 Release(m); 232 } 233 234 public virtual void Rewind() { 235 Rewind(lastMarker); 236 } 237 238 public virtual void Release(int marker) { 239 // unwind any other markers made after m and release m 240 markDepth = marker; 241 // release this marker 242 markDepth--; 243 } 244 245 /** <summary> 246 * consume() ahead until p==index; can't just set p=index as we must 247 * update line and charPositionInLine. 248 * </summary> 249 */ 250 public virtual void Seek(int index) { 251 if (index <= p) { 252 p = index; // just jump; don't update stream state (line, ...) 253 return; 254 } 255 // seek forward, consume until p hits index 256 while (p < index) { 257 Consume(); 258 } 259 } 260 261 public virtual string Substring(int start, int length) { 262 if (start < 0) 263 throw new ArgumentOutOfRangeException(); 264 if (length < 0) 265 throw new ArgumentOutOfRangeException(); 266 if (start + length > data.Length) 267 throw new ArgumentException(); 268 269 if (length == 0) 270 return string.Empty; 271 272 return new string(data, start, length); 273 } 274 275 public virtual string SourceName { 276 get { 277 return name; 278 } 279 } 280 281 public override string ToString() { 282 return new string(data); 283 } 284 } 285} 286