diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000000000000000000000000000000000000..e96534fb27b68192f27f985d3879e173ec77adb8 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="Palette2"> + <group name="Swing"> + <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" /> + </item> + <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" /> + </item> + <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true"> + <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" /> + <initial-values> + <property name="text" value="Button" /> + </initial-values> + </item> + <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="RadioButton" /> + </initial-values> + </item> + <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="CheckBox" /> + </initial-values> + </item> + <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="Label" /> + </initial-values> + </item> + <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3"> + <preferred-size width="200" height="200" /> + </default-constraints> + </item> + <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3"> + <preferred-size width="200" height="200" /> + </default-constraints> + </item> + <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" /> + </item> + <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1"> + <preferred-size width="-1" height="20" /> + </default-constraints> + </item> + <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" /> + </item> + <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" /> + </item> + </group> + </component> +</project> \ No newline at end of file diff --git a/src/Expression.java b/src/Expression.java index 68630f1a486f03a8c0fa50bade2a55a25eace03c..9a67eee1a89b525982d7d41d24fde0a71ebb00c6 100644 --- a/src/Expression.java +++ b/src/Expression.java @@ -3,10 +3,17 @@ import java.util.List; import java.util.Objects; public class Expression { + /** + * @param <T> pure virtual interface of template T in order to have an abstracted consistent way of retrieving data + * , made safe by isinstance checks before any grab using getValue(). + */ public interface Value<T> { public T getValue(); } + /** + * A Value that holds an integer + */ static class IntVal implements Value<Integer> { Integer v; @@ -18,6 +25,9 @@ public class Expression { } } + /** + * A Value that holds an bool + */ static class BoolValue implements Value<Boolean> { boolean b; @@ -30,10 +40,16 @@ public class Expression { } } + /** + * Abstracted expression, all expressions must be evaluable, the template of value doesn't matter as its abstracted + */ interface Expr { Value run(ProgramHandler.ProgramState s); } + /** + * a constant expression, value template type doesnt matter because any value can be constant + */ public static class LiteralExpr implements Expr { Value x; @@ -47,11 +63,15 @@ public class Expression { } } - static class VarExpr implements Expr { + + /** + * a Variable expression, value template type matters because variables are lock into being Integers + */ + static class VarExpr implements Expr { String name; @Override - public Value run(ProgramHandler.ProgramState s) { + public Value<Integer> run(ProgramHandler.ProgramState s) { return new IntVal(s.varLookup.get(name)); } @@ -60,6 +80,10 @@ public class Expression { } } + /** + * A not comparison expression, the expr return types are not templated as this is irelevant, however the output + * value will always ben boolean + */ static class NotExpr implements Expr { Expr lhs, rhs; @@ -67,17 +91,13 @@ public class Expression { this.lhs = lhs; this.rhs = rhs; } - public Value run(ProgramHandler.ProgramState s) { + public Value<Boolean> run(ProgramHandler.ProgramState s) { Value lhsV = lhs.run(s); Value rhsV = rhs.run(s); if (lhsV.getClass() == rhsV.getClass()) { - return new BoolValue(lhsV.getValue() == rhsV.getValue()); + return new BoolValue(lhsV.getValue() != rhsV.getValue()); } - return new BoolValue(false); + return new BoolValue(true); } } - - public static class ExpressionBuilder { - List<Expr> x = new ArrayList<Expr>(); - } } diff --git a/src/Interpreter.java b/src/Interpreter.java index 577c933660ae099b2c935ddcbf5e6d7b1f32325a..991be3ba43984986f5cb06d3517904446bd6b4cf 100644 --- a/src/Interpreter.java +++ b/src/Interpreter.java @@ -2,6 +2,9 @@ import java.io.File; import java.io.FileNotFoundException; import java.util.*; +/** + * the main class, runs all the sub-routinse + */ public class Interpreter { public static void main(String[] args) { try { @@ -15,10 +18,15 @@ public class Interpreter { data.append(" "); } reader.close(); - Lexer.LexerContainer container = Lexer.lexer(data.toString().trim().replaceAll(" +", " ")); + // Creating a container from a static lexer method + Pair<List<Token>, List<String>> container = Lexer.lexer(data.toString().trim().replaceAll(" +", " ")); + // creates a new state ProgramHandler.ProgramState state = new ProgramHandler.ProgramState(); + // creates a new main program from the parser ProgramHandler.Program program = Parser.parse(container); + // starts the programs running program.run(state); + // prints all variables and values for (Map.Entry<String, Integer> entry : state.varLookup.entrySet()) { System.out.println("Variable: " + entry.getKey() + ", Value: " + entry.getValue()); } diff --git a/src/Lexer.java b/src/Lexer.java index d588bd621201fb973fcb8de124b1a3f693c90fc6..ac2644aac1389af7a8b14ece320aba95a524609c 100644 --- a/src/Lexer.java +++ b/src/Lexer.java @@ -2,24 +2,21 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +/** + * The lexers job is to take a string from a file and convert it into a list of tokens and a list of variables referenced + * l : String -> [token] + */ public class Lexer { - - public static class LexerContainer { - public List<Token> tokens; - List<String> vars; - public LexerContainer(List<Token> tokens, List<String> vars) { - this.tokens = tokens; - this.vars = vars; - } - } - /** * @param file the file to be processed - * @return list of tokens produced by the lexer + * @return a Pair holding a list of the tokens and a list of the variable names */ - public static LexerContainer lexer(String file) { - List<Token> tokens = new ArrayList<Token>(); + public static Pair<List<Token>, List<String>> lexer(String file) { + List<Token> tokens = new ArrayList<>(); List<String> vars = new ArrayList<>(); + + // Looks through the file, identifying and isolating all tokens and all variables and constants, such that + // the order of vars and numbers in the tokens matches with the correct names/values in the vars list int previousChar = 0; for (int currentChar = 0; currentChar < file.length(); currentChar++) { if (file.charAt(currentChar) == ' ' || file.charAt(currentChar) == ';') { @@ -69,6 +66,6 @@ public class Lexer { previousChar = currentChar; } } - return new LexerContainer(tokens, vars); + return new Pair<>(tokens, vars); } } diff --git a/src/Pair.java b/src/Pair.java index 1a10efcf79ea3dc6cb9655b047b635e5a8f845a6..06a982d1ba31a468a7455c7689ed84bcb490d55e 100644 --- a/src/Pair.java +++ b/src/Pair.java @@ -1,3 +1,4 @@ +// Simple templated pair class because this was too hard for the java developers to do :) public class Pair<T, K> { T first; K second; diff --git a/src/Parser.java b/src/Parser.java index c3a1e9de8cf94b984d4734a5aad5e24d94c66358..a885751b7a990e08d25fb61e75d149ad38292747 100644 --- a/src/Parser.java +++ b/src/Parser.java @@ -1,20 +1,34 @@ import java.util.List; +/** + * A parser that p : [token] -> program + */ public class Parser { - public static ProgramHandler.Program parse(Lexer.LexerContainer container) { - List<Token> tokens = container.tokens; - List<String> vars = container.vars; + /** + * @param container the list of tokens and variables generated by the lexer + * @return the program that contains all the statements in the program + */ + public static ProgramHandler.Program parse(Pair<List<Token>, List<String>> container) { + // pulls the individual lists from the pair for convenience + List<Token> tokens = container.first; + List<String> vars = container.second; + + // creates a new program where commands can be assigned ProgramHandler.Program program = new ProgramHandler.Program(); + // goes through each token while (!tokens.isEmpty()) { Token token = tokens.remove(0); + // removes the first one and stores it if (token != Token.SemiColon) { switch (token) { case Clear -> { if (tokens.remove(0) == Token.Var) { + // creates a clear statement, creates a Variable instance from the name of the next variable ProgramHandler.ClearStatement statement = new ProgramHandler.ClearStatement(); statement.v = new ProgramHandler.Variable(vars.remove(0)); + // adds the statement to the program to be run program.stmts.add(statement); } else { System.err.println("Clear not followed by variable"); @@ -22,8 +36,10 @@ public class Parser { } case Incr -> { if (tokens.remove(0) == Token.Var) { + // creates an incr statement, creates a Variable instance from the name of the next variable ProgramHandler.IncrStatement statement = new ProgramHandler.IncrStatement(); statement.v = new ProgramHandler.Variable(vars.remove(0)); + // adds the statement to the program to be run program.stmts.add(statement); } else { System.err.println("Incr not followed by variable"); @@ -31,18 +47,25 @@ public class Parser { } case Decr -> { if (tokens.remove(0) == Token.Var) { + // creates a decr statement, creates a Variable instance from the name of the next variable ProgramHandler.DecrStatement statement = new ProgramHandler.DecrStatement(); statement.v = new ProgramHandler.Variable(vars.remove(0)); + // adds the statement to the program to be run program.stmts.add(statement); } else { System.err.println("Decr not followed by variable"); } } case While -> { + // creates a while loop ProgramHandler.WhileLoop loop = new ProgramHandler.WhileLoop(); + // uses the expression parser to develop an expression Expression.Expr expr = eParse(container); + // gives the loop the expression loop.expr = expr; + // recursively pass until next end to create program to be looped loop.p = parse(container); + // add it to this programs statements program.stmts.add(loop); } case End -> { @@ -58,32 +81,58 @@ public class Parser { return program; } - private static Expression.Expr eParse(Lexer.LexerContainer container){ - List<Token> tokens = container.tokens; - List<String> vars = container.vars; + /** + * @param container contains tokens and variable names + * @return + */ + private static Expression.Expr eParse(Pair<List<Token>, List<String>> container){ + List<Token> tokens = container.first; + List<String> vars = container.second; Expression.Expr e = null; while (!tokens.isEmpty()) { + // takes first token Token token = tokens.remove(0); switch (token) { case Var -> { + // if expression doesnt exist, create one if (e == null) { e = new Expression.VarExpr(vars.remove(0)); } else { - System.err.println("Expression not valid"); + // this means 2 variables or numbers are in a row which is meaningless + System.err.print("Expression not valid around " + token); + for (int i = 0; i < 5; i++) { + if (i < tokens.size()) + System.err.print(tokens.get(i)); + } System.exit(1); } } case Number -> { if (e == null) { + // if expression doesnt exist, create one e = new Expression.LiteralExpr(new Expression.IntVal(Integer.parseInt(vars.remove(0)))); } else { - System.err.println("Expression not valid"); + // this means 2 variables or numbers are in a row which is meaningless + System.err.print("Expression not valid around " + token); + for (int i = 0; i < 5; i++) { + if (i < tokens.size()) + System.err.print(tokens.get(i)); + } System.exit(1); } } case Not -> { if (e != null) { + // if preceded by an expression continue Expression.Expr rhs = eParse(container); e = new Expression.NotExpr(e, rhs); + } else { + // this means not isn't preceded by a variable or number, making it invalid + System.err.print("Expression not valid around " + token); + for (int i = 0; i < 5; i++) { + if (i < tokens.size()) + System.err.print(tokens.get(i)); + } + System.exit(1); } } case Do, End, SemiColon -> { return e; @@ -92,6 +141,7 @@ public class Parser { } System.err.println("Expr never ended"); System.exit(1); + // code never reached, here to satisfy javac return new Expression.LiteralExpr(new Expression.IntVal(1)); } } diff --git a/src/ProgramHandler.java b/src/ProgramHandler.java index fbd7b8d3a7fee4a6f20dfdc6293078976c22122a..b8637166dc7333a9cd4a20b9dc6c59a681b4ac9e 100644 --- a/src/ProgramHandler.java +++ b/src/ProgramHandler.java @@ -21,10 +21,17 @@ public class ProgramHandler { return single_instance; } + /** + * Pure Virtual interface in order to create a set of programs that all have the void run(ProgramState) method + */ interface Runnable { public void run(ProgramState state); } + + /** + * All statements must be runnable, this is a wrapper class to determine what is a statement and what is just runnable + */ static class Statement implements Runnable { @Override public void run(ProgramState state) { @@ -32,79 +39,130 @@ public class ProgramHandler { } } + /** + * Wrapper for a hash map, containing variables names and values + */ static class ProgramState { public HashMap<String, Integer> varLookup = new HashMap<>(); - - public HashMap<String, Integer> getState() { - return varLookup; - } } + /** + * A program stores a list of statements which all impliment the function run(ProgramState) meaning that it can run + * all statements in its program + */ static class Program implements Runnable { public List<Statement> stmts = new ArrayList<Statement>(); + /** + * implimentation of the abstract Runnable's void run(ProgramState) + * @param state holds the varLookup + */ @Override public void run(ProgramState state) { + // loops through all statements and runs them each for (Statement statement : stmts) { statement.run(state); } } } + /** + * "Clear" statement implementation + */ static class ClearStatement extends Statement { + // the variable to be worked on when ran public Variable v; + /** + * @param state the varLookup + */ @Override public void run(ProgramState state) { + // checks if the variable exists if (!state.varLookup.containsKey(v.name)) { + // if no, create it state.varLookup.put(v.name, 0); } else { + // if yes, set it to 0 state.varLookup.replace(v.name, 0); } } } + /** + * "Incr" statement implementation + */ static class IncrStatement extends Statement { + // the variable to be worked on when ran public Variable v; + /** + * @param state the varLookup container + */ @Override public void run(ProgramState state) { if (state.varLookup.containsKey(v.name)) { + // if v exists in varLookup, increase value by 1 int curr = state.varLookup.get(v.name); state.varLookup.replace(v.name, curr + 1); } } } + /** + * "Decr" statement implementation + */ static class DecrStatement extends Statement { + // the variable to be worked on when ran public Variable v; + /** + * @param state varLookup container + */ @Override public void run(ProgramState state) { if (state.varLookup.containsKey(v.name)) { + // if v in varLookup, decrease value by 1 int curr = state.varLookup.get(v.name); state.varLookup.replace(v.name, curr - 1); } } } + /** + * Implementation of while loop + */ static class WhileLoop extends Statement { + // a program of its content to recursively run public Program p; + // an expression that if it returns a boolValue, will determine when the loop runs or continues public Expression.Expr expr; + /** + * @param state varLookup container + */ @Override public void run(ProgramState state) { + // gets the value from the expression at this instance - note value is an abstract class and val is a sub class + // to Value Expression.Value val = expr.run(state); Expression.BoolValue boolValue = val instanceof Expression.BoolValue ? ((Expression.BoolValue) val) : null; + // Checks that val is a boolValue, and creates a new boolValue if (boolValue != null) { - if (!boolValue.b) { + // runs if the bool is true + if (boolValue.b) { + // runs the recursive program p.run(state); + // reruns "void run(ProgramState)" to check expr again and continue until the bool is false run(state); } } else { + // if the expression is not of boolType, the user has made a mistake and not properly defined their + // Expression System.err.println("Wrong Expression Type"); } } } } + diff --git a/src/Token.java b/src/Token.java index d715d491a7a68bf8c7d690501ed36332de7abf0a..3976481e842c117d825fcc662e8af244f4ba425d 100644 --- a/src/Token.java +++ b/src/Token.java @@ -1,3 +1,4 @@ +// all different tokens usable by the lexer public enum Token { Clear, Incr, diff --git a/src/program.bb b/src/program.bb index d088686cf58265a805a553ab110c8986aa740ef3..7b542fedafe35d813af263473db92de397d74c93 100644 --- a/src/program.bb +++ b/src/program.bb @@ -1,13 +1,21 @@ clear X; -clear Y; -incr Y; -clear jakub; -while jakub not 7 do; - incr jakub; -end; -incr X; incr X; incr X; +clear Y; +incr Y; +incr Y; +incr Y; +clear Z; while X not 0 do; + clear W; + while Y not 0 do; + incr Z; + incr W; + decr Y; + end; + while W not 0 do; + incr Y; + decr W; + end; decr X; end; \ No newline at end of file