forked from jasder/antlr
318 lines
10 KiB
C#
318 lines
10 KiB
C#
/*
|
|
* [The "BSD license"]
|
|
* Copyright (c) 2013 Terence Parr
|
|
* Copyright (c) 2013 Sam Harwell
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
using System;
|
|
using System.IO;
|
|
using Antlr4.Runtime;
|
|
using Antlr4.Runtime.Misc;
|
|
using Sharpen;
|
|
|
|
namespace Antlr4.Runtime
|
|
{
|
|
/// <summary>Vacuum all input from a Reader/InputStream and then treat it like a char[] buffer.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Vacuum all input from a Reader/InputStream and then treat it like a char[] buffer.
|
|
/// Can also pass in a string or char[] to use.
|
|
/// If you need encoding, pass in stream/reader with correct encoding.
|
|
/// </remarks>
|
|
public class AntlrInputStream : ICharStream
|
|
{
|
|
public const int ReadBufferSize = 1024;
|
|
|
|
public const int InitialBufferSize = 1024;
|
|
|
|
/// <summary>The data being scanned</summary>
|
|
protected internal char[] data;
|
|
|
|
/// <summary>How many characters are actually in the buffer</summary>
|
|
protected internal int n;
|
|
|
|
/// <summary>0..n-1 index into string of next char</summary>
|
|
protected internal int p = 0;
|
|
|
|
/// <summary>What is name or source of this char stream?</summary>
|
|
public string name;
|
|
|
|
public AntlrInputStream()
|
|
{
|
|
}
|
|
|
|
/// <summary>Copy data in string to a local char array</summary>
|
|
public AntlrInputStream(string input)
|
|
{
|
|
this.data = input.ToCharArray();
|
|
this.n = input.Length;
|
|
}
|
|
|
|
/// <summary>This is the preferred constructor for strings as no data is copied</summary>
|
|
public AntlrInputStream(char[] data, int numberOfActualCharsInArray)
|
|
{
|
|
this.data = data;
|
|
this.n = numberOfActualCharsInArray;
|
|
}
|
|
|
|
/// <exception cref="System.IO.IOException"></exception>
|
|
public AntlrInputStream(StreamReader r) : this(r, InitialBufferSize, ReadBufferSize
|
|
)
|
|
{
|
|
}
|
|
|
|
/// <exception cref="System.IO.IOException"></exception>
|
|
public AntlrInputStream(StreamReader r, int initialSize) : this(r, initialSize, ReadBufferSize
|
|
)
|
|
{
|
|
}
|
|
|
|
/// <exception cref="System.IO.IOException"></exception>
|
|
public AntlrInputStream(StreamReader r, int initialSize, int readChunkSize)
|
|
{
|
|
Load(r, initialSize, readChunkSize);
|
|
}
|
|
|
|
/// <exception cref="System.IO.IOException"></exception>
|
|
public AntlrInputStream(Stream input) : this(new StreamReader(input), InitialBufferSize
|
|
)
|
|
{
|
|
}
|
|
|
|
/// <exception cref="System.IO.IOException"></exception>
|
|
public AntlrInputStream(Stream input, int initialSize) : this(new StreamReader(input
|
|
), initialSize)
|
|
{
|
|
}
|
|
|
|
/// <exception cref="System.IO.IOException"></exception>
|
|
public AntlrInputStream(Stream input, int initialSize, int readChunkSize) : this(
|
|
new StreamReader(input), initialSize, readChunkSize)
|
|
{
|
|
}
|
|
|
|
/// <exception cref="System.IO.IOException"></exception>
|
|
public virtual void Load(StreamReader r, int size, int readChunkSize)
|
|
{
|
|
if (r == null)
|
|
{
|
|
return;
|
|
}
|
|
if (size <= 0)
|
|
{
|
|
size = InitialBufferSize;
|
|
}
|
|
if (readChunkSize <= 0)
|
|
{
|
|
readChunkSize = ReadBufferSize;
|
|
}
|
|
// System.out.println("load "+size+" in chunks of "+readChunkSize);
|
|
try
|
|
{
|
|
// alloc initial buffer size.
|
|
data = new char[size];
|
|
// read all the data in chunks of readChunkSize
|
|
int numRead = 0;
|
|
int p = 0;
|
|
do
|
|
{
|
|
if (p + readChunkSize > data.Length)
|
|
{
|
|
// overflow?
|
|
// System.out.println("### overflow p="+p+", data.length="+data.length);
|
|
data = Arrays.CopyOf(data, data.Length * 2);
|
|
}
|
|
numRead = r.Read(data, p, readChunkSize);
|
|
// System.out.println("read "+numRead+" chars; p was "+p+" is now "+(p+numRead));
|
|
p += numRead;
|
|
}
|
|
while (numRead != -1);
|
|
// while not EOF
|
|
// set the actual size of the data available;
|
|
// EOF subtracted one above in p+=numRead; add one back
|
|
n = p + 1;
|
|
}
|
|
finally
|
|
{
|
|
//System.out.println("n="+n);
|
|
r.Close();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reset the stream so that it's in the same state it was
|
|
/// when the object was created *except* the data array is not
|
|
/// touched.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Reset the stream so that it's in the same state it was
|
|
/// when the object was created *except* the data array is not
|
|
/// touched.
|
|
/// </remarks>
|
|
public virtual void Reset()
|
|
{
|
|
p = 0;
|
|
}
|
|
|
|
public virtual void Consume()
|
|
{
|
|
if (p >= n)
|
|
{
|
|
System.Diagnostics.Debug.Assert(La(1) == IntStreamConstants.Eof);
|
|
throw new InvalidOperationException("cannot consume EOF");
|
|
}
|
|
//System.out.println("prev p="+p+", c="+(char)data[p]);
|
|
if (p < n)
|
|
{
|
|
p++;
|
|
}
|
|
}
|
|
|
|
//System.out.println("p moves to "+p+" (c='"+(char)data[p]+"')");
|
|
public virtual int La(int i)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
// undefined
|
|
if (i < 0)
|
|
{
|
|
i++;
|
|
// e.g., translate LA(-1) to use offset i=0; then data[p+0-1]
|
|
if ((p + i - 1) < 0)
|
|
{
|
|
return IntStreamConstants.Eof;
|
|
}
|
|
}
|
|
// invalid; no char before first char
|
|
if ((p + i - 1) >= n)
|
|
{
|
|
//System.out.println("char LA("+i+")=EOF; p="+p);
|
|
return IntStreamConstants.Eof;
|
|
}
|
|
//System.out.println("char LA("+i+")="+(char)data[p+i-1]+"; p="+p);
|
|
//System.out.println("LA("+i+"); p="+p+" n="+n+" data.length="+data.length);
|
|
return data[p + i - 1];
|
|
}
|
|
|
|
public virtual int Lt(int i)
|
|
{
|
|
return La(i);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return the current input symbol index 0..n where n indicates the
|
|
/// last symbol has been read.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Return the current input symbol index 0..n where n indicates the
|
|
/// last symbol has been read. The index is the index of char to
|
|
/// be returned from LA(1).
|
|
/// </remarks>
|
|
public virtual int Index
|
|
{
|
|
get
|
|
{
|
|
return p;
|
|
}
|
|
}
|
|
|
|
public virtual int Size
|
|
{
|
|
get
|
|
{
|
|
return n;
|
|
}
|
|
}
|
|
|
|
/// <summary>mark/release do nothing; we have entire buffer</summary>
|
|
public virtual int Mark()
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
public virtual void Release(int marker)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// consume() ahead until p==index; can't just set p=index as we must
|
|
/// update line and charPositionInLine.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// consume() ahead until p==index; can't just set p=index as we must
|
|
/// update line and charPositionInLine. If we seek backwards, just set p
|
|
/// </remarks>
|
|
public virtual void Seek(int index)
|
|
{
|
|
if (index <= p)
|
|
{
|
|
p = index;
|
|
// just jump; don't update stream state (line, ...)
|
|
return;
|
|
}
|
|
// seek forward, consume until p hits index
|
|
while (p < index && index < n)
|
|
{
|
|
Consume();
|
|
}
|
|
}
|
|
|
|
public virtual string GetText(Interval interval)
|
|
{
|
|
int start = interval.a;
|
|
int stop = interval.b;
|
|
if (stop >= n)
|
|
{
|
|
stop = n - 1;
|
|
}
|
|
int count = stop - start + 1;
|
|
if (start >= n)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
// System.err.println("data: "+Arrays.toString(data)+", n="+n+
|
|
// ", start="+start+
|
|
// ", stop="+stop);
|
|
return new string(data, start, count);
|
|
}
|
|
|
|
public virtual string SourceName
|
|
{
|
|
get
|
|
{
|
|
return name;
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return new string(data);
|
|
}
|
|
}
|
|
}
|