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 33// #define TRACK_POSITION 34 35namespace Antlr.Runtime 36{ 37 using System.Collections.Generic; 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 SlimStringStream : ICharStream 47 { 48 /** <summary>The data being scanned</summary> */ 49 protected string data; 50 //protected char[] data; 51 52 /** <summary>How many characters are actually in the buffer</summary> */ 53 protected int n; 54 55 /** <summary>0..n-1 index into string of next char</summary> */ 56 protected int p = 0; 57 58#if TRACK_POSITION 59 /** <summary>line number 1..n within the input</summary> */ 60 protected int line = 1; 61 62 /** <summary>The index of the character relative to the beginning of the line 0..n-1</summary> */ 63 protected int charPositionInLine = 0; 64#endif 65 66 /** <summary>tracks how deep mark() calls are nested</summary> */ 67 protected int markDepth = 0; 68 69 /** <summary> 70 * A list of CharStreamState objects that tracks the stream state 71 * values line, charPositionInLine, and p that can change as you 72 * move through the input stream. Indexed from 1..markDepth. 73 * A null is kept @ index 0. Create upon first call to mark(). 74 * </summary> 75 */ 76 protected IList<CharStreamState> markers; 77 78 /** <summary>Track the last mark() call result value for use in rewind().</summary> */ 79 protected int lastMarker; 80 81 /** <summary>What is name or source of this char stream?</summary> */ 82 public string name; 83 84 public SlimStringStream() 85 { 86 } 87 88 /** <summary>Copy data in string to a local char array</summary> */ 89 public SlimStringStream( string input ) 90 : this( input, null ) 91 { 92 } 93 94 public SlimStringStream( string input, string sourceName ) 95 : this( input.ToCharArray(), input.Length, sourceName ) 96 { 97 } 98 99 /** <summary>This is the preferred constructor as no data is copied</summary> */ 100 public SlimStringStream( char[] data, int numberOfActualCharsInArray ) 101 : this( data, numberOfActualCharsInArray, null ) 102 { 103 } 104 105 public SlimStringStream( char[] data, int numberOfActualCharsInArray, string sourceName ) 106 : this() 107 { 108 //this.data = data; 109 this.data = new string( data ); 110 this.n = numberOfActualCharsInArray; 111 this.name = sourceName; 112 } 113 114 /** <summary> 115 * Return the current input symbol index 0..n where n indicates the 116 * last symbol has been read. The index is the index of char to 117 * be returned from LA(1). 118 * </summary> 119 */ 120 public int Index 121 { 122 get 123 { 124 return p; 125 } 126 } 127#if TRACK_POSITION 128 public int Line 129 { 130 get 131 { 132 return line; 133 } 134 set 135 { 136 line = value; 137 } 138 } 139 public int CharPositionInLine 140 { 141 get 142 { 143 return charPositionInLine; 144 } 145 set 146 { 147 charPositionInLine = value; 148 } 149 } 150#else 151 public int Line 152 { 153 get 154 { 155 return -1; 156 } 157 set 158 { 159 } 160 } 161 public int CharPositionInLine 162 { 163 get 164 { 165 return -1; 166 } 167 set 168 { 169 } 170 } 171#endif 172 173 /** <summary> 174 * Reset the stream so that it's in the same state it was 175 * when the object was created *except* the data array is not 176 * touched. 177 * </summary> 178 */ 179 public void Reset() 180 { 181 p = 0; 182#if TRACK_POSITION 183 line = 1; 184 charPositionInLine = 0; 185#endif 186 markDepth = 0; 187 } 188 189 public void Consume() 190 { 191 //System.out.println("prev p="+p+", c="+(char)data[p]); 192 if ( p < n ) 193 { 194#if TRACK_POSITION 195 charPositionInLine++; 196 if ( data[p] == '\n' ) 197 { 198 /* 199 System.out.println("newline char found on line: "+line+ 200 "@ pos="+charPositionInLine); 201 */ 202 line++; 203 charPositionInLine = 0; 204 } 205#endif 206 p++; 207 //System.out.println("p moves to "+p+" (c='"+(char)data[p]+"')"); 208 } 209 } 210 211 public int LA( int i ) 212 { 213 if ( i == 0 ) 214 { 215 return 0; // undefined 216 } 217 if ( i < 0 ) 218 { 219 i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1] 220 if ( ( p + i - 1 ) < 0 ) 221 { 222 return CharStreamConstants.EndOfFile; // invalid; no char before first char 223 } 224 } 225 226 if ( ( p + i - 1 ) >= n ) 227 { 228 //System.out.println("char LA("+i+")=EOF; p="+p); 229 return CharStreamConstants.EndOfFile; 230 } 231 //System.out.println("char LA("+i+")="+(char)data[p+i-1]+"; p="+p); 232 //System.out.println("LA("+i+"); p="+p+" n="+n+" data.length="+data.length); 233 return data[p + i - 1]; 234 } 235 236 public int LT( int i ) 237 { 238 return LA( i ); 239 } 240 241 public int Count 242 { 243 get 244 { 245 return n; 246 } 247 } 248 249 public int Mark() 250 { 251 if ( markers == null ) 252 { 253 markers = new List<CharStreamState>(); 254 markers.Add( null ); // depth 0 means no backtracking, leave blank 255 } 256 markDepth++; 257 CharStreamState state = null; 258 if ( markDepth >= markers.Count ) 259 { 260 state = new CharStreamState(); 261 markers.Add( state ); 262 } 263 else 264 { 265 state = markers[markDepth]; 266 } 267 state.p = p; 268#if TRACK_POSITION 269 state.line = line; 270 state.charPositionInLine = charPositionInLine; 271#endif 272 lastMarker = markDepth; 273 return markDepth; 274 } 275 276 public void Rewind( int m ) 277 { 278 CharStreamState state = markers[m]; 279 // restore stream state 280 Seek( state.p ); 281#if TRACK_POSITION 282 line = state.line; 283 charPositionInLine = state.charPositionInLine; 284#endif 285 Release( m ); 286 } 287 288 public void Rewind() 289 { 290 Rewind( lastMarker ); 291 } 292 293 public void Release( int marker ) 294 { 295 // unwind any other markers made after m and release m 296 markDepth = marker; 297 // release this marker 298 markDepth--; 299 } 300 301 /** <summary> 302 * consume() ahead until p==index; can't just set p=index as we must 303 * update line and charPositionInLine. 304 * </summary> 305 */ 306 public void Seek( int index ) 307 { 308 if ( index <= p ) 309 { 310 p = index; // just jump; don't update stream state (line, ...) 311 return; 312 } 313 // seek forward, consume until p hits index 314 while ( p < index ) 315 { 316 Consume(); 317 } 318 } 319 320 public string Substring( int start, int length ) 321 { 322 return data.Substring( start, length ); 323 //return new string( data, start, stop - start + 1 ); 324 } 325 326 public string SourceName 327 { 328 get 329 { 330 return name; 331 } 332 } 333 } 334} 335