001: package persistence.antlr;
002:
003: /* ANTLR Translator Generator
004: * Project led by Terence Parr at http://www.jGuru.com
005: * Software rights: http://www.antlr.org/license.html
006: *
007: */
008:
009: // SAS: Added this class to genericise the input buffers for scanners
010: // This allows a scanner to use a binary (FileInputStream) or
011: // text (FileReader) stream of data; the generated scanner
012: // subclass will define the input stream
013: // There are two subclasses to this: CharBuffer and ByteBuffer
014: import java.io.IOException;
015:
016: /**A Stream of characters fed to the lexer from a InputStream that can
017: * be rewound via mark()/rewind() methods.
018: * <p>
019: * A dynamic array is used to buffer up all the input characters. Normally,
020: * "k" characters are stored in the buffer. More characters may be stored during
021: * guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
022: * Consumption of characters is deferred. In other words, reading the next
023: * character is not done by conume(), but deferred until needed by LA or LT.
024: * <p>
025: *
026: * @see persistence.antlr.CharQueue
027: */
028: public abstract class InputBuffer {
029: // Number of active markers
030: protected int nMarkers = 0;
031:
032: // Additional offset used when markers are active
033: protected int markerOffset = 0;
034:
035: // Number of calls to consume() since last LA() or LT() call
036: protected int numToConsume = 0;
037:
038: // Circular queue
039: protected CharQueue queue;
040:
041: /** Create an input buffer */
042: public InputBuffer() {
043: queue = new CharQueue(1);
044: }
045:
046: /** This method updates the state of the input buffer so that
047: * the text matched since the most recent mark() is no longer
048: * held by the buffer. So, you either do a mark/rewind for
049: * failed predicate or mark/commit to keep on parsing without
050: * rewinding the input.
051: */
052: public void commit() {
053: nMarkers--;
054: }
055:
056: /** Mark another character for deferred consumption */
057: public void consume() {
058: numToConsume++;
059: }
060:
061: /** Ensure that the input buffer is sufficiently full */
062: public abstract void fill(int amount) throws CharStreamException;
063:
064: public String getLAChars() {
065: StringBuffer la = new StringBuffer();
066: for (int i = markerOffset; i < queue.nbrEntries; i++)
067: la.append(queue.elementAt(i));
068: return la.toString();
069: }
070:
071: public String getMarkedChars() {
072: StringBuffer marked = new StringBuffer();
073: for (int i = 0; i < markerOffset; i++)
074: marked.append(queue.elementAt(i));
075: return marked.toString();
076: }
077:
078: public boolean isMarked() {
079: return (nMarkers != 0);
080: }
081:
082: /** Get a lookahead character */
083: public char LA(int i) throws CharStreamException {
084: fill(i);
085: return queue.elementAt(markerOffset + i - 1);
086: }
087:
088: /**Return an integer marker that can be used to rewind the buffer to
089: * its current state.
090: */
091: public int mark() {
092: syncConsume();
093: nMarkers++;
094: return markerOffset;
095: }
096:
097: /**Rewind the character buffer to a marker.
098: * @param mark Marker returned previously from mark()
099: */
100: public void rewind(int mark) {
101: syncConsume();
102: markerOffset = mark;
103: nMarkers--;
104: }
105:
106: /** Reset the input buffer
107: */
108: public void reset() {
109: nMarkers = 0;
110: markerOffset = 0;
111: numToConsume = 0;
112: queue.reset();
113: }
114:
115: /** Sync up deferred consumption */
116: protected void syncConsume() {
117: while (numToConsume > 0) {
118: if (nMarkers > 0) {
119: // guess mode -- leave leading characters and bump offset.
120: markerOffset++;
121: } else {
122: // normal mode -- remove first character
123: queue.removeFirst();
124: }
125: numToConsume--;
126: }
127: }
128: }
|