1   // Copyright 2012- Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import java.io.FileNotFoundException;
6   import java.util.Stack;
7   import java.util.Vector;
8   
9   /**
10   * A lexical analyzer for j-- that interfaces with the hand-written parser (Parser). It
11   * provides a backtracking mechanism, and makes use of the underlying hand-written scanner
12   * (Scanner).
13   */
14  class LookaheadScanner {
15      // The underlying hand-written scanner.
16      private Scanner scanner;
17  
18      // Backtracking queue.
19      private Vector<TokenInfo> backtrackingQueue;
20  
21      // Token queue.
22      private Vector<TokenInfo> nextQueue;
23  
24      // Stack of token queues for nested lookahead.
25      private Stack<Vector<TokenInfo>> queueStack;
26  
27      // Whether we are looking ahead.
28      public boolean isLookingAhead;
29  
30      // Previous token.
31      private TokenInfo previousToken;
32  
33      // Current token.
34      private TokenInfo token;
35  
36      /**
37       * Constructs a LookaheadScanner.
38       *
39       * @param fileName the name of the file containing the source.
40       * @throws FileNotFoundException when the named file cannot be found.
41       */
42      public LookaheadScanner(String fileName) throws FileNotFoundException {
43          scanner = new Scanner(fileName);
44          backtrackingQueue = new Vector<TokenInfo>();
45          nextQueue = new Vector<TokenInfo>();
46          queueStack = new Stack<Vector<TokenInfo>>();
47          isLookingAhead = false;
48      }
49  
50      /**
51       * Scans to the next token in the input.
52       */
53      public void next() {
54          previousToken = token;
55          if (backtrackingQueue.size() == 0) {
56              token = scanner.getNextToken();
57          } else {
58              token = backtrackingQueue.remove(0);
59          }
60          if (isLookingAhead) {
61              nextQueue.add(token);
62          }
63      }
64  
65      /**
66       * Records the current position in the input, so that we can start looking ahead in the input
67       * (and later return to this position) --- the current and subsequent tokens are queued until
68       * returnToPosition() is invoked.
69       */
70      public void recordPosition() {
71          isLookingAhead = true;
72          queueStack.push(nextQueue);
73          nextQueue = new Vector<TokenInfo>();
74          nextQueue.add(previousToken);
75          nextQueue.add(token);
76      }
77  
78      /**
79       * Returns to the previously recorded position in the input stream of tokens.
80       */
81      public void returnToPosition() {
82          while (backtrackingQueue.size() > 0) {
83              nextQueue.add(backtrackingQueue.remove(0));
84          }
85          backtrackingQueue = nextQueue;
86          nextQueue = queueStack.pop();
87          isLookingAhead = !(queueStack.empty());
88  
89          // Restore previous and current tokens
90          previousToken = backtrackingQueue.remove(0);
91          token = backtrackingQueue.remove(0);
92      }
93  
94      /**
95       * Returns the current token.
96       *
97       * @return the current token.
98       */
99      public TokenInfo token() {
100         return token;
101     }
102 
103     /**
104      * Returns the previous token.
105      *
106      * @return the previous token.
107      */
108     public TokenInfo previousToken() {
109         return previousToken;
110     }
111 
112     /**
113      * Returns true if an error has occurred, and false otherwise.
114      *
115      * @return true if an error has occurred, and false otherwise.
116      */
117     public boolean errorHasOccured() {
118         return scanner.errorHasOccurred();
119     }
120 
121     /**
122      * Returns the name of the source file.
123      *
124      * @return the name of the source file.
125      */
126     public String fileName() {
127         return scanner.fileName();
128     }
129 }
130