Select Git revision
StatementParser.java
-
p9malino26 authoredp9malino26 authored
StatementParser.java 6.70 KiB
import java.util.HashSet;
//not thread safe! Only one instance per program!
public abstract class StatementParser {
private String commandName;
private RegexChecker initialRegexChecker;
private RegexChecker[] checkingStages; // to be initialized in sub class
private static Interpreter interpreter;
//private int startIndex;
private int tempIndex;
protected static final String VARIABLE_NAME_STR = "([A-Za-z]*)";
public static final String OPTIONAL_ANY_BREAK_STR = "[\\n\\s]*";
protected static final String BREAK_STR = "\\s+";
protected static final String OPTIONAL_BREAK_STR = "\\s*";
protected static final String SEMI_COLON_STR = ";";
protected static final int VAR_NAME_GROUP = 0;
private static HashSet<String> reservedWords = new HashSet<>();
enum FundamentalChecker {VARIABLE_NAME, OPTIONAL_ANY_BREAK, BREAK, OPTIONAL_BREAK, SEMI_COLON, END_OF_STATEMENT};
protected static RegexChecker[] fundamentalCheckers = { new RegexChecker(VARIABLE_NAME_STR),
new RegexChecker(OPTIONAL_ANY_BREAK_STR),
new RegexChecker(BREAK_STR),
new RegexChecker(OPTIONAL_BREAK_STR),
new RegexChecker(SEMI_COLON_STR),
new RegexChecker(OPTIONAL_BREAK_STR + SEMI_COLON_STR)};
protected static RegexChecker fundamentalChecker(FundamentalChecker checkerType) {
return fundamentalCheckers[checkerType.ordinal()];
}
//call this first ASAP!
public static void setInterpreter(Interpreter _interpreter) {
//the fundamental checkers will be set the code of the parser.
//Then when the constructor is called, the initial string will be instantiated with that
//code.
interpreter = _interpreter;
for (RegexChecker fundamentalChecker : fundamentalCheckers) {
fundamentalChecker.setCode(interpreter.getCode());
}
}
protected static boolean isValidVariableName(String name) {
return !reservedWords.contains(name);
}
public StatementParser(String commandName) {
this.commandName = commandName;
this.initialRegexChecker = new RegexChecker(commandName, interpreter.getCode());
checkingStages = initializeStages();
for (RegexChecker stage: checkingStages) {
stage.setCode(interpreter.getCode());
}
reservedWords.add(commandName);
}
protected abstract RegexChecker[] initializeStages();
public static Interpreter getInterpreter() {
return interpreter;
}
public boolean initiallyMatches(int index ) {
//first set the fundamental checkers to this
boolean success = initialRegexChecker.matches(index);
return processInitialMatch(success);
}
public boolean initiallyMatchesAfter(int index) {
boolean success = initialRegexChecker.matchesAfter(index);
return processInitialMatch(success);
}
private boolean processInitialMatch(boolean success) {
if(success) {
setIndex(initialRegexChecker.end());
//startIndex = initialRegexChecker.start();
}
return success;
}
public boolean fullyMatchesAfter(int index) throws SyntaxError{
if (initiallyMatchesAfter(index)) {
checkSyntaxFully();
return true;
}
return false;
}
public boolean fullyMatchesAfter() {
return fullyMatchesAfter(end());
}
public String getCommandName() {
return commandName;
}
private int getIndex() {
return tempIndex;
}
private void setIndex(int newIndex) {
tempIndex = newIndex;
}
public int start() {
return initialRegexChecker.start();
}
public int end() {
return tempIndex;
}
protected String getVariable(int varID) { return null;}
//maps stage id (in for loop) to variable id
protected int getVarIDFromStageID(int varID) { return -1;}
protected static String getVariableNameErrorMessage(String varName) {
return "Invalid variable name: " + varName;
}
protected static String getVariableNameErrorMessage() {
return "Invalid variable name.";
}
protected void assertVariableName(String name) throws SyntaxError{
if (!isValidVariableName(name)) {
throwSyntaxError(getVariableNameErrorMessage(name));
}
}
private String getOperationContext(int index) {
return commandName + ": " + interpreter.getLineAndCol(index);
}
private String getOperationContext() {
return getOperationContext(getIndex());
}
//YOU MUST call setParser before constructing!
protected abstract String getStageErrorMessage(int stagePosition);
public void checkSyntaxFully() throws SyntaxError {
for (int i = 0; i < checkingStages.length; i++) {
if (!checkingStages[i].matches(getIndex())) {
throwSyntaxError(getStageErrorMessage(i));
}
//do something after the stage has been passed, such as setting up the variable
afterStagePass(i);
int varID = getVarIDFromStageID(i);
//if we are at a variable, we must check it
if (varID != -1) {
String var = getVariable(varID);
assertVariableName(var);
}
setIndex(checkingStages[i].end());
}
}
//for there to be overridden
protected void afterStagePass(int stageID) {}
public void execute() throws OperationError {
try {
_execute();
} catch (OperationError e) {
throwOperationError(e.getMessage());
}
}
protected abstract void _execute() throws OperationError;
public abstract String getChangeMessage();
public void printChange() {
System.out.println(formatMessage("INFO", start(),getChangeMessage()));
}
protected static String getVariableString(String var) {
return "variable \'" + var + "\' ";
}
private String formatMessage(String messageIdentifier, int index, String mainMessage) {
return String.format("[%s] %s: %s", messageIdentifier, getOperationContext(index), mainMessage);
}
public void throwSyntaxError(String message) throws SyntaxError {
throw new SyntaxError(formatMessage("SYNTAX ERROR", getIndex(), message));
}
public void throwOperationError(String message) throws OperationError {
throw new OperationError(formatMessage("OPERATION ERROR", start(), message));
}
}