diff options
author | jwansek <eddie.atten.ea29@gmail.com> | 2021-11-22 18:46:42 +0000 |
---|---|---|
committer | jwansek <eddie.atten.ea29@gmail.com> | 2021-11-22 18:46:42 +0000 |
commit | de5022e778c12a8b91b905473f2f74bf7172eac3 (patch) | |
tree | 4f16f1cb0b6b75c0e8975bb77f432071684e57ed /src | |
parent | 6557b7b080abab676cc15774bb4b4428e776cd03 (diff) | |
parent | 424ac34886895756525fbf5ddd704976e2e7d7dc (diff) | |
download | esotericFORTRAN-de5022e778c12a8b91b905473f2f74bf7172eac3.tar.gz esotericFORTRAN-de5022e778c12a8b91b905473f2f74bf7172eac3.zip |
Merge branch 'main' of https://github.com/AlfieEagleton/EsotericProject into argparse
Diffstat (limited to 'src')
-rw-r--r-- | src/Compiler/Environment.java | 19 | ||||
-rw-r--r-- | src/Compiler/ExecuteC.java | 2 | ||||
-rw-r--r-- | src/Compiler/Expression.java | 17 | ||||
-rw-r--r-- | src/Compiler/Language.java | 11 | ||||
-rw-r--r-- | src/Compiler/Parser.java | 89 | ||||
-rw-r--r-- | src/Compiler/Token.java | 4 | ||||
-rw-r--r-- | src/Compiler/TokenScanner.java | 35 | ||||
-rw-r--r-- | src/Compiler/TokenType.java | 2 | ||||
-rw-r--r-- | src/Compiler/Translator.java | 42 | ||||
-rw-r--r-- | src/example.txt | 19 |
10 files changed, 164 insertions, 76 deletions
diff --git a/src/Compiler/Environment.java b/src/Compiler/Environment.java index 3ccf425..1bb0e88 100644 --- a/src/Compiler/Environment.java +++ b/src/Compiler/Environment.java @@ -12,21 +12,20 @@ public class Environment { } //Get a variable if it is defined, or report an error - public Object getVariable(String name){ - if(variableMap.containsKey(name)){ - return variableMap.get(name); + public Object getVariable(Token token){ + if(variableMap.containsKey(token.text)){ + return variableMap.get(token.text); } - Language.displayError("Undefined Variable"); + Language.displayError(token,"Undefined Variable"); throw new Error(); } - //Assign a value to an existing variable - public void assignVariable(String name,Object value){ - if(variableMap.containsKey(name)){ - variableMap.put(name, value); - return; + //Get a variable if it is defined, or report an error + public Boolean checkVariable(Token token){ + if(variableMap.containsKey(token.text)){ + return true; } - Language.displayError("Variable undefined"); + Language.displayError(token,"Undefined Variable"); throw new Error(); } } diff --git a/src/Compiler/ExecuteC.java b/src/Compiler/ExecuteC.java index dd26e3c..fbc7ade 100644 --- a/src/Compiler/ExecuteC.java +++ b/src/Compiler/ExecuteC.java @@ -40,7 +40,7 @@ public class ExecuteC { System.out.println(output); } } else { - Language.displayError("Runtime Error"); + Language.displayError(0, "Runtime Error"); } if (!leaveCFile) { cProgram.delete(); diff --git a/src/Compiler/Expression.java b/src/Compiler/Expression.java index 7605c8b..d331f24 100644 --- a/src/Compiler/Expression.java +++ b/src/Compiler/Expression.java @@ -20,6 +20,23 @@ abstract class Expression { } + static class Singular extends Expression{ + + final Expression right; + final Token op; + + Singular(Token op, Expression right){ + this.op=op; + this.right = right; + } + + @Override + public String getExpressionType() { + return "singular"; + } + + } + static class Literal extends Expression{ final Token value; final String type; diff --git a/src/Compiler/Language.java b/src/Compiler/Language.java index 7326d10..1d95555 100644 --- a/src/Compiler/Language.java +++ b/src/Compiler/Language.java @@ -113,9 +113,16 @@ public class Language { } //Basic error reporting - static void displayError(String message){ + static void displayError(int line,String message){ hadError=true; - System.out.println("An error was encountered"); + System.out.println("An error was encountered on line: "+line); + System.out.println(message); + } + //Basic error reporting + static void displayError(Token token,String message){ + hadError=true; + System.out.println("An error was encountered on line: "+token.line); + System.out.println("ERROR: "+token.text); System.out.println(message); } diff --git a/src/Compiler/Parser.java b/src/Compiler/Parser.java index 8bb8951..d0556e4 100644 --- a/src/Compiler/Parser.java +++ b/src/Compiler/Parser.java @@ -17,7 +17,7 @@ public class Parser { List<Statement> statements = new ArrayList<>(); try{ while (!checkEOF()){ - statements.add(declaration()); + statements.add(statement()); } }catch (Error e){ return null; @@ -26,6 +26,20 @@ public class Parser { } + private Statement statement(){ + if(checkToken(TokenType.INT)||checkToken(TokenType.REAL)||checkToken(TokenType.STRING)){ + return declaration(); + } + else if (matchAndAdvance(TokenType.PRINT)){ + return printStatement(); + }else if (matchAndAdvance(TokenType.IF)){ + return ifStatement(); + }else if (matchAndAdvance(TokenType.DO)){ + return doStatement(); + } + return expressionStatement(); + } + //Clean up and reduce code mess private Statement declaration(){ @@ -47,13 +61,13 @@ public class Parser { matchOrError(TokenType.EQUALS, "Length of string must be defined"); Expression length = expression(); if(!(length instanceof Expression.Literal)){ - throw error("String length must be a number"); + throw error(getCurrentToken(),"String length must be a number"); } if(!((Expression.Literal)length).type.equals("int")){ - throw error("String length must be a integer"); + throw error(getCurrentToken(),"String length must be a integer"); } if((int)((Expression.Literal)length).value.value<1){ - throw error("String length must be greater then 0"); + throw error(getCurrentToken(),"String length must be greater then 0"); } matchOrError(TokenType.RIGHT_PAREN, "Length of string must be defined"); @@ -62,30 +76,16 @@ public class Parser { Token varName = getPreviousToken(); return new Statement.StringDeclaration(varName,length); } - - return statement(); - } - - private Statement statement(){ - if (matchAndAdvance(TokenType.PRINT)){ - return printStatement(); - }else if (matchAndAdvance(TokenType.IF)){ - Statement statement = ifStatement(); - return statement; - }else if (matchAndAdvance(TokenType.DO)){ - Statement statement = doStatement(); - return statement; - } - return expressionStatement(); + return null; } private BlockStatement blockStatement(){ List<Statement> statements = new ArrayList<>(); while(!matchAndAdvance(TokenType.END)&&!checkToken(TokenType.ELSE)){ if(checkEOF()){ - throw error("end missing from block"); + throw error(getCurrentToken(),"end missing from block"); } - statements.add(declaration()); + statements.add(statement()); } return new Statement.BlockStatement(statements); } @@ -93,11 +93,10 @@ public class Parser { private Statement printStatement(){ matchOrError(TokenType.STAR, "Syntax, print *, item1, item2..."); List<Expression> exprList = new ArrayList<>(); - while(!matchAndAdvance(TokenType.ENDPRINT)){ + while(matchAndAdvance(TokenType.COMMA)){ if(checkEOF()){ - throw error("Missing close parentheses"); + throw error(getCurrentToken(),"reached end of file"); } - matchOrError(TokenType.COMMA, "Print items must be seperated by ,"); Expression expr = expression(); exprList.add(expr); } @@ -141,9 +140,9 @@ public class Parser { } private Statement whileStatement(){ - matchOrError(TokenType.LEFT_PAREN, " missing '("); + matchOrError(TokenType.LEFT_PAREN, " missing '(' for do statement condition"); Expression condition = expression(); - matchOrError(TokenType.RIGHT_PAREN, " missing ')"); + matchOrError(TokenType.RIGHT_PAREN, " missing ')' for do condition"); Statement.BlockStatement codeBlock = blockStatement(); matchOrError(TokenType.DO, "Do while statements end with do"); return new Statement.DoWhileStatement(condition,codeBlock); @@ -162,7 +161,7 @@ public class Parser { if (variable instanceof Expression.Variable){ return new Expression.AssignmentExpression(((Expression.Variable)variable).name,assignedvalue); } - throw error("Incorrect assignment operation"); + throw error(getCurrentToken(),"Left of assignment must be a variable"); } return variable; } @@ -173,9 +172,25 @@ public class Parser { } private Expression equality(){ - Expression createdExpression = comparison(); + Expression createdExpression = logical(); while (matchAndAdvance(TokenType.EQUALITY)){ Token op = getPreviousToken(); + Expression right = logical(); + createdExpression = new Expression.Binary(createdExpression, op, right); + } + return createdExpression; + } + + private Expression logical(){ + if(matchAndAdvance(TokenType.NOT)){ + Token op = getPreviousToken(); + Expression right = comparison(); + Expression createdExpression = new Expression.Singular(op, right); + return createdExpression; + } + Expression createdExpression = comparison(); + while (matchAndAdvance(TokenType.AND)||matchAndAdvance(TokenType.OR)){ + Token op = getPreviousToken(); Expression right = comparison(); createdExpression = new Expression.Binary(createdExpression, op, right); } @@ -184,7 +199,7 @@ public class Parser { private Expression comparison(){ Expression createdExpression = term(); - while (matchAndAdvance(TokenType.GREATER)||matchAndAdvance(TokenType.LESS)){ + while (matchAndAdvance(TokenType.GREATER)||matchAndAdvance(TokenType.LESS)||matchAndAdvance(TokenType.GREATER_EQUAL)||matchAndAdvance(TokenType.LESS_EQUAL)){ Token op = getPreviousToken(); Expression right = term(); createdExpression = new Expression.Binary(createdExpression, op, right); @@ -231,14 +246,10 @@ public class Parser { if (matchAndAdvance(TokenType.LEFT_PAREN)){ Expression expr = expression(); - if (matchAndAdvance(TokenType.RIGHT_PAREN)){ - return new Expression.BracketedExpression(expr); - } - else{ - throw error("Expected ')"); - } + matchOrError(TokenType.RIGHT_PAREN,"Expected ')'"); + return new Expression.BracketedExpression(expr); } - throw error("Expected Expression"); + throw error(getCurrentToken(),"Unknown syntax error"); } private void advanceToken(){ @@ -259,7 +270,7 @@ public class Parser { if (matchAndAdvance(type)){ return true; } - throw error(errorMessage); + throw error(getCurrentToken(),errorMessage); } private boolean checkToken(TokenType type){ @@ -279,8 +290,8 @@ public class Parser { return tokens.get(currentToken - 1); } - private Error error(String message){ - Language.displayError(message); + private Error error(Token token, String message){ + Language.displayError(token ,message); return new Error(); } diff --git a/src/Compiler/Token.java b/src/Compiler/Token.java index 4608a3d..0af2c34 100644 --- a/src/Compiler/Token.java +++ b/src/Compiler/Token.java @@ -7,12 +7,14 @@ public class Token { public final TokenType type; final String text; final Object value; + final int line; - Token(TokenType type, String text, Object value){ + Token(TokenType type, String text, Object value,int line){ this.type=type; this.text=text; this.value=value; + this.line=line; } diff --git a/src/Compiler/TokenScanner.java b/src/Compiler/TokenScanner.java index 49500c5..5f55119 100644 --- a/src/Compiler/TokenScanner.java +++ b/src/Compiler/TokenScanner.java @@ -10,6 +10,7 @@ public class TokenScanner { List<Token> tokens = new ArrayList<>(); private int tokenStart=0; private int currentLoc=0; + private int line=0; //Extract tokens from the source code by reading character by character List<Token> extractTokens(String sourceCode){ @@ -18,7 +19,7 @@ public class TokenScanner { tokenStart=currentLoc; readToken(); } - tokens.add(new Token(TokenType.EOF, "", null)); + tokens.add(new Token(TokenType.EOF, "", null,line)); return tokens; } @@ -28,7 +29,9 @@ public class TokenScanner { switch(checkChar){ case ' ':break; - case '\n':break; + case '\n': + line++; + break; case '\r':break; case '\t': break; @@ -81,12 +84,34 @@ public class TokenScanner { currentLoc++; } if(checkEOF()){ - Language.displayError("Strings must end with \""); + Language.displayError(line, "Strings must end with a closing \""); break; } currentLoc++; createToken(TokenType.STRING, sourceCode.substring(tokenStart, currentLoc+1)); break; + case '.': + if(checkIsAlpha(lookAhead())) + while (checkIsAlpha(lookAhead())){ + currentLoc++; + } + String logical = sourceCode.substring(tokenStart+1, currentLoc+1); + if (checkNextChar('.')){ + if (logical.equals("and")){ + createTokenNull(TokenType.AND); + break; + } else if(logical.equals("or")){ + createTokenNull(TokenType.OR); + break; + } else if(logical.equals("not")){ + createTokenNull(TokenType.NOT); + break; + } else{ + Language.displayError(line, "Expected logical expression"); + } + } else { + Language.displayError(line, "Expected '.' after logical expression"); + } default: //Check for numer @@ -122,7 +147,7 @@ public class TokenScanner { } } else { - Language.displayError("Unexpected Character"); + Language.displayError(line,"Unexpected Character"); } } currentLoc++; @@ -142,7 +167,7 @@ public class TokenScanner { //Create token private void createToken(TokenType type, Object value){ String tokenText = sourceCode.substring(tokenStart, currentLoc+1); - tokens.add(new Token(type, tokenText, value)); + tokens.add(new Token(type, tokenText, value, line)); } //Check if the next char matches a given char diff --git a/src/Compiler/TokenType.java b/src/Compiler/TokenType.java index 82776f9..a82d169 100644 --- a/src/Compiler/TokenType.java +++ b/src/Compiler/TokenType.java @@ -12,7 +12,7 @@ public enum TokenType { NUMBER,IDENTIFIER,STRING, - INT,REAL,PRINT,ENDPRINT,IF,THEN,END,ELSE,LEN,DO,WHILE, + INT,REAL,PRINT,ENDPRINT,IF,THEN,END,ELSE,LEN,DO,WHILE,AND,OR,NOT, EOF } diff --git a/src/Compiler/Translator.java b/src/Compiler/Translator.java index ee43905..c40c6b5 100644 --- a/src/Compiler/Translator.java +++ b/src/Compiler/Translator.java @@ -104,7 +104,7 @@ public class Translator{ exprType=((Expression.Literal)expr).type; } else if (expr instanceof Expression.Variable){ - exprType=(String)environment.getVariable((((Expression.Variable)expr).name).text); + exprType=(String)environment.getVariable((((Expression.Variable)expr).name)); } if (exprType.equals("int")){ types+="%d"; @@ -153,6 +153,8 @@ public class Translator{ switch(expression.getExpressionType()){ case "binary": return evaluateBinaryExpression((Binary)expression); + case "singular": + return evaluateSingularExpression((Singular)expression); case "literal": return evaluateLiteralExpression((Literal)expression); case "bracket": @@ -182,8 +184,27 @@ public class Translator{ return evaluateExpression(expr.left)+">"+evaluateExpression(expr.right); case LESS: return evaluateExpression(expr.left)+"<"+evaluateExpression(expr.right); + case GREATER_EQUAL: + return evaluateExpression(expr.left)+">="+evaluateExpression(expr.right); + case LESS_EQUAL: + return evaluateExpression(expr.left)+"<="+evaluateExpression(expr.right); case EQUALITY: return evaluateExpression(expr.left)+"=="+evaluateExpression(expr.right); + case AND: + return evaluateExpression(expr.left)+"&&"+evaluateExpression(expr.right); + case OR: + return evaluateExpression(expr.left)+"||"+evaluateExpression(expr.right); + + default: + break; + } + return null; + } + + private String evaluateSingularExpression(Singular expr){ + switch (expr.op.type){ + case NOT: + return "!"+evaluateExpression(expr.right); default: break; } @@ -195,18 +216,21 @@ public class Translator{ } private String evaluateBracketedExpression(BracketedExpression expr){ - return evaluateExpression(expr.expr); + return "("+evaluateExpression(expr.expr)+")"; } private void evaluateAssignmentExpression(AssignmentExpression expr){ - if(expr.value instanceof Expression.Literal){ - if(((Expression.Literal)expr.value).type.equals("string")){ - CCode.add("strcpy("+expr.name.text+","+evaluateExpression(expr.value)+");"); + if(environment.checkVariable(expr.name)){ + if(expr.value instanceof Expression.Literal){ + if(((Expression.Literal)expr.value).type.equals("string")){ + CCode.add("strcpy("+expr.name.text+","+evaluateExpression(expr.value)+");"); + }else{ + CCode.add(expr.name.text+"="+evaluateExpression(expr.value)+";"); + } + } + else{ + CCode.add(expr.name.text+"="+evaluateExpression(expr.value)+";"); } - CCode.add(expr.name.text+"="+evaluateExpression(expr.value)+";"); - } - else{ - CCode.add(expr.name.text+"="+evaluateExpression(expr.value)+";"); } } diff --git a/src/example.txt b/src/example.txt index bbc8973..55236c1 100644 --- a/src/example.txt +++ b/src/example.txt @@ -1,9 +1,12 @@ -int::nfact int::n -nfact=1 -n=1 -do while(n<10) -nfact=nfact*n -n=n+1 -print*,n," ", nfact endprint -end do
\ No newline at end of file +int::a +int::b +int::temp +a=0 +b=2 +if (a==0.and.b==1) then +print*,"true" +else +print*,"false" +end if + |