diff --git a/sample.bb b/sample.bb new file mode 100644 index 0000000000000000000000000000000000000000..add947b0d9ed40c33ac7f7f33d5307ecd42dc35a --- /dev/null +++ b/sample.bb @@ -0,0 +1,12 @@ +clear x ; + +incr x; +incr x; +incr x; + + +#comment +while x not 0 do; + decr x; +end; + diff --git a/src/ClearParser.java b/src/ClearParser.java new file mode 100644 index 0000000000000000000000000000000000000000..c2f97ded3aedf241569253b05141104a8d574e96 --- /dev/null +++ b/src/ClearParser.java @@ -0,0 +1,19 @@ +public class ClearParser extends Unary { + + public ClearParser() { + super("clear"); + } + + + @Override + public void _execute() throws OperationError { + getInterpreter().executeClear(getVariable(0)); + } + + @Override + public String getChangeMessage() { + return "Cleared " + getVariableString(getVariable()); + } + + +} diff --git a/src/Comment.java b/src/Comment.java new file mode 100644 index 0000000000000000000000000000000000000000..defdd0b95b09a2ac54beed6fa94e416672133bbb --- /dev/null +++ b/src/Comment.java @@ -0,0 +1,35 @@ +public class Comment extends StatementParser { + + public Comment() { + super("#"); + } + + @Override + protected RegexChecker[] initializeStages() { + + return new RegexChecker[] { + new RegexChecker(".*(\\n)?") + }; + } + + @Override + protected String getStageErrorMessage(int stagePosition) { + return null; + } + + @Override + public void _execute() throws OperationError { + + } + + @Override + public String getChangeMessage() { + return "Executed comment."; + } + + //does nothing + @Override + public void printChange() { + + } +} diff --git a/src/DecrParser.java b/src/DecrParser.java new file mode 100644 index 0000000000000000000000000000000000000000..8358126af766905fdd3a4364a4699c3d575ccb81 --- /dev/null +++ b/src/DecrParser.java @@ -0,0 +1,17 @@ +public class DecrParser extends Unary { + + public DecrParser() { + super("decr"); + } + + + @Override + public void _execute() throws OperationError { + setNewValue(getInterpreter().executeDecr(getVariable())); + } + + @Override + public String getChangeMessage() { + return "Decremented " + getVariableString(getVariable()) + "to " + getNewValue(); + } +} diff --git a/src/EndParser.java b/src/EndParser.java new file mode 100644 index 0000000000000000000000000000000000000000..e98bd458a33c2a47ec08edbf1357fc2d1aa0bb57 --- /dev/null +++ b/src/EndParser.java @@ -0,0 +1,31 @@ +public class EndParser extends StatementParser { + public EndParser() { + super("end"); + } + + + @Override + protected RegexChecker[] initializeStages() { + return new RegexChecker[] { + fundamentalChecker(FundamentalChecker.END_OF_STATEMENT) + }; + } + + @Override + protected String getStageErrorMessage(int stagePosition) { + return "Missing semicolon"; + } + + + @Override + public void _execute() throws OperationError { + getInterpreter().executeEnd(); + } + + @Override + public String getChangeMessage() { + return "Going back to my while loop"; + } + + +} diff --git a/src/Environment.java b/src/Environment.java new file mode 100644 index 0000000000000000000000000000000000000000..ef1fa45a94b9e8bf62a443abfb9d2a4dddcbb68c --- /dev/null +++ b/src/Environment.java @@ -0,0 +1,48 @@ +import java.util.HashMap; + +public class Environment { + HashMap<String, Integer> varInfo; + + public Environment () { + varInfo = new HashMap<>(); + + } + + public void clear (String var) { + + varInfo.put(var, 0); + + } + + public int incr (String var) throws OperationError{ + assertContainsKey(var, "increment"); + int oldValue = varInfo.get(var); + varInfo.put(var, oldValue + 1); + return varInfo.get(var); + } + + public int decr (String var) throws OperationError { + assertContainsKey(var, "decrement"); + int oldValue = varInfo.get(var); + if (oldValue == 0) { + throw new OperationError("[ERROR] Attempt to decrement variable " + var + "which is equal to zero."); + } + varInfo.put(var, oldValue - 1); + return varInfo.get(var); + } + + public boolean equalsZero (String var) throws OperationError{ + assertContainsKey(var, "check equaling of zero for"); + + return varInfo.get(var) == 0; + } + + private void assertContainsKey(String key, String operation) throws OperationError { + if (!varInfo.containsKey(key)) { + throw new OperationError(String.format("[ERROR] Attempt to increment %s which does not exist.", key)); + } + } + + //public void printVars + +} diff --git a/src/IncrParser.java b/src/IncrParser.java new file mode 100644 index 0000000000000000000000000000000000000000..c2141dcdbefa6e471ef111c12c44a8d8a392890c --- /dev/null +++ b/src/IncrParser.java @@ -0,0 +1,18 @@ +public class IncrParser extends Unary { + + + public IncrParser() { + super("incr"); + } + + + @Override + public void _execute() throws OperationError { + setNewValue(getInterpreter().executeIncr(getVariable(0))); + } + + @Override + public String getChangeMessage() { + return getVariableString(getVariable()) + "incremented to " + getNewValue(); + } +} diff --git a/src/Interpreter.java b/src/Interpreter.java new file mode 100644 index 0000000000000000000000000000000000000000..179ef507b5476b1dce163f9a1a90e2c223af778e --- /dev/null +++ b/src/Interpreter.java @@ -0,0 +1,240 @@ +//package com.patryk.spacecadets.barebones; + +import java.io.FileNotFoundException; +import java.io.IOException; + +import java.util.EmptyStackException; +import java.util.Stack; + +public class Interpreter { + private String code; + private int index; + + private StatementParser[] possibleStatements; + + private RegexChecker anyBreakChecker; + + private Environment environment; + private Stack<Integer> loopStack; + + //maps the beginning of a while to its corresponding done statement + enum StatementParserName {CLEAR_PARSER, INCR_PARSER, DECR_PARSER, WHILE_PARSER, END_PARSER}; + + public Interpreter(String code) throws FileNotFoundException, IOException { + + this.code = code; + StatementParser.setInterpreter(this); + + environment = new Environment(); + loopStack = new Stack<Integer>(); + anyBreakChecker = new RegexChecker(StatementParser.OPTIONAL_ANY_BREAK_STR, code); + possibleStatements = new StatementParser[] {new ClearParser(), new IncrParser(), new DecrParser(), new WhileParser(), new EndParser(), new Comment()}; + + } + + private StatementParser getStatementParser(StatementParserName name) { + int id = name.ordinal(); + return possibleStatements[id]; + } + + public String getCode() { + return code; + } + + private int getIndex() { + return index; + } + + + public String getLineAndCol() { + return getLineAndCol(this.index); + } + + public String getLineAndCol(int index) { + return Util.getLineAndCol(getCode(), index).toString(); + } + + public Environment getEnvironment() { + return environment; + } + + private void skipWhitespace() { + anyBreakChecker.matches(index); + index = anyBreakChecker.end(); + } + + //the command respond methods. Will be called by a StatementParser + public void executeClear(String var) { + + environment.clear(var); + } + + public int executeIncr(String var) { + return environment.incr(var); + } + + public int executeDecr(String var) { + return environment.decr(var); + } + + public boolean executeWhile(String var) throws OperationError{ + //TODO come back here! + if (environment.equalsZero(var)) { // i.e. skip to the end + + index = getEndOfThisWhileLoop(); + return true; + } else { // go into this loop and push the start of the loop on the stack + loopStack.push(getStatementParser(StatementParserName.WHILE_PARSER).start()); + return false; + } + } + + public void executeEnd() throws OperationError{ + try { + index = loopStack.pop(); + } catch (EmptyStackException e) { + throw new OperationError("Have no while loop to go to!"); + } + } + + private int getEndOfThisWhileLoop() throws OperationError{ + /* Summary: + * Get index of closest end. Then, get index of next while loop. If there isn't a while loop, that's it! If there is, go to the end of that while loop and repeat the same process. + */ + //t=TODO + int whileStart = getStatementParser(StatementParserName.WHILE_PARSER).start(); + boolean anotherEndExists = getStatementParser(StatementParserName.END_PARSER).fullyMatchesAfter(index); + //if not, complain! + if (!anotherEndExists) { + throw new OperationError("No end exists after this while loop!"); + } + //otherwise + int endEnd = getStatementParser(StatementParserName.END_PARSER).end(); + //currently, the while parser has executed you while statement + int whileEnd = getStatementParser(StatementParserName.WHILE_PARSER).end(); + + int steps = 0; + + do { + if(getStatementParser(StatementParserName.WHILE_PARSER).fullyMatchesAfter(whileEnd)) { // if there is another while loop + whileEnd = getStatementParser(StatementParserName.WHILE_PARSER).end(); + + if (whileEnd > endEnd) { + break; + } else { + steps++; + } + + } else { + break; + } + + } while(true); + + for (int i = 0; i < steps; i++) { + boolean success = getStatementParser(StatementParserName.END_PARSER).fullyMatchesAfter(); + if(!success) { + throw new OperationError(WhileParser.getNoEndMessage()); + } + } + + getStatementParser(StatementParserName.WHILE_PARSER).fullyMatchesAfter(whileStart); + return getStatementParser(StatementParserName.END_PARSER).end(); + + } + + //needs to be un-fd-up + public void run() throws SyntaxError, OperationError{ + + while (index != code.length()) { + boolean matchFound = false; + for (StatementParser parser : possibleStatements) { + if (parser.initiallyMatches(index)) { + parser.checkSyntaxFully(); + index = parser.end(); + parser.execute(); + parser.printChange(); + skipWhitespace(); + matchFound = true; + break; + } + } + + if (!matchFound) { + throw new SyntaxError(getLineAndCol() + ": Unrecognized command."); + } + } + + + } + + /*public RegexChecker CreateFromCommand(String command) { + String[] words = command.split(" "); + String regex = OPTIONAL_ANY_BREAK; + for(int i = 0; i < words.length; i++) { + regex += words[i]; + if (i < words.length - 1) { + regex += BREAK; + } else { + regex += END_OF_STATEMENT; + } + } + + return new RegexChecker(regex, code); + }*/ + + + + + +} + + +/*class WhileChecker { + RegexChecker syntax; + RegexChecker variableName; + RegexChecker semiColon; + + public WhileChecker(String code) { + syntax = RegexChecker("while ") + } +}*/ + + +//unused +/* + public int getEndOfNextEnd (Matcher whileMatcher, Matcher endMatcher) { + //if there are no more whiles + endMatcher.find(index); + int startOfNextEnd = endMatcher.start(); + + //int nextWhile = 0; + + int steps = 0; + + do { + + //we see if there are any more while loops before the next end + if (!whileMatcher.find()) { + break; + } + + if (whileMatcher.start() > startOfNextEnd) { + break; + } + //so there is a while before the end + + steps ++; + + }while(true); + + for(int i = 0; i < steps; i++) { + endMatcher.find(); + } + + return endMatcher.end(); + } + */ + + + diff --git a/src/LineAndCol.java b/src/LineAndCol.java new file mode 100644 index 0000000000000000000000000000000000000000..8f56532c02461fb36262d7c208a3588e642c9ef5 --- /dev/null +++ b/src/LineAndCol.java @@ -0,0 +1,12 @@ +public class LineAndCol { + public int lineNumber, columnNumber; + + public LineAndCol (int lineNumber, int columnNumber) { + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + } + + public String toString() { + return String.format("Line %d, col %d", lineNumber, columnNumber); + } +} \ No newline at end of file diff --git a/src/Main.java b/src/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..7d9da4a3973538c42c5e678913b9fca40dc563be --- /dev/null +++ b/src/Main.java @@ -0,0 +1,49 @@ +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; + +public class Main { + private static final String DEFAULT_FILENAME = "sample.bb"; + //handles syntax errors locally, but still may throw file not found errors. + private Main(String fileName) throws FileNotFoundException, IOException{ + String code = getStringFromFile(new FileReader(fileName)); + try { + Interpreter interpreter = new Interpreter(code); + interpreter.run(); + //then print the values of the variables optionally + } catch (RuntimeException e) { + System.err.println(e.getMessage()); + System.exit(1); + } + + } + + private String getStringFromFile (FileReader reader) throws IOException { + String code = ""; + int charCode; + while ((charCode = reader.read()) != -1) { + code += (char) charCode; + } + + return code; + } + public static void main(String[] args) { + + int filenamePos = 1; + String fileName; + + //if no filename was specified, set the file name to default + if (args.length <= filenamePos ){ + fileName = DEFAULT_FILENAME; + } else { + fileName = args[filenamePos]; + } + + try { + Main main = new Main(fileName); + } catch (Exception e) { + e.printStackTrace(); + System.exit(-1); + } + } +} diff --git a/src/OperationError.java b/src/OperationError.java new file mode 100644 index 0000000000000000000000000000000000000000..786c6367a9daa2a2ce42eca8ab523721b7789924 --- /dev/null +++ b/src/OperationError.java @@ -0,0 +1,7 @@ +import java.lang.RuntimeException; + +public class OperationError extends RuntimeException { + public OperationError(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/RegexChecker.java b/src/RegexChecker.java new file mode 100644 index 0000000000000000000000000000000000000000..2f4addf9732534bb3a81ebbf3659c04229e5c929 --- /dev/null +++ b/src/RegexChecker.java @@ -0,0 +1,54 @@ +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +class RegexChecker { + + private Pattern pattern; + private Matcher matcher; + + + public RegexChecker(String patternRegex) { + pattern = Pattern.compile(patternRegex); + } + + public RegexChecker(String patternRegex, String code) { + pattern = Pattern.compile(patternRegex); + setCode(code); + } + + public void setCode(String code) { + matcher = pattern.matcher(code); + } + + public boolean matches(int index) { + if (matcher.find(index)) { + int regexStart = matcher.start(); + if(!(regexStart == index)) { + return false; + } + return true; + } + + return false; + } + + public boolean matchesAfter() { + return matcher.find(); + } + + public boolean matchesAfter(int index) { + return matcher.find(index); + } + + public String group(int groupID) { + return matcher.group(groupID); + } + + public int start() { + return matcher.start(); + } + + public int end() { + return matcher.end(); + } +} \ No newline at end of file diff --git a/src/SampleStrings.java b/src/SampleStrings.java new file mode 100644 index 0000000000000000000000000000000000000000..5a4e6cf204d8a463db9627cfc36a2908ff123cee --- /dev/null +++ b/src/SampleStrings.java @@ -0,0 +1,13 @@ +public enum SampleStrings { + VARIABLE_NAME_STR ( "([A-Za-z]*)"), + OPTIONAL_ANY_BREAK_STR ( "[\\n\\s]*" ), + BREAK_STR ( "\\s+" ), + OPTIONAL_BREAK_STR ( "\\s*" ), + SEMI_COLON_STR ( ";" ); + + private String value; + + SampleStrings(String value) { + this.value = value; + } +} diff --git a/src/StatementParser.java b/src/StatementParser.java new file mode 100644 index 0000000000000000000000000000000000000000..d7b9be80c25981ca68b24502a31a937074c89f3f --- /dev/null +++ b/src/StatementParser.java @@ -0,0 +1,204 @@ +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)); + } +} diff --git a/src/SyntaxError.java b/src/SyntaxError.java new file mode 100644 index 0000000000000000000000000000000000000000..718b85a1314bc6a2de73fef8b260e78092a9f094 --- /dev/null +++ b/src/SyntaxError.java @@ -0,0 +1,5 @@ +public class SyntaxError extends RuntimeException { + public SyntaxError(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/Test.java b/src/Test.java new file mode 100644 index 0000000000000000000000000000000000000000..ccd8b23749870204ac384df0259c49e0c931ca21 --- /dev/null +++ b/src/Test.java @@ -0,0 +1,14 @@ +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +class Test { + public static void main(String[] args) { + String command = "while; incr; decr"; + Pattern commandPattern = Pattern.compile("([while,incr,decr])"); + Matcher matcher = commandPattern.matcher(command); + if (matcher.find()) { + System.out.println(String.format("Group: %s", matcher.group(1))); + } + + } +} diff --git a/src/Unary.java b/src/Unary.java new file mode 100644 index 0000000000000000000000000000000000000000..876e8a85e9bec42beed1dfe014c53aaae36f538a --- /dev/null +++ b/src/Unary.java @@ -0,0 +1,70 @@ +public abstract class Unary extends StatementParser{ + private String var; + + private int newValue; + + enum Stage {BREAK, VARNAME, END}; + + + public Unary(String commandName) { + super(commandName); + } + + protected int getNewValue() { + return newValue; + } + + protected void setNewValue(int x) { + newValue = x; + } + + protected String getVariable() { + return var; + } + + @Override + protected RegexChecker[] initializeStages() { + return new RegexChecker[] { + fundamentalChecker(FundamentalChecker.BREAK), + fundamentalChecker(FundamentalChecker.VARIABLE_NAME), + fundamentalChecker(FundamentalChecker.END_OF_STATEMENT) + }; + } + + + @Override + protected String getVariable(int varID) { + return var; + } + + @Override + protected int getVarIDFromStageID(int stageID) { + if (stageID == Stage.VARNAME.ordinal()) { + return 0; + } + return -1; + } + + @Override + protected void afterStagePass(int stageID) { + if (stageID == Stage.VARNAME.ordinal()) { + var = fundamentalChecker(FundamentalChecker.VARIABLE_NAME).group(VAR_NAME_GROUP); + } + } + + @Override + protected String getStageErrorMessage(int stagePosition) { + Stage stage = Stage.values()[stagePosition]; + switch (stage) { + case BREAK: + return "Expected break after \'" + getCommandName() + "\'"; + case VARNAME: + return getVariableNameErrorMessage(); + case END: + return "Missing semicolon after variable name"; + default: + return "Unknown error"; + } + } + +} diff --git a/src/Util.java b/src/Util.java new file mode 100644 index 0000000000000000000000000000000000000000..4bff9e25e8f30ee232edcb59299631ddc9227588 --- /dev/null +++ b/src/Util.java @@ -0,0 +1,23 @@ +public class Util { + static LineAndCol getLineAndCol(String text, int index) { + + int lineNumber = 1; + int lastNewLineIndex = 0; + + + for (int i = 0; i < index; i++) { + if (text.charAt(i) == '\n') { + lastNewLineIndex = i; + lineNumber ++; + } + } + + int colNumber = index - lastNewLineIndex; + if (colNumber == 0) { + colNumber = 1; + } + + return new LineAndCol(lineNumber, colNumber); + + } +} \ No newline at end of file diff --git a/src/WhileParser.java b/src/WhileParser.java new file mode 100644 index 0000000000000000000000000000000000000000..1ae8c3c4c8c8adc48a10e33800335206fb6d0da4 --- /dev/null +++ b/src/WhileParser.java @@ -0,0 +1,86 @@ +public class WhileParser extends StatementParser { + enum Stage {BREAK_1, VAR, BREAK_2, NOT_0_DO, END}; + public WhileParser() { + super("while"); + } + + private String variable; + + private boolean skipped; + + @Override + protected String getVariable(int varID) { + return variable; + } + + @Override + protected int getVarIDFromStageID(int stageID) { + if (stageID == Stage.VAR.ordinal()) { + return 0; + } + return -1; + } + + + @Override + protected RegexChecker[] initializeStages() { + return new RegexChecker[] { + fundamentalChecker(FundamentalChecker.BREAK), + fundamentalChecker(FundamentalChecker.VARIABLE_NAME), + fundamentalChecker(FundamentalChecker.BREAK), + new RegexChecker("not" + BREAK_STR + "0" + BREAK_STR + "do"), + fundamentalChecker(FundamentalChecker.END_OF_STATEMENT) + }; + } + + + @Override + protected String getStageErrorMessage(int stagePosition) { + Stage stage = Stage.values()[stagePosition]; + switch (stage) { + case BREAK_1: + return "Expected break after \'while\'"; + case VAR: + return getVariableNameErrorMessage(); + case BREAK_2: + return "Expected break after variable name."; + case NOT_0_DO: + return "Expected \'not 0 do;\' after variable name"; + case END: + return "No semicolon after valid variable name."; + default: + return "Unknown error."; + } + } + + @Override + protected void afterStagePass(int stageID){ + if(Stage.values()[stageID] == Stage.VAR) { + variable = fundamentalChecker(FundamentalChecker.VARIABLE_NAME).group(VAR_NAME_GROUP); + } + } + + + /*public int getStartOfStatement() { + return + }*/ + + + @Override + public void _execute() throws OperationError { + skipped = getInterpreter().executeWhile(variable); + } + + @Override + public String getChangeMessage() { + if (skipped) { + return getVariableString(variable) + " is 0. Skipped loop."; + } else { + return getVariableString(variable) + " not 0. Went into loop."; + } + } + + public static String getNoEndMessage() { + return "No end exists after this while loop!"; + } +}