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 namespace Antlr.Runtime.Misc { 34 using IndexOutOfRangeException = System.IndexOutOfRangeException; 35 36 /** <summary> 37 * A lookahead queue that knows how to mark/release locations 38 * in the buffer for backtracking purposes. Any markers force the FastQueue 39 * superclass to keep all tokens until no more markers; then can reset 40 * to avoid growing a huge buffer. 41 * </summary> 42 */ 43 public abstract class LookaheadStream<T> 44 : FastQueue<T> 45 where T : class { 46 /** Absolute token index. It's the index of the symbol about to be 47 * read via LT(1). Goes from 0 to numtokens. 48 */ 49 private int _currentElementIndex = 0; 50 51 private T _previousElement; 52 53 /** Track object returned by nextElement upon end of stream; 54 * Return it later when they ask for LT passed end of input. 55 */ 56 T _eof = null; 57 58 /** <summary>Track the last mark() call result value for use in rewind().</summary> */ 59 int _lastMarker; 60 61 /** <summary>tracks how deep mark() calls are nested</summary> */ 62 int _markDepth; 63 64 public T EndOfFile { 65 get { 66 return _eof; 67 } 68 protected set { 69 _eof = value; 70 } 71 } 72 Clear()73 public override void Clear() { 74 base.Clear(); 75 _currentElementIndex = 0; 76 _p = 0; 77 _previousElement = null; 78 } 79 80 /** <summary> 81 * Implement nextElement to supply a stream of elements to this 82 * lookahead buffer. Return eof upon end of the stream we're pulling from. 83 * </summary> 84 */ NextElement()85 public abstract T NextElement(); 86 IsEndOfFile(T o)87 public abstract bool IsEndOfFile(T o); 88 89 /** <summary>Get and remove first element in queue; override FastQueue.remove()</summary> */ Dequeue()90 public override T Dequeue() { 91 T o = this[0]; 92 _p++; 93 // have we hit end of buffer and not backtracking? 94 if (_p == _data.Count && _markDepth == 0) { 95 // if so, it's an opportunity to start filling at index 0 again 96 Clear(); // size goes to 0, but retains memory 97 } 98 return o; 99 } 100 101 /** <summary>Make sure we have at least one element to remove, even if EOF</summary> */ Consume()102 public virtual void Consume() { 103 SyncAhead(1); 104 _previousElement = Dequeue(); 105 _currentElementIndex++; 106 } 107 108 /** <summary> 109 * Make sure we have 'need' elements from current position p. Last valid 110 * p index is data.size()-1. p+need-1 is the data index 'need' elements 111 * ahead. If we need 1 element, (p+1-1)==p must be < data.size(). 112 * </summary> 113 */ SyncAhead(int need)114 protected virtual void SyncAhead(int need) { 115 int n = (_p + need - 1) - _data.Count + 1; // how many more elements we need? 116 if (n > 0) 117 Fill(n); // out of elements? 118 } 119 120 /** <summary>add n elements to buffer</summary> */ Fill(int n)121 public virtual void Fill(int n) { 122 for (int i = 0; i < n; i++) { 123 T o = NextElement(); 124 if (IsEndOfFile(o)) 125 _eof = o; 126 127 _data.Add(o); 128 } 129 } 130 131 /** <summary>Size of entire stream is unknown; we only know buffer size from FastQueue</summary> */ 132 public override int Count { 133 get { 134 throw new System.NotSupportedException("streams are of unknown size"); 135 } 136 } 137 LT(int k)138 public virtual T LT(int k) { 139 if (k == 0) { 140 return null; 141 } 142 if (k < 0) { 143 return LB(-k); 144 } 145 146 SyncAhead(k); 147 if ((_p + k - 1) > _data.Count) 148 return _eof; 149 150 return this[k - 1]; 151 } 152 153 public virtual int Index { 154 get { 155 return _currentElementIndex; 156 } 157 } 158 Mark()159 public virtual int Mark() { 160 _markDepth++; 161 _lastMarker = _p; // track where we are in buffer, not absolute token index 162 return _lastMarker; 163 } 164 Release(int marker)165 public virtual void Release(int marker) { 166 _markDepth--; 167 } 168 Rewind(int marker)169 public virtual void Rewind(int marker) { 170 Seek(marker); 171 Release(marker); 172 } 173 Rewind()174 public virtual void Rewind() { 175 Seek(_lastMarker); 176 } 177 178 /** <summary> 179 * Seek to a 0-indexed position within data buffer. Can't handle 180 * case where you seek beyond end of existing buffer. Normally used 181 * to seek backwards in the buffer. Does not force loading of nodes. 182 * Doesn't see to absolute position in input stream since this stream 183 * is unbuffered. Seeks only into our moving window of elements. 184 * </summary> 185 */ Seek(int index)186 public virtual void Seek(int index) { 187 _p = index; 188 } 189 LB(int k)190 protected virtual T LB(int k) { 191 if (k == 1) 192 return _previousElement; 193 194 throw new IndexOutOfRangeException("can't look backwards more than one token in this stream"); 195 } 196 } 197 } 198