summaryrefslogtreecommitdiff
path: root/Homework/cs5300/project-one/p1-scanner/scanner/Scanner.java
diff options
context:
space:
mode:
authorElizabeth Alexander Hunt <me@liz.coffee>2026-07-02 11:55:17 -0700
committerElizabeth Alexander Hunt <me@liz.coffee>2026-07-02 11:55:17 -0700
commit6bf4b90c90f15f4ab60833bddf5b5756d1a6b1f6 (patch)
treeed97e39ec77c5231ffd2c394493e68d00ddac5a4 /Homework/cs5300/project-one/p1-scanner/scanner/Scanner.java
downloadmisc-undergrad-6bf4b90c90f15f4ab60833bddf5b5756d1a6b1f6.tar.gz
misc-undergrad-6bf4b90c90f15f4ab60833bddf5b5756d1a6b1f6.zip
Diffstat (limited to 'Homework/cs5300/project-one/p1-scanner/scanner/Scanner.java')
-rw-r--r--Homework/cs5300/project-one/p1-scanner/scanner/Scanner.java121
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;
+ }
+}