From 0c54d7f8cb4b17d80ed21f7a9916ad27a13e34ed Mon Sep 17 00:00:00 2001 From: AidenRushbrooke <72034940+AidenRushbrooke@users.noreply.github.com> Date: Sat, 6 Nov 2021 01:44:14 +0000 Subject: Re-arranged files and added C compilation --- code/Interpreter/.idea/misc.xml | 6 - code/Interpreter/.idea/modules.xml | 8 - code/Interpreter/.idea/uiDesigner.xml | 124 -------------- code/Interpreter/.idea/vcs.xml | 6 - code/Interpreter/.idea/workspace.xml | 100 ------------ code/Interpreter/Environment.java | 30 ---- code/Interpreter/Expression.java | 84 ---------- code/Interpreter/Interpreter.java | 131 --------------- code/Interpreter/Interpreter/.idea/misc.xml | 6 - code/Interpreter/Interpreter/.idea/modules.xml | 8 - code/Interpreter/Interpreter/.idea/uiDesigner.xml | 124 -------------- code/Interpreter/Interpreter/.idea/vcs.xml | 6 - code/Interpreter/Interpreter/.idea/workspace.xml | 34 ---- .../Interpreter/Interpreter/Interpreter.iml | 11 -- code/Interpreter/Language.java | 63 -------- code/Interpreter/Parser.java | 179 --------------------- code/Interpreter/Statement.java | 49 ------ code/Interpreter/Token.java | 23 --- code/Interpreter/TokenScanner.java | 179 --------------------- code/Interpreter/TokenType.java | 17 -- code/example.txt | 12 -- src/.vscode/launch.json | 22 +++ src/Compiler/Environment.java | 29 ++++ src/Compiler/ExecuteC.java | 76 +++++++++ src/Compiler/Expression.java | 84 ++++++++++ src/Compiler/Language.java | 66 ++++++++ src/Compiler/Parser.java | 179 +++++++++++++++++++++ src/Compiler/Statement.java | 49 ++++++ src/Compiler/Token.java | 23 +++ src/Compiler/TokenScanner.java | 179 +++++++++++++++++++++ src/Compiler/TokenType.java | 17 ++ src/Compiler/Translator.java | 123 ++++++++++++++ src/example.txt | 4 + src/main.c | 7 + src/main.exe | Bin 0 -> 297288 bytes 35 files changed, 858 insertions(+), 1200 deletions(-) delete mode 100644 code/Interpreter/.idea/misc.xml delete mode 100644 code/Interpreter/.idea/modules.xml delete mode 100644 code/Interpreter/.idea/uiDesigner.xml delete mode 100644 code/Interpreter/.idea/vcs.xml delete mode 100644 code/Interpreter/.idea/workspace.xml delete mode 100644 code/Interpreter/Environment.java delete mode 100644 code/Interpreter/Expression.java delete mode 100644 code/Interpreter/Interpreter.java delete mode 100644 code/Interpreter/Interpreter/.idea/misc.xml delete mode 100644 code/Interpreter/Interpreter/.idea/modules.xml delete mode 100644 code/Interpreter/Interpreter/.idea/uiDesigner.xml delete mode 100644 code/Interpreter/Interpreter/.idea/vcs.xml delete mode 100644 code/Interpreter/Interpreter/.idea/workspace.xml delete mode 100644 code/Interpreter/Interpreter/Interpreter/Interpreter.iml delete mode 100644 code/Interpreter/Language.java delete mode 100644 code/Interpreter/Parser.java delete mode 100644 code/Interpreter/Statement.java delete mode 100644 code/Interpreter/Token.java delete mode 100644 code/Interpreter/TokenScanner.java delete mode 100644 code/Interpreter/TokenType.java delete mode 100644 code/example.txt create mode 100644 src/.vscode/launch.json create mode 100644 src/Compiler/Environment.java create mode 100644 src/Compiler/ExecuteC.java create mode 100644 src/Compiler/Expression.java create mode 100644 src/Compiler/Language.java create mode 100644 src/Compiler/Parser.java create mode 100644 src/Compiler/Statement.java create mode 100644 src/Compiler/Token.java create mode 100644 src/Compiler/TokenScanner.java create mode 100644 src/Compiler/TokenType.java create mode 100644 src/Compiler/Translator.java create mode 100644 src/example.txt create mode 100644 src/main.c create mode 100644 src/main.exe diff --git a/code/Interpreter/.idea/misc.xml b/code/Interpreter/.idea/misc.xml deleted file mode 100644 index 06e4882..0000000 --- a/code/Interpreter/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/code/Interpreter/.idea/modules.xml b/code/Interpreter/.idea/modules.xml deleted file mode 100644 index b0b7e77..0000000 --- a/code/Interpreter/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/code/Interpreter/.idea/uiDesigner.xml b/code/Interpreter/.idea/uiDesigner.xml deleted file mode 100644 index e96534f..0000000 --- a/code/Interpreter/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/code/Interpreter/.idea/vcs.xml b/code/Interpreter/.idea/vcs.xml deleted file mode 100644 index b2bdec2..0000000 --- a/code/Interpreter/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/code/Interpreter/.idea/workspace.xml b/code/Interpreter/.idea/workspace.xml deleted file mode 100644 index bd535b9..0000000 --- a/code/Interpreter/.idea/workspace.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1635957051799 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/code/Interpreter/Environment.java b/code/Interpreter/Environment.java deleted file mode 100644 index d191bde..0000000 --- a/code/Interpreter/Environment.java +++ /dev/null @@ -1,30 +0,0 @@ -package Interpreter; - -import java.util.HashMap; -import java.util.Map; - -public class Environment { - private final Map 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/Interpreter/Expression.java b/code/Interpreter/Expression.java deleted file mode 100644 index 85ade48..0000000 --- a/code/Interpreter/Expression.java +++ /dev/null @@ -1,84 +0,0 @@ -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/Interpreter/Interpreter.java b/code/Interpreter/Interpreter.java deleted file mode 100644 index 65cdeb4..0000000 --- a/code/Interpreter/Interpreter.java +++ /dev/null @@ -1,131 +0,0 @@ -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 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/Interpreter/Interpreter/.idea/misc.xml b/code/Interpreter/Interpreter/.idea/misc.xml deleted file mode 100644 index 40674af..0000000 --- a/code/Interpreter/Interpreter/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/code/Interpreter/Interpreter/.idea/modules.xml b/code/Interpreter/Interpreter/.idea/modules.xml deleted file mode 100644 index bbaf613..0000000 --- a/code/Interpreter/Interpreter/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/code/Interpreter/Interpreter/.idea/uiDesigner.xml b/code/Interpreter/Interpreter/.idea/uiDesigner.xml deleted file mode 100644 index e96534f..0000000 --- a/code/Interpreter/Interpreter/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/code/Interpreter/Interpreter/.idea/vcs.xml b/code/Interpreter/Interpreter/.idea/vcs.xml deleted file mode 100644 index b2bdec2..0000000 --- a/code/Interpreter/Interpreter/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/code/Interpreter/Interpreter/.idea/workspace.xml b/code/Interpreter/Interpreter/.idea/workspace.xml deleted file mode 100644 index c4f325d..0000000 --- a/code/Interpreter/Interpreter/.idea/workspace.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - 1635957051799 - - - - \ No newline at end of file diff --git a/code/Interpreter/Interpreter/Interpreter/Interpreter.iml b/code/Interpreter/Interpreter/Interpreter/Interpreter.iml deleted file mode 100644 index b107a2d..0000000 --- a/code/Interpreter/Interpreter/Interpreter/Interpreter.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/code/Interpreter/Language.java b/code/Interpreter/Language.java deleted file mode 100644 index 80aa1e3..0000000 --- a/code/Interpreter/Language.java +++ /dev/null @@ -1,63 +0,0 @@ -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 tokens = scanner.extractTokens(sourceCode); - //for (Token token : tokens) { - // System.out.println(token); - //} - if (hadError) return; - //Parse into AST - Parser parser = new Parser(tokens); - List 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/Interpreter/Parser.java b/code/Interpreter/Parser.java deleted file mode 100644 index 6b55299..0000000 --- a/code/Interpreter/Parser.java +++ /dev/null @@ -1,179 +0,0 @@ -package Interpreter; - -import java.util.ArrayList; -import java.util.List; - -public class Parser { - private final List tokens; - private int currentToken = 0; - - Parser(List tokens){ - this.tokens=tokens; - } - - List parse(){ - List 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/Interpreter/Statement.java b/code/Interpreter/Statement.java deleted file mode 100644 index 5a9aef7..0000000 --- a/code/Interpreter/Statement.java +++ /dev/null @@ -1,49 +0,0 @@ -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/Interpreter/Token.java b/code/Interpreter/Token.java deleted file mode 100644 index 0129b78..0000000 --- a/code/Interpreter/Token.java +++ /dev/null @@ -1,23 +0,0 @@ -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/Interpreter/TokenScanner.java b/code/Interpreter/TokenScanner.java deleted file mode 100644 index c9249a4..0000000 --- a/code/Interpreter/TokenScanner.java +++ /dev/null @@ -1,179 +0,0 @@ -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 tokens = new ArrayList<>(); - private int tokenStart=0; - private int currentLoc=0; - - //Extract tokens from the source code by reading character by character - List 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 keywords; - - static { - keywords = new HashMap<>(); - keywords.put("var", TokenType.VAR); - keywords.put("print", TokenType.PRINT); - } -} diff --git a/code/Interpreter/TokenType.java b/code/Interpreter/TokenType.java deleted file mode 100644 index 756fab6..0000000 --- a/code/Interpreter/TokenType.java +++ /dev/null @@ -1,17 +0,0 @@ -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 -} diff --git a/code/example.txt b/code/example.txt deleted file mode 100644 index cf6adc8..0000000 --- a/code/example.txt +++ /dev/null @@ -1,12 +0,0 @@ -var :: a -a=5 -a=a+1 -print a - -a=7 -a=a*2 -print a - -var :: b -b = 10 -print a+b \ No newline at end of file diff --git a/src/.vscode/launch.json b/src/.vscode/launch.json new file mode 100644 index 0000000..a4b8347 --- /dev/null +++ b/src/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Launch Current File", + "request": "launch", + "mainClass": "${file}" + }, + { + "type": "java", + "name": "Launch Language", + "request": "launch", + "mainClass": "Compiler.Language", + "projectName": "src_1da2a030", + "args":"example.txt" + } + ] +} \ No newline at end of file diff --git a/src/Compiler/Environment.java b/src/Compiler/Environment.java new file mode 100644 index 0000000..0e682a4 --- /dev/null +++ b/src/Compiler/Environment.java @@ -0,0 +1,29 @@ +package Compiler; +import java.util.HashMap; +import java.util.Map; + +public class Environment { + private final Map 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/src/Compiler/ExecuteC.java b/src/Compiler/ExecuteC.java new file mode 100644 index 0000000..5e32eea --- /dev/null +++ b/src/Compiler/ExecuteC.java @@ -0,0 +1,76 @@ +package Compiler; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; + + +public class ExecuteC { + public void compileAndExecuteC(List code){ + writeProgram(code); + if (!compileC()){ + String output = runProgram(); + System.out.println(output); + } + else{ + Language.displayError("Runtime Error"); + } + } + + public void writeProgram(List codeLines){ + BufferedWriter output = null; + try { + File file = new File("main.c"); + output = new BufferedWriter(new FileWriter(file)); + for(String line:codeLines){ + output.write(line+"\n"); + } + output.close(); + } catch ( IOException e ) { + e.printStackTrace(); + } + + } + + public Boolean compileC(){ + try{ + String s= null; + Process p = Runtime.getRuntime().exec("cmd /C gcc main.c -o main.exe"); + BufferedReader stdError = new BufferedReader(new + InputStreamReader(p.getErrorStream())); + boolean error=false; + while ((s = stdError.readLine()) != null) { + error=true; + } + return error; + } catch (IOException e){ + e.printStackTrace(); + } + return false; + } + + public String runProgram(){ + + try{ + String[] command = {"cmd", "/C", "main.exe"}; + ProcessBuilder probuilder = new ProcessBuilder(command); + Process p = probuilder.start(); + BufferedReader stdInput = new BufferedReader(new + InputStreamReader(p.getInputStream())); + + String s = null; + String output=""; + while ((s = stdInput.readLine()) != null) { + output+=s; + } + return output; + } catch (IOException e){ + e.printStackTrace(); + } + return null; + } +} diff --git a/src/Compiler/Expression.java b/src/Compiler/Expression.java new file mode 100644 index 0000000..63ed7f2 --- /dev/null +++ b/src/Compiler/Expression.java @@ -0,0 +1,84 @@ +package Compiler; + +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/src/Compiler/Language.java b/src/Compiler/Language.java new file mode 100644 index 0000000..9151bd5 --- /dev/null +++ b/src/Compiler/Language.java @@ -0,0 +1,66 @@ +package Compiler; + +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 tokens = scanner.extractTokens(sourceCode); + //for (Token token : tokens) { + // System.out.println(token); + //} + if (hadError) return; + //Parse into AST + Parser parser = new Parser(tokens); + List ast = parser.parse(); + if (hadError) return; + Translator translator = new Translator(); + List code = translator.compileToC(ast); + if (hadError) return; + ExecuteC cExecutor = new ExecuteC(); + cExecutor.compileAndExecuteC(code); + } + + static void displayError(String message){ + hadError=true; + System.out.println("An error was encountered"); + System.out.println(message); + } +} diff --git a/src/Compiler/Parser.java b/src/Compiler/Parser.java new file mode 100644 index 0000000..4339fd4 --- /dev/null +++ b/src/Compiler/Parser.java @@ -0,0 +1,179 @@ +package Compiler; + +import java.util.ArrayList; +import java.util.List; + +public class Parser { + private final List tokens; + private int currentToken = 0; + + Parser(List tokens){ + this.tokens=tokens; + } + + List parse(){ + List 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/src/Compiler/Statement.java b/src/Compiler/Statement.java new file mode 100644 index 0000000..885e462 --- /dev/null +++ b/src/Compiler/Statement.java @@ -0,0 +1,49 @@ +package Compiler; + +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/src/Compiler/Token.java b/src/Compiler/Token.java new file mode 100644 index 0000000..4608a3d --- /dev/null +++ b/src/Compiler/Token.java @@ -0,0 +1,23 @@ +package Compiler; + +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/src/Compiler/TokenScanner.java b/src/Compiler/TokenScanner.java new file mode 100644 index 0000000..f00f7b0 --- /dev/null +++ b/src/Compiler/TokenScanner.java @@ -0,0 +1,179 @@ +package Compiler; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class TokenScanner { + private String sourceCode; + List tokens = new ArrayList<>(); + private int tokenStart=0; + private int currentLoc=0; + + //Extract tokens from the source code by reading character by character + List 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 keywords; + + static { + keywords = new HashMap<>(); + keywords.put("var", TokenType.VAR); + keywords.put("print", TokenType.PRINT); + } +} diff --git a/src/Compiler/TokenType.java b/src/Compiler/TokenType.java new file mode 100644 index 0000000..83ce6cc --- /dev/null +++ b/src/Compiler/TokenType.java @@ -0,0 +1,17 @@ +package Compiler; + +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 +} diff --git a/src/Compiler/Translator.java b/src/Compiler/Translator.java new file mode 100644 index 0000000..b62df63 --- /dev/null +++ b/src/Compiler/Translator.java @@ -0,0 +1,123 @@ +package Compiler; + +import java.util.ArrayList; +import java.util.List; + +import Compiler.Expression.*; +import Compiler.Statement.*; + + +public class Translator{ + + List CCode = new ArrayList<>(); + private Environment environment = new Environment(); + + + public List compileToC(List statements){ + CCode.add("#include "); + CCode.add("int main(){"); + try{ + for (Statement statement: statements){ + evaluateStatement(statement); + } + } catch (Error e){ + + } + CCode.add("}"); + + for(String t:CCode){ + System.out.println(t); + } + System.out.println(""); + return CCode; + } + + private void evaluateStatement(Statement statement){ + switch(statement.getStatmentType()){ + case "exprStmt": + evalExpressionStatement((ExpressionStatement)statement); + break; + case "vardec": + evalVariableDeclaration((VariableDeclaration)statement); + break; + case "print": + evalPrintStatement((PrintStatement)statement); + break; + } + } + private void evalExpressionStatement(ExpressionStatement stmt){ + evaluateExpression(stmt.expr); + } + + private void evalVariableDeclaration(VariableDeclaration vardec){ + environment.defineVariable(vardec.name.text, null); + CCode.add("int "+vardec.name.text+";"); + } + + private void evalPrintStatement(PrintStatement print){ + CCode.add("printf(\"%d\","+evaluateExpression(print.expr)+");"); + } + + private String 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": + evaluateAssignmentExpression((AssignmentExpression)expression); + return ""; + case "var": + return evaluateVariableExpression((Variable)expression); + default: + return null; + } + } + + private String evaluateBinaryExpression(Binary expr){ + switch (expr.op.type){ + case PLUS: + //return "leftEval+rightEval" + return evaluateExpression(expr.left)+"+"+evaluateExpression(expr.right); + case STAR: + return evaluateExpression(expr.left)+"*"+evaluateExpression(expr.right); + case MINUS: + return evaluateExpression(expr.left)+"-"+evaluateExpression(expr.right); + case SLASH: + return evaluateExpression(expr.left)+"/"+evaluateExpression(expr.right); + case GREATER: + return evaluateExpression(expr.left)+">"+evaluateExpression(expr.right); + case LESS: + return evaluateExpression(expr.left)+"<"+evaluateExpression(expr.right); + case EQUALITY: + return evaluateExpression(expr.left)+"=="+evaluateExpression(expr.right); + default: + break; + } + return null; + } + + private String evaluateLiteralExpression(Literal expr){ + return (expr.value.value).toString(); + } + + private String evaluateBracketedExpression(BracketedExpression expr){ + return evaluateExpression(expr.expr); + } + + private void evaluateAssignmentExpression(AssignmentExpression expr){ + Object assignedValue = evaluateExpression(expr.value); + environment.assignVariable(expr.name.text, assignedValue); + CCode.add(expr.name.text+"="+evaluateExpression(expr.value)+";"); + } + + private String evaluateVariableExpression(Variable expr){ + return expr.name.text; + } + + +} + + diff --git a/src/example.txt b/src/example.txt new file mode 100644 index 0000000..a9202e5 --- /dev/null +++ b/src/example.txt @@ -0,0 +1,4 @@ +var :: a +a=5 +a=a+1 +print a diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..0403b49 --- /dev/null +++ b/src/main.c @@ -0,0 +1,7 @@ +#include +int main(){ +int a; +a=5.0; +a=a+1.0; +printf("%d",a); +} diff --git a/src/main.exe b/src/main.exe new file mode 100644 index 0000000..dbfd6ba Binary files /dev/null and b/src/main.exe differ -- cgit v1.2.3