diff options
| author | Alfie Eagleton <67986414+TheAlfanator@users.noreply.github.com> | 2021-11-03 16:56:38 +0000 | 
|---|---|---|
| committer | Alfie Eagleton <67986414+TheAlfanator@users.noreply.github.com> | 2021-11-03 16:56:38 +0000 | 
| commit | 85345d7d80eeb950ab64633ae1cb1f1c5dc87269 (patch) | |
| tree | b353c985d4cdf51517a907efd9c6968a62db5655 /code/Interpreter2 | |
| parent | 85e2726ddedd2981425c5ac07f7257bce1a6ddbf (diff) | |
| download | esotericFORTRAN-85345d7d80eeb950ab64633ae1cb1f1c5dc87269.tar.gz esotericFORTRAN-85345d7d80eeb950ab64633ae1cb1f1c5dc87269.zip | |
New Project Working + Report
Diffstat (limited to 'code/Interpreter2')
| -rw-r--r-- | code/Interpreter2/.idea/misc.xml | 6 | ||||
| -rw-r--r-- | code/Interpreter2/.idea/modules.xml | 8 | ||||
| -rw-r--r-- | code/Interpreter2/.idea/uiDesigner.xml | 124 | ||||
| -rw-r--r-- | code/Interpreter2/.idea/vcs.xml | 6 | ||||
| -rw-r--r-- | code/Interpreter2/.idea/workspace.xml | 52 | ||||
| -rw-r--r-- | code/Interpreter2/Interpreter2.iml | 11 | ||||
| -rw-r--r-- | code/Interpreter2/src/Interpreter/Environment.java | 30 | ||||
| -rw-r--r-- | code/Interpreter2/src/Interpreter/Expression.java | 84 | ||||
| -rw-r--r-- | code/Interpreter2/src/Interpreter/Interpreter.java | 131 | ||||
| -rw-r--r-- | code/Interpreter2/src/Interpreter/Language.java | 63 | ||||
| -rw-r--r-- | code/Interpreter2/src/Interpreter/Parser.java | 179 | ||||
| -rw-r--r-- | code/Interpreter2/src/Interpreter/Statement.java | 49 | ||||
| -rw-r--r-- | code/Interpreter2/src/Interpreter/Token.java | 23 | ||||
| -rw-r--r-- | code/Interpreter2/src/Interpreter/TokenScanner.java | 179 | ||||
| -rw-r--r-- | code/Interpreter2/src/Interpreter/TokenType.java | 17 | 
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 +} | 
