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!";
+    }
+}