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: /**A Stream of Token objects fed to the parser from a Tokenizer that can
010: * be rewound via mark()/rewind() methods.
011: * <p>
012: * A dynamic array is used to buffer up all the input tokens. Normally,
013: * "k" tokens are stored in the buffer. More tokens may be stored during
014: * guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
015: * Consumption of tokens is deferred. In other words, reading the next
016: * token is not done by conume(), but deferred until needed by LA or LT.
017: * <p>
018: *
019: * @see persistence.antlr.Token
020: * @see persistence.antlr.Tokenizer
021: * @see persistence.antlr.TokenQueue
022: */
023:
024: import java.io.IOException;
025:
026: public class TokenBuffer {
027:
028: // Token source
029: protected TokenStream input;
030:
031: // Number of active markers
032: int nMarkers = 0;
033:
034: // Additional offset used when markers are active
035: int markerOffset = 0;
036:
037: // Number of calls to consume() since last LA() or LT() call
038: int numToConsume = 0;
039:
040: // Circular queue
041: TokenQueue queue;
042:
043: /** Create a token buffer */
044: public TokenBuffer(TokenStream input_) {
045: input = input_;
046: queue = new TokenQueue(1);
047: }
048:
049: /** Reset the input buffer to empty state */
050: public final void reset() {
051: nMarkers = 0;
052: markerOffset = 0;
053: numToConsume = 0;
054: queue.reset();
055: }
056:
057: /** Mark another token for deferred consumption */
058: public final void consume() {
059: numToConsume++;
060: }
061:
062: /** Ensure that the token buffer is sufficiently full */
063: private final void fill(int amount) throws TokenStreamException {
064: syncConsume();
065: // Fill the buffer sufficiently to hold needed tokens
066: while (queue.nbrEntries < amount + markerOffset) {
067: // Append the next token
068: queue.append(input.nextToken());
069: }
070: }
071:
072: /** return the Tokenizer (needed by ParseView) */
073: public TokenStream getInput() {
074: return input;
075: }
076:
077: /** Get a lookahead token value */
078: public final int LA(int i) throws TokenStreamException {
079: fill(i);
080: return queue.elementAt(markerOffset + i - 1).type;
081: }
082:
083: /** Get a lookahead token */
084: public final Token LT(int i) throws TokenStreamException {
085: fill(i);
086: return queue.elementAt(markerOffset + i - 1);
087: }
088:
089: /**Return an integer marker that can be used to rewind the buffer to
090: * its current state.
091: */
092: public final int mark() {
093: syncConsume();
094: //System.out.println("Marking at " + markerOffset);
095: //try { for (int i = 1; i <= 2; i++) { System.out.println("LA("+i+")=="+LT(i).getText()); } } catch (ScannerException e) {}
096: nMarkers++;
097: return markerOffset;
098: }
099:
100: /**Rewind the token buffer to a marker.
101: * @param mark Marker returned previously from mark()
102: */
103: public final void rewind(int mark) {
104: syncConsume();
105: markerOffset = mark;
106: nMarkers--;
107: //System.out.println("Rewinding to " + mark);
108: //try { for (int i = 1; i <= 2; i++) { System.out.println("LA("+i+")=="+LT(i).getText()); } } catch (ScannerException e) {}
109: }
110:
111: /** Sync up deferred consumption */
112: private final void syncConsume() {
113: while (numToConsume > 0) {
114: if (nMarkers > 0) {
115: // guess mode -- leave leading tokens and bump offset.
116: markerOffset++;
117: } else {
118: // normal mode -- remove first token
119: queue.removeFirst();
120: }
121: numToConsume--;
122: }
123: }
124: }
|