summaryrefslogtreecommitdiffstats
path: root/code/Interpreter2
diff options
context:
space:
mode:
Diffstat (limited to 'code/Interpreter2')
-rw-r--r--code/Interpreter2/.idea/misc.xml6
-rw-r--r--code/Interpreter2/.idea/modules.xml8
-rw-r--r--code/Interpreter2/.idea/uiDesigner.xml124
-rw-r--r--code/Interpreter2/.idea/vcs.xml6
-rw-r--r--code/Interpreter2/.idea/workspace.xml52
-rw-r--r--code/Interpreter2/Interpreter2.iml11
-rw-r--r--code/Interpreter2/src/Interpreter/Environment.java30
-rw-r--r--code/Interpreter2/src/Interpreter/Expression.java84
-rw-r--r--code/Interpreter2/src/Interpreter/Interpreter.java131
-rw-r--r--code/Interpreter2/src/Interpreter/Language.java63
-rw-r--r--code/Interpreter2/src/Interpreter/Parser.java179
-rw-r--r--code/Interpreter2/src/Interpreter/Statement.java49
-rw-r--r--code/Interpreter2/src/Interpreter/Token.java23
-rw-r--r--code/Interpreter2/src/Interpreter/TokenScanner.java179
-rw-r--r--code/Interpreter2/src/Interpreter/TokenType.java17
15 files changed, 962 insertions, 0 deletions
diff --git a/code/Interpreter2/.idea/misc.xml b/code/Interpreter2/.idea/misc.xml
new file mode 100644
index 0000000..b1001d2
--- /dev/null
+++ b/code/Interpreter2/.idea/misc.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_15" default="true" project-jdk-name="openjdk-15" project-jdk-type="JavaSDK">
+ <output url="file://$PROJECT_DIR$/out" />
+ </component>
+</project> \ No newline at end of file
diff --git a/code/Interpreter2/.idea/modules.xml b/code/Interpreter2/.idea/modules.xml
new file mode 100644
index 0000000..944dd7c
--- /dev/null
+++ b/code/Interpreter2/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectModuleManager">
+ <modules>
+ <module fileurl="file://$PROJECT_DIR$/Interpreter2.iml" filepath="$PROJECT_DIR$/Interpreter2.iml" />
+ </modules>
+ </component>
+</project> \ No newline at end of file
diff --git a/code/Interpreter2/.idea/uiDesigner.xml b/code/Interpreter2/.idea/uiDesigner.xml
new file mode 100644
index 0000000..e96534f
--- /dev/null
+++ b/code/Interpreter2/.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/code/Interpreter2/.idea/vcs.xml b/code/Interpreter2/.idea/vcs.xml
new file mode 100644
index 0000000..b2bdec2
--- /dev/null
+++ b/code/Interpreter2/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="VcsDirectoryMappings">
+ <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
+ </component>
+</project> \ No newline at end of file
diff --git a/code/Interpreter2/.idea/workspace.xml b/code/Interpreter2/.idea/workspace.xml
new file mode 100644
index 0000000..4198910
--- /dev/null
+++ b/code/Interpreter2/.idea/workspace.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ChangeListManager">
+ <list default="true" id="d53ed2ac-d387-4e72-b30b-e936be78d097" name="Default Changelist" comment="" />
+ <option name="SHOW_DIALOG" value="false" />
+ <option name="HIGHLIGHT_CONFLICTS" value="true" />
+ <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
+ <option name="LAST_RESOLUTION" value="IGNORE" />
+ </component>
+ <component name="Git.Settings">
+ <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../.." />
+ </component>
+ <component name="ProjectId" id="20PtUsPCm3Avx9BljmzQRhs1xbs" />
+ <component name="ProjectLevelVcsManager" settingsEditedManually="true" />
+ <component name="ProjectViewState">
+ <option name="hideEmptyMiddlePackages" value="true" />
+ <option name="showLibraryContents" value="true" />
+ </component>
+ <component name="PropertiesComponent">
+ <property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
+ </component>
+ <component name="RunManager">
+ <configuration name="Language" type="Application" factoryName="Application">
+ <option name="MAIN_CLASS_NAME" value="Interpreter.Language" />
+ <module name="Interpreter2" />
+ <method v="2">
+ <option name="Make" enabled="true" />
+ </method>
+ </configuration>
+ </component>
+ <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
+ <component name="TaskManager">
+ <task active="true" id="Default" summary="Default task">
+ <changelist id="d53ed2ac-d387-4e72-b30b-e936be78d097" name="Default Changelist" comment="" />
+ <created>1635958069096</created>
+ <option name="number" value="Default" />
+ <option name="presentableId" value="Default" />
+ <updated>1635958069096</updated>
+ </task>
+ <servers />
+ </component>
+ <component name="WindowStateProjectService">
+ <state x="414" y="180" width="1092" height="714" key="#com.intellij.execution.impl.EditConfigurationsDialog" timestamp="1635958280293">
+ <screen x="0" y="0" width="1920" height="1050" />
+ </state>
+ <state x="414" y="180" width="1092" height="714" key="#com.intellij.execution.impl.EditConfigurationsDialog/0.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1635958280293" />
+ <state x="689" y="327" key="#com.intellij.ide.util.TreeClassChooserDialog" timestamp="1635958256418">
+ <screen x="0" y="0" width="1920" height="1050" />
+ </state>
+ <state x="689" y="327" key="#com.intellij.ide.util.TreeClassChooserDialog/0.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1635958256418" />
+ </component>
+</project> \ No newline at end of file
diff --git a/code/Interpreter2/Interpreter2.iml b/code/Interpreter2/Interpreter2.iml
new file mode 100644
index 0000000..c90834f
--- /dev/null
+++ b/code/Interpreter2/Interpreter2.iml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ </component>
+</module> \ No newline at end of file
diff --git a/code/Interpreter2/src/Interpreter/Environment.java b/code/Interpreter2/src/Interpreter/Environment.java
new file mode 100644
index 0000000..d191bde
--- /dev/null
+++ b/code/Interpreter2/src/Interpreter/Environment.java
@@ -0,0 +1,30 @@
+package Interpreter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Environment {
+ private final Map<String,Object> variableMap = new HashMap<>();
+
+ //Maybe check if variable is already defined?
+ public void defineVariable(String name,Object value){
+ variableMap.put(name, value);
+ }
+
+ public Object getVariable(String name){
+ if(variableMap.containsKey(name)){
+ return variableMap.get(name);
+ }
+ Language.displayError("Undefined Variable");
+ throw new Error();
+ }
+
+ public void assignVariable(String name,Object value){
+ if(variableMap.containsKey(name)){
+ variableMap.put(name, value);
+ return;
+ }
+ Language.displayError("Variable undefined");
+ throw new Error();
+ }
+}
diff --git a/code/Interpreter2/src/Interpreter/Expression.java b/code/Interpreter2/src/Interpreter/Expression.java
new file mode 100644
index 0000000..85ade48
--- /dev/null
+++ b/code/Interpreter2/src/Interpreter/Expression.java
@@ -0,0 +1,84 @@
+package Interpreter;
+
+abstract class Expression {
+ static class Binary extends Expression{
+
+ final Expression left;
+ final Expression right;
+ final Token op;
+
+ Binary(Expression left, Token op, Expression right){
+ this.left=left;
+ this.op=op;
+ this.right = right;
+ }
+
+ @Override
+ public String getExpressionType() {
+ return "binary";
+ }
+
+ }
+
+ static class Literal extends Expression{
+ final Token value;
+
+ Literal(Token value){
+ this.value=value;
+ }
+
+
+ @Override
+ public String getExpressionType() {
+ return "literal";
+ }
+
+ }
+
+ static class BracketedExpression extends Expression{
+ final Expression expr;
+
+ BracketedExpression(Expression expr){
+ this.expr=expr;
+ }
+
+ @Override
+ public String getExpressionType() {
+ return "bracket";
+ }
+
+
+ }
+
+ static class AssignmentExpression extends Expression{
+ final Token name;
+ final Expression value;
+
+ AssignmentExpression(Token name,Expression value){
+ this.name=name;
+ this.value=value;
+ }
+
+
+ @Override
+ public String getExpressionType() {
+ return "assign";
+ }
+
+ }
+
+ static class Variable extends Expression{
+
+ Variable(Token name){
+ this.name=name;
+
+ }
+ @Override
+ public String getExpressionType() {
+ return "var";
+ }
+ final Token name;
+
+ }
+ public abstract String getExpressionType();
+}
diff --git a/code/Interpreter2/src/Interpreter/Interpreter.java b/code/Interpreter2/src/Interpreter/Interpreter.java
new file mode 100644
index 0000000..65cdeb4
--- /dev/null
+++ b/code/Interpreter2/src/Interpreter/Interpreter.java
@@ -0,0 +1,131 @@
+package Interpreter;
+
+import java.util.List;
+
+import Interpreter.Expression.*;
+import Interpreter.Statement.ExpressionStatement;
+import Interpreter.Statement.PrintStatement;
+import Interpreter.Statement.VariableDeclaration;
+
+public class Interpreter {
+
+ private Environment environment = new Environment();
+
+ void interpret(List<Statement> statements){
+ try{
+ for (Statement statement: statements){
+ evaluateStatement(statement);
+ }
+ } catch (Error e){
+
+ }
+ }
+
+ private Object evaluateStatement(Statement statement){
+ switch(statement.getStatmentType()){
+ case "exprStmt":
+ return evalExpressionStatement((ExpressionStatement)statement);
+ case "vardec":
+ return evalVariableDeclaration((VariableDeclaration)statement);
+ case "print":
+ return evalPrintStatement((PrintStatement)statement);
+ default:
+ return null;
+ }
+ }
+ private Object evalExpressionStatement(ExpressionStatement stmt){
+ return evaluateExpression(stmt.expr);
+ }
+
+ private Object evalVariableDeclaration(VariableDeclaration vardec){
+ environment.defineVariable(vardec.name.text, null);
+ return null;
+ }
+
+ private Object evalPrintStatement(PrintStatement print){
+ System.out.println(evaluateExpression(print.expr));
+ return null;
+ }
+
+ private Object evaluateExpression(Expression expression){
+ switch(expression.getExpressionType()){
+ case "binary":
+ return evaluateBinaryExpression((Binary)expression);
+ case "literal":
+ return evaluateLiteralExpression((Literal)expression);
+ case "bracket":
+ return evaluateBracketedExpression((BracketedExpression)expression);
+ case "assign":
+ return evaluateAssignmentExpression((AssignmentExpression)expression);
+ case "var":
+ return evaluateVariableExpression((Variable)expression);
+ default:
+ return null;
+ }
+ }
+
+ private Object evaluateBinaryExpression(Binary expr){
+ Object leftEval = evaluateExpression(expr.left);
+ Object rightEval = evaluateExpression(expr.right);
+ switch (expr.op.type){
+ case PLUS:
+ if (checkOperandsNum(leftEval, leftEval)){
+ return (double)leftEval + (double)rightEval;
+ }
+ case STAR:
+ if (checkOperandsNum(leftEval, leftEval)){
+ return (double)leftEval * (double)rightEval;
+ }
+ case MINUS:
+ if (checkOperandsNum(leftEval, leftEval)){
+ return (double)leftEval - (double)rightEval;
+ }
+ case SLASH:
+ if (checkOperandsNum(leftEval, leftEval)){
+ return (double)leftEval / (double)rightEval;
+ }
+
+ case GREATER:
+ if (checkOperandsNum(leftEval, leftEval)){
+ return (double)leftEval > (double)rightEval;
+ }
+ case LESS:
+ if (checkOperandsNum(leftEval, leftEval)){
+ return (double)leftEval < (double)rightEval;
+ }
+
+ case EQUALITY:
+ return leftEval.equals(rightEval);
+ default:
+ break;
+ }
+ return null;
+ }
+
+ private Object evaluateLiteralExpression(Literal expr){
+ return expr.value.value;
+ }
+
+ private Object evaluateBracketedExpression(BracketedExpression expr){
+ return evaluateExpression(expr.expr);
+ }
+
+ private Object evaluateAssignmentExpression(AssignmentExpression expr){
+ Object assignedValue = evaluateExpression(expr.value);
+ environment.assignVariable(expr.name.text, assignedValue);
+ return null;
+ }
+
+ private Object evaluateVariableExpression(Variable expr){
+ return environment.getVariable(expr.name.text);
+ }
+
+ private boolean checkOperandsNum(Object left, Object right){
+ if (left instanceof Double && right instanceof Double){
+ return true;
+ } else {
+ Language.displayError("Operands must be numbers");
+ throw new Error();
+ }
+ }
+}
diff --git a/code/Interpreter2/src/Interpreter/Language.java b/code/Interpreter2/src/Interpreter/Language.java
new file mode 100644
index 0000000..80aa1e3
--- /dev/null
+++ b/code/Interpreter2/src/Interpreter/Language.java
@@ -0,0 +1,63 @@
+package Interpreter;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Scanner;
+
+//Base class for the interpreter
+public class Language {
+ static boolean hadError = false;
+ public static void main(String[] args){
+
+ //Allow users to input a single line of code
+ //Still needs some work to re-ask for input after each line
+ if (args.length < 1){
+ Scanner input = new Scanner(System.in);
+ String sourceCode = "1";
+ while (sourceCode!=""){
+ System.out.print("Code: ");
+ sourceCode = input.nextLine();
+ runInterpreter(sourceCode);
+ hadError=false;
+ }
+ input.close();
+
+ //Allow users to provide a path to a file as an argument
+ } else if (args.length==1){
+ try {
+ String sourcecode = Files.readString(Paths.get(args[0])); //Maybe should set charset here
+ runInterpreter(sourcecode);
+ } catch (IOException exception){
+ System.out.println("File not found");
+ }
+
+ } else {
+ System.out.println("Error, argument should be file path");
+ System.exit(64);
+ }
+ }
+
+ //Extract and print each token
+ private static void runInterpreter(String sourceCode){
+ TokenScanner scanner = new TokenScanner();
+ List<Token> tokens = scanner.extractTokens(sourceCode);
+ //for (Token token : tokens) {
+ // System.out.println(token);
+ //}
+ if (hadError) return;
+ //Parse into AST
+ Parser parser = new Parser(tokens);
+ List<Statement> ast = parser.parse();
+ if (hadError) return;
+ Interpreter interpreter = new Interpreter();
+ interpreter.interpret(ast);
+ }
+
+ static void displayError(String message){
+ hadError=true;
+ System.out.println("An error was encountered");
+ System.out.println(message);
+ }
+}
diff --git a/code/Interpreter2/src/Interpreter/Parser.java b/code/Interpreter2/src/Interpreter/Parser.java
new file mode 100644
index 0000000..6b55299
--- /dev/null
+++ b/code/Interpreter2/src/Interpreter/Parser.java
@@ -0,0 +1,179 @@
+package Interpreter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Parser {
+ private final List<Token> tokens;
+ private int currentToken = 0;
+
+ Parser(List<Token> tokens){
+ this.tokens=tokens;
+ }
+
+ List<Statement> parse(){
+ List<Statement> statements = new ArrayList<>();
+ while (!checkEOF()){
+ statements.add(declaration());
+ }
+ return statements;
+
+ }
+
+ private Statement declaration(){
+ try{
+ if (matchAndAdvance(TokenType.VAR)){
+ if (matchOrError(TokenType.DEFINE, ":: Required for variable definition")){
+ if (matchOrError(TokenType.IDENTIFIER,"Expected variable name.")){
+ Token varName = getPreviousToken();
+ return new Statement.VariableDeclaration(varName);
+ }
+ }
+ }
+ return statement();
+ } catch (Error e){
+ currentToken++;
+ return null;
+ }
+ }
+
+ private Statement statement(){
+ if (matchAndAdvance(TokenType.PRINT)){
+ Expression expression = expression();
+ return new Statement.PrintStatement(expression);
+ }
+ return expressionStatement();
+ }
+
+
+
+ private Statement expressionStatement(){
+ Expression expression = assignment();
+ return new Statement.ExpressionStatement(expression);
+ }
+
+ private Expression assignment(){
+ Expression variable = expression();
+ if (matchAndAdvance(TokenType.EQUALS)){
+ Expression assignedvalue = expression();
+
+ if (variable instanceof Expression.Variable){
+ return new Expression.AssignmentExpression(((Expression.Variable)variable).name,assignedvalue);
+ }
+ throw error("Incorrect assignment operation");
+ }
+ return variable;
+ }
+
+ private Expression expression(){
+ Expression createdExpression = equality();
+ return createdExpression;
+ }
+
+ private Expression equality(){
+ Expression createdExpression = comparison();
+ while (matchAndAdvance(TokenType.EQUALITY)){
+ Token op = getPreviousToken();
+ Expression right = comparison();
+ createdExpression = new Expression.Binary(createdExpression, op, right);
+ }
+ return createdExpression;
+ }
+
+ private Expression comparison(){
+ Expression createdExpression = term();
+ while (matchAndAdvance(TokenType.GREATER)||matchAndAdvance(TokenType.LESS)){
+ Token op = getPreviousToken();
+ Expression right = term();
+ createdExpression = new Expression.Binary(createdExpression, op, right);
+ }
+ return createdExpression;
+ }
+
+ private Expression term(){
+ Expression createdExpression = factor();
+ while (matchAndAdvance(TokenType.PLUS)||matchAndAdvance(TokenType.MINUS)){
+ Token op = getPreviousToken();
+ Expression right = factor();
+ createdExpression = new Expression.Binary(createdExpression, op, right);
+ }
+ return createdExpression;
+ }
+
+ private Expression factor(){
+ Expression createdExpression = primary();
+ while (matchAndAdvance(TokenType.STAR)||matchAndAdvance(TokenType.SLASH)){
+ Token op = getPreviousToken();
+ Expression right = primary();
+ createdExpression = new Expression.Binary(createdExpression, op, right);
+ }
+ return createdExpression;
+ }
+
+ private Expression primary(){
+ if (matchAndAdvance(TokenType.NUMBER)){
+ return new Expression.Literal(getPreviousToken());
+ }
+
+ if (matchAndAdvance(TokenType.IDENTIFIER)) {
+
+ return new Expression.Variable(getPreviousToken());
+ }
+
+ if (matchAndAdvance(TokenType.LEFT_PAREN)){
+ Expression expr = expression();
+ if (matchAndAdvance(TokenType.RIGHT_PAREN)){
+ return new Expression.BracketedExpression(expr);
+ }
+ else{
+ throw error("Expected ')");
+ }
+ }
+ throw error("Expected Expression");
+ }
+
+ private void advanceToken(){
+ if (!checkEOF()) {
+ currentToken++;
+ };
+ }
+
+ private boolean matchAndAdvance(TokenType type){
+ if (checkToken(type)) {
+ advanceToken();
+ return true;
+ }
+ return false;
+ }
+
+ private boolean matchOrError(TokenType type,String errorMessage){
+ if (matchAndAdvance(type)){
+ return true;
+ }
+ throw error(errorMessage);
+ }
+
+ private boolean checkToken(TokenType type){
+ if (checkEOF()) return false;
+ return getCurrentToken().type == type;
+ }
+
+ private boolean checkEOF(){
+ return tokens.get(currentToken).type==TokenType.EOF;
+ }
+
+ private Token getCurrentToken(){
+ return tokens.get(currentToken);
+ }
+
+ private Token getPreviousToken(){
+ return tokens.get(currentToken - 1);
+ }
+
+ private Error error(String message){
+ Language.displayError(message);
+ return new Error();
+ }
+
+
+}
diff --git a/code/Interpreter2/src/Interpreter/Statement.java b/code/Interpreter2/src/Interpreter/Statement.java
new file mode 100644
index 0000000..5a9aef7
--- /dev/null
+++ b/code/Interpreter2/src/Interpreter/Statement.java
@@ -0,0 +1,49 @@
+package Interpreter;
+
+abstract class Statement {
+
+ static class ExpressionStatement extends Statement{
+ ExpressionStatement(Expression expr){
+ this.expr = expr;
+ }
+
+
+ final Expression expr;
+
+ @Override
+ public String getStatmentType() {
+ return "exprStmt";
+ }
+ }
+
+
+ static class VariableDeclaration extends Statement{
+ VariableDeclaration(Token name){
+ this.name=name;
+ }
+
+
+ final Token name;
+
+ @Override
+ public String getStatmentType() {
+ return "vardec";
+ }
+
+ }
+
+ static class PrintStatement extends Statement{
+ PrintStatement(Expression expr){
+ this.expr=expr;
+ }
+ final Expression expr;
+
+ @Override
+ public String getStatmentType() {
+ return "print";
+ }
+ }
+
+
+ public abstract String getStatmentType();
+}
diff --git a/code/Interpreter2/src/Interpreter/Token.java b/code/Interpreter2/src/Interpreter/Token.java
new file mode 100644
index 0000000..0129b78
--- /dev/null
+++ b/code/Interpreter2/src/Interpreter/Token.java
@@ -0,0 +1,23 @@
+package Interpreter;
+
+public class Token {
+
+
+ //Stores the token type, the actual text and the runtime object
+ public final TokenType type;
+ final String text;
+ final Object value;
+
+
+ Token(TokenType type, String text, Object value){
+ this.type=type;
+ this.text=text;
+ this.value=value;
+
+ }
+
+ @Override
+ public String toString() {
+ return type + " " + text + " " + value;
+ }
+}
diff --git a/code/Interpreter2/src/Interpreter/TokenScanner.java b/code/Interpreter2/src/Interpreter/TokenScanner.java
new file mode 100644
index 0000000..c9249a4
--- /dev/null
+++ b/code/Interpreter2/src/Interpreter/TokenScanner.java
@@ -0,0 +1,179 @@
+package Interpreter;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class TokenScanner {
+ private String sourceCode;
+ List<Token> tokens = new ArrayList<>();
+ private int tokenStart=0;
+ private int currentLoc=0;
+
+ //Extract tokens from the source code by reading character by character
+ List<Token> extractTokens(String sourceCode){
+ this.sourceCode=sourceCode;
+ while (!checkEOF()){
+ tokenStart=currentLoc;
+ readToken();
+ }
+ tokens.add(new Token(TokenType.EOF, "", null));
+ return tokens;
+ }
+
+ //Extract a single token
+ private void readToken(){
+ char checkChar = sourceCode.charAt(currentLoc);
+ switch(checkChar){
+
+ case ' ':break;
+ case '\n':break;
+ case '\r':break;
+ case '\t':
+ break;
+
+ case '(': createTokenNull(TokenType.LEFT_PAREN); break;
+ case ')': createTokenNull(TokenType.RIGHT_PAREN); break;
+ case '+': createTokenNull(TokenType.PLUS); break;
+ case '-': createTokenNull(TokenType.MINUS); break;
+ case '*': createTokenNull(TokenType.STAR); break;
+ case '/': createTokenNull(TokenType.SLASH); break;
+ case ';': createTokenNull(TokenType.SEMI_COLON); break;
+
+ //Some tokens are multiple characters long (==, <=) etc
+ //so need to check next char as well
+ case '=':
+ if (checkNextChar('=')){
+ createTokenNull(TokenType.EQUALITY);
+ break;
+ } else {
+ createTokenNull(TokenType.EQUALS);
+ break;
+ }
+ case ':':
+ if (checkNextChar(':')){
+ createTokenNull(TokenType.DEFINE);
+ break;
+ } else {
+ createTokenNull(TokenType.COLON);
+ break;
+ }
+ case '<':
+ if (checkNextChar('=')){
+ createTokenNull(TokenType.LESS_EQUAL);
+ break;
+ } else {
+ createTokenNull(TokenType.LESS);
+ break;
+ }
+ case '>':
+ if (checkNextChar('=')){
+ createTokenNull(TokenType.GREATER_EQUAL);
+ break;
+ } else {
+ createTokenNull(TokenType.GREATER);
+ break;
+ }
+ default:
+
+ //Check for numer
+ if (checkIsDigit(checkChar)){
+ while (checkIsDigit(lookAhead())){
+ currentLoc++;
+ }
+ //Check if number contains a decimal point
+ if (lookAhead()=='.' && checkIsDigit(lookTwoAhead())){
+ currentLoc++;
+ while (checkIsDigit(lookAhead())){
+ currentLoc++;
+ }
+ }
+ createToken(TokenType.NUMBER, Double.parseDouble(sourceCode.substring(tokenStart, currentLoc+1)));
+ }
+ else if (checkIsAlpha(checkChar)){
+ while (checkIsAlpha(lookAhead())){
+ currentLoc++;
+ }
+ String text = sourceCode.substring(tokenStart, currentLoc+1);
+ TokenType type = keywords.get(text);
+ if(type == null){
+ createToken(TokenType.IDENTIFIER, text);
+ } else{
+ createToken(type, text);
+ }
+
+ } else {
+ Language.displayError("Unexpected Character");
+ }
+ }
+ currentLoc++;
+
+ }
+
+ //Test for end of file
+ private boolean checkEOF(){
+ return currentLoc>=sourceCode.length();
+ }
+
+ //Create a token without a value
+ private void createTokenNull(TokenType type){
+ createToken(type, null);
+ }
+
+ //Create token
+ private void createToken(TokenType type, Object value){
+ String tokenText = sourceCode.substring(tokenStart, currentLoc+1);
+ tokens.add(new Token(type, tokenText, value));
+ }
+
+ //Check if the next char matches a given char
+ private boolean checkNextChar(char matchChar){
+ if (checkEOF()){
+ return false;
+ }
+ if (sourceCode.charAt(currentLoc+1)==matchChar){
+ currentLoc++;
+ return true;
+ }
+ return false;
+ }
+
+ //Look at the next char in the source code
+ private char lookAhead(){
+ if (currentLoc+1>=sourceCode.length()){
+ return ' ';
+
+ } else {
+ return sourceCode.charAt(currentLoc+1);
+ }
+ }
+
+ //Look 2 chars ahead in the source code
+ private char lookTwoAhead(){
+ if (currentLoc+2>=sourceCode.length()){
+ return ' ';
+
+ } else {
+ return sourceCode.charAt(currentLoc+2);
+ }
+ }
+
+ //Check if a given char is a digit
+ private boolean checkIsDigit(char checkChar){
+ return checkChar>='0' && checkChar<='9';
+ }
+
+ private boolean checkIsAlpha(char checkChar){
+ return ('a'<=checkChar && checkChar<='z')||
+ ('A'<=checkChar && checkChar<='Z');
+ }
+
+ private static final Map<String, TokenType> keywords;
+
+ static {
+ keywords = new HashMap<>();
+ keywords.put("var", TokenType.VAR);
+ keywords.put("print", TokenType.PRINT);
+ }
+}
diff --git a/code/Interpreter2/src/Interpreter/TokenType.java b/code/Interpreter2/src/Interpreter/TokenType.java
new file mode 100644
index 0000000..756fab6
--- /dev/null
+++ b/code/Interpreter2/src/Interpreter/TokenType.java
@@ -0,0 +1,17 @@
+package Interpreter;
+
+public enum TokenType {
+ EQUALS, LEFT_PAREN, RIGHT_PAREN,
+ PLUS, MINUS, SLASH, STAR, SEMI_COLON,
+ COLON,
+
+ EQUALITY, GREATER, LESS,
+ GREATER_EQUAL, LESS_EQUAL,
+ DEFINE,
+
+ NUMBER,IDENTIFIER,
+
+ VAR,PRINT,
+
+ EOF
+}