summaryrefslogtreecommitdiff
path: root/Homework/cs5300/project-two/scanner/Scanner.java
blob: 5681932e71ae747354abf50d2df6876ad1f59941 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package scanner;

import java.util.HashMap;
import java.util.Stack;

/**
 * This is the file you will modify.
 */
public class Scanner {

  //------------------------------------------------------------
  // TODO: declare the HashMaps that you will use to store
  // your tables. Also declare the start state.
  //------------------------------------------------------------

  // Category table
  final HashMap<Character, String> char2category = new HashMap<>();
  // Transition table
  final HashMap<String, HashMap<String, String>> state2category2state = new HashMap<>();
  // Token type table
  final HashMap<String, String> state2tokenType = new HashMap<>();
  // Utility
  final HashMap<String, String> name2state = new HashMap<>();
  // Start state
  private String s0;

  //------------------------------------------------------------
  // TODO: build your tables in the constructor and implement
  // the get methods.
  //------------------------------------------------------------

  /**
   * Builds the tables needed for the scanner.
   */
  public Scanner(TableReader tableReader) {
    // TODO: starting with the skeleton code below, build the
    // classifer, transition and token type tables. You will need
    // to also implement the test functions below once you have your
    // tables built.

    // Build catMap, mapping a character to a category.
    for (TableReader.CharCat cat : tableReader.getClassifier()) {
//      System.out.println("Character " + cat.getC() + " is of category "
//              + cat.getCategory());
      char2category.put(cat.getC(), cat.getCategory());
    }

    // Build the transition table. Given a state and a character category,
    // give a new state.
    for (TableReader.Transition t : tableReader.getTransitions()) {
      String from = t.getFromStateName();
      String to = t.getToStateName();
//      System.out.println(from + " -- " + t.getCategory()
//              + " --> " + to);

      if (s0 == null)
        s0 = from;

      HashMap<String, String> cat2state;
      if (state2category2state.containsKey(from)) {
        cat2state = state2category2state.get(from);
      } else {
        cat2state = new HashMap<>();
        state2category2state.put(from, cat2state);
      }
      cat2state.put(t.getCategory(), to);
    }

    // Build the token types
    for (TableReader.TokenType tt : tableReader.getTokens()) {
//      System.out.println("State " + tt.getState()
//              + " accepts with the lexeme being of type " + tt.getType());

      state2tokenType.put(tt.getState(), tt.getType());
    }

  }

  /**
   * Returns the category for c or "not in alphabet" if c has no category. Do not hardcode
   * this. That is, this function should have nothing more than a table lookup
   * or two. You should not have any character literals in here such as 'r' or '3'.
   */
  public String getCategory(Character c) {
    if (!char2category.containsKey(c)) return "not in alphabet";
    return char2category.get(c);
  }

  /**
   * Returns the new state given a current state and category. This models
   * the transition table. Returns "error" if there is no transition.
   * Do not hardcode any state names or categories. You should have only
   * table lookups here.
   */
  public String getNewState(String state, String category) {
    if (!state2category2state.containsKey(state)) return "error";
    if (!state2category2state.get(state).containsKey(category)) return "error";
    return state2category2state.get(state).get(category);
  }

  /**
   * Returns the type of token corresponding to a given state. If the state
   * is not accepting then return "error".
   * Do not hardcode any state names or token types.
   */
  public String getTokenType(String state) {
    if (!state2tokenType.containsKey(state)) return "error";
    return state2tokenType.get(state);
  }

  //------------------------------------------------------------
  // TODO: implement nextToken
  //------------------------------------------------------------

  /**
   * Return the next token or null if there's a lexical error.
   */
  public Token nextToken(ScanStream ss) {
    // TODO: get a single token. This is an implementation of the nextToken
    // algorithm given in class. You may *not* use TableReader in this
    // function. Return null if there is a lexical error.

    String state = s0;
    String lexeme = "";
    Stack<String> stack = new Stack<>();
    String bad = "bad";
    String error = "error";
    stack.push(bad);
    while (state != error) {
      char c;
      try {
        c = ss.next();
        System.out.println("current state is " + state + " and next is " + c);
      } catch(Exception e) {
        state = error;
        continue;
      }
      lexeme += c;
      if (state2tokenType.containsKey(state))
        stack.clear();
      stack.push(state);
      String category = char2category.get(c);
      if (state2category2state.containsKey(state)) {
        state = state2category2state.get(state).get(category);
      } else {
        state = null;
      }
      if (state == null) {
        state = error;
      }
      System.out.println("Moving to state " + state);
    }
    while (state != bad && !state2tokenType.containsKey(state)) {
      state = stack.pop();
      if (!lexeme.isEmpty()) {
        lexeme = lexeme.substring(0, lexeme.length() - 1);
        ss.rollback();
      }
    }
    if (state2tokenType.containsKey(state)) {
      return new Token(state2tokenType.get(state), lexeme);
    }
    return null;
  }

}