diff options
Diffstat (limited to 'Homework/cs5300/project-one/p1-scanner/scanner/Scanner.java')
| -rw-r--r-- | Homework/cs5300/project-one/p1-scanner/scanner/Scanner.java | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/Homework/cs5300/project-one/p1-scanner/scanner/Scanner.java b/Homework/cs5300/project-one/p1-scanner/scanner/Scanner.java new file mode 100644 index 0000000..2581dcb --- /dev/null +++ b/Homework/cs5300/project-one/p1-scanner/scanner/Scanner.java @@ -0,0 +1,121 @@ +package scanner; + +import java.util.HashMap; +import java.util.Stack; + +public class Scanner { + HashMap<Character, String> charCategories; + HashMap<String, HashMap<String, String>> transitions; + HashMap<String, String> tokenTypes; + String s0; + + /** + * Builds the tables needed for the scanner. + */ + public Scanner(TableReader tableReader) { + charCategories = new HashMap<>(); + transitions = new HashMap<>(); + tokenTypes = new HashMap<>(); + + // Build catMap, mapping a character to a category. + for (TableReader.CharCat cat : tableReader.getClassifier()) + charCategories.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()) { + if (s0 == null) + s0 = t.getFromStateName(); + if (!transitions.containsKey(t.getFromStateName())) + transitions.put(t.getFromStateName(), new HashMap<String, String>()); + + transitions.get(t.getFromStateName()) + .put(t.getCategory(), t.getToStateName()); + } + + // Build the token types table + for (TableReader.TokenType tt : tableReader.getTokens()) + tokenTypes.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 (charCategories.containsKey(c)) + return charCategories.get(c); + + return "not in alphabet"; + } + + /** + * 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 (transitionExists(state, category)) + return transitions.get(state).get(category); + + return "error"; + } + + private boolean transitionExists(String state, String category) { + if (transitions.containsKey(state)) { + HashMap<String, String> transitionTable = transitions.get(state); + return transitionTable.containsKey(category); + } + return false; + } + + /** + * 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 (tokenTypes.containsKey(state)) + return tokenTypes.get(state); + return "error"; + } + + /** + * Return the next token or null if there's a lexical error. + */ + public Token nextToken(ScanStream ss) { + String state = s0; + String lexeme = ""; + + Stack<String> stack = new Stack<>(); + stack.push("bad"); + + while (!state.equals("error") && !ss.eof()) { + char c = ss.next(); + lexeme += c; + + if (tokenTypes.containsKey(state)) + stack.clear(); + + stack.push(state); + + state = getNewState(state, getCategory(c)); + } + + while (!tokenTypes.containsKey(state) && !state.equals("bad")) { + state = stack.pop(); + if (lexeme.length() > 0) + lexeme = lexeme.substring(0, lexeme.length() - 1); + + ss.rollback(); + } + + if (tokenTypes.containsKey(state)) + return new Token(tokenTypes.get(state), lexeme); + + return null; + } +} |
