diff options
author | AidenRushbrooke <72034940+AidenRushbrooke@users.noreply.github.com> | 2021-11-07 22:35:33 +0000 |
---|---|---|
committer | AidenRushbrooke <72034940+AidenRushbrooke@users.noreply.github.com> | 2021-11-07 22:35:33 +0000 |
commit | 975fb6f000918085d1f5ba4ac6eb95c60411dae9 (patch) | |
tree | 8dab2d0447e9e2dca9dc1b06d42d5331d55c4547 /src | |
parent | f8b888716211b78900db62ede497fa4ac2100c00 (diff) | |
download | esotericFORTRAN-975fb6f000918085d1f5ba4ac6eb95c60411dae9.tar.gz esotericFORTRAN-975fb6f000918085d1f5ba4ac6eb95c60411dae9.zip |
Added support for strings and improved print statement syntax
Diffstat (limited to 'src')
-rw-r--r-- | src/.vscode/settings.json | 3 | ||||
-rw-r--r-- | src/.vscode/tasks.json | 68 | ||||
-rw-r--r-- | src/Compiler/Parser.java | 60 | ||||
-rw-r--r-- | src/Compiler/Statement.java | 25 | ||||
-rw-r--r-- | src/Compiler/TokenScanner.java | 15 | ||||
-rw-r--r-- | src/Compiler/TokenType.java | 6 | ||||
-rw-r--r-- | src/Compiler/Translator.java | 61 | ||||
-rw-r--r-- | src/example.txt | 10 | ||||
-rw-r--r-- | src/main.c | 11 | ||||
-rw-r--r-- | src/main.exe | bin | 297800 -> 297288 bytes |
10 files changed, 213 insertions, 46 deletions
diff --git a/src/.vscode/settings.json b/src/.vscode/settings.json new file mode 100644 index 0000000..bf562e6 --- /dev/null +++ b/src/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "C_Cpp.errorSquiggles": "Enabled" +}
\ No newline at end of file diff --git a/src/.vscode/tasks.json b/src/.vscode/tasks.json new file mode 100644 index 0000000..4f00211 --- /dev/null +++ b/src/.vscode/tasks.json @@ -0,0 +1,68 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: gcc.exe build active file", + "command": "C:\\msys64\\mingw64\\bin\\gcc.exe", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}\\${fileBasenameNoExtension}.exe" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": "build", + "detail": "Task generated by Debugger." + }, + { + "type": "cppbuild", + "label": "C/C++: gcc.exe build active file ver(1)", + "command": "C:\\msys64\\mingw64\\bin\\gcc.exe", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}\\${fileBasenameNoExtension}.exe" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": "build", + "detail": "Task generated by Debugger." + }, + { + "type": "cppbuild", + "label": "C/C++: gcc.exe build active file ver(2)", + "command": "C:\\msys64\\mingw64\\bin\\gcc.exe", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}\\${fileBasenameNoExtension}.exe" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "Task generated by Debugger." + } + ], + "version": "2.0.0" +}
\ No newline at end of file diff --git a/src/Compiler/Parser.java b/src/Compiler/Parser.java index 68851bf..7eb22df 100644 --- a/src/Compiler/Parser.java +++ b/src/Compiler/Parser.java @@ -28,19 +28,37 @@ public class Parser { //Clean up and reduce code mess private Statement declaration(){ if (matchAndAdvance(TokenType.INT)){ - if (matchOrError(TokenType.DEFINE, ":: Required for variable definition")){ - if (matchOrError(TokenType.IDENTIFIER,"Expected variable name.")){ - Token varName = getPreviousToken(); - return new Statement.VariableDeclaration(varName,"int"); - } - } + matchOrError(TokenType.DEFINE, ":: Required for variable definition"); + matchOrError(TokenType.IDENTIFIER,"Expected variable name."); + Token varName = getPreviousToken(); + return new Statement.VariableDeclaration(varName,"int"); } else if (matchAndAdvance(TokenType.REAL)){ - if (matchOrError(TokenType.DEFINE, ":: Required for variable definition")){ - if (matchOrError(TokenType.IDENTIFIER,"Expected variable name.")){ - Token varName = getPreviousToken(); - return new Statement.VariableDeclaration(varName,"real"); - } + matchOrError(TokenType.DEFINE, ":: Required for variable definition"); + matchOrError(TokenType.IDENTIFIER,"Expected variable name."); + Token varName = getPreviousToken(); + return new Statement.VariableDeclaration(varName,"real"); + + //Could be improved significatly when verifiying length is a positive integer + } else if (matchAndAdvance(TokenType.STRING)){ + matchOrError(TokenType.LEFT_PAREN, "Length of string must be defined"); + matchOrError(TokenType.LEN, "Length of string must be defined"); + 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"); + } + if(!((Expression.Literal)length).type.equals("int")){ + throw error("String length must be a integer"); } + if((int)((Expression.Literal)length).value.value<1){ + throw error("String length must be greater then 0"); + } + matchOrError(TokenType.RIGHT_PAREN, "Length of string must be defined"); + + matchOrError(TokenType.DEFINE, ":: Required for variable definition"); + matchOrError(TokenType.IDENTIFIER,"Expected variable name."); + Token varName = getPreviousToken(); + return new Statement.StringDeclaration(varName,length); } return statement(); @@ -48,8 +66,7 @@ public class Parser { private Statement statement(){ if (matchAndAdvance(TokenType.PRINT)){ - Expression expression = expression(); - return new Statement.PrintStatement(expression); + return printStatement(); }else if (matchAndAdvance(TokenType.IF)){ Statement statement = ifStatement(); return statement; @@ -57,6 +74,20 @@ public class Parser { return expressionStatement(); } + private Statement printStatement(){ + matchOrError(TokenType.STAR, "Syntax, print *, item1, item2..."); + List<Expression> exprList = new ArrayList<>(); + while(!matchAndAdvance(TokenType.ENDPRINT)){ + if(checkEOF()){ + throw error("Missing close parentheses"); + } + matchOrError(TokenType.COMMA, "Print items must be seperated by ,"); + Expression expr = expression(); + exprList.add(expr); + } + return new Statement.PrintStatement(exprList); + } + //Could be cleaned up to handle else statements better private Statement ifStatement(){ Expression condition = expression(); @@ -155,6 +186,9 @@ public class Parser { return new Expression.Literal(getPreviousToken(),"double"); } } + if (matchAndAdvance(TokenType.STRING)){ + return new Expression.Literal(getPreviousToken(), "string"); + } if (matchAndAdvance(TokenType.IDENTIFIER)) { diff --git a/src/Compiler/Statement.java b/src/Compiler/Statement.java index a74009d..b8916aa 100644 --- a/src/Compiler/Statement.java +++ b/src/Compiler/Statement.java @@ -48,16 +48,33 @@ abstract class Statement { @Override public String getStatmentType() { - return "vardec"; + return "varDec"; + } + + } + + static class StringDeclaration extends Statement{ + StringDeclaration(Token name,Expression length){ + this.name=name; + this.length=length; + } + + + final Token name; + final Expression length; + + @Override + public String getStatmentType() { + return "stringDec"; } } static class PrintStatement extends Statement{ - PrintStatement(Expression expr){ - this.expr=expr; + PrintStatement(List<Expression> exprList){ + this.exprList=exprList; } - final Expression expr; + final List<Expression> exprList; @Override public String getStatmentType() { diff --git a/src/Compiler/TokenScanner.java b/src/Compiler/TokenScanner.java index 27501fa..f2fcab3 100644 --- a/src/Compiler/TokenScanner.java +++ b/src/Compiler/TokenScanner.java @@ -40,6 +40,7 @@ public class TokenScanner { case '*': createTokenNull(TokenType.STAR); break; case '/': createTokenNull(TokenType.SLASH); break; case ';': createTokenNull(TokenType.SEMI_COLON); break; + case ',': createTokenNull(TokenType.COMMA); break; //Some tokens are multiple characters long (==, <=) etc //so need to check next char as well @@ -75,6 +76,17 @@ public class TokenScanner { createTokenNull(TokenType.GREATER); break; } + case '"': + while(lookAhead()!='"' && !checkEOF()){ + currentLoc++; + } + if(checkEOF()){ + Language.displayError("Strings must end with \""); + break; + } + currentLoc++; + createToken(TokenType.STRING, sourceCode.substring(tokenStart, currentLoc+1)); + break; default: //Check for numer @@ -180,8 +192,11 @@ public class TokenScanner { static { keywords = new HashMap<>(); keywords.put("int", TokenType.INT); + keywords.put("len", TokenType.LEN); keywords.put("real", TokenType.REAL); + keywords.put("character", TokenType.STRING); keywords.put("print", TokenType.PRINT); + keywords.put("endprint", TokenType.ENDPRINT); keywords.put("if", TokenType.IF); keywords.put("then", TokenType.THEN); keywords.put("endif", TokenType.ENDIF); diff --git a/src/Compiler/TokenType.java b/src/Compiler/TokenType.java index f56bf38..f597d2f 100644 --- a/src/Compiler/TokenType.java +++ b/src/Compiler/TokenType.java @@ -4,15 +4,15 @@ package Compiler; public enum TokenType { EQUALS, LEFT_PAREN, RIGHT_PAREN, PLUS, MINUS, SLASH, STAR, SEMI_COLON, - COLON, + COLON,COMMA, EQUALITY, GREATER, LESS, GREATER_EQUAL, LESS_EQUAL, DEFINE, - NUMBER,IDENTIFIER, + NUMBER,IDENTIFIER,STRING, - INT,REAL,PRINT,IF,THEN,ENDIF,ELSE, + INT,REAL,PRINT,ENDPRINT,IF,THEN,ENDIF,ELSE,LEN, EOF } diff --git a/src/Compiler/Translator.java b/src/Compiler/Translator.java index 716bafd..d343b80 100644 --- a/src/Compiler/Translator.java +++ b/src/Compiler/Translator.java @@ -15,6 +15,7 @@ public class Translator{ public List<String> compileToC(List<Statement> statements){ CCode.add("#include <stdio.h>"); + CCode.add("#include <string.h>"); CCode.add("int main(){"); try{ for (Statement statement: statements){ @@ -37,9 +38,12 @@ public class Translator{ case "exprStmt": evalExpressionStatement((ExpressionStatement)statement); break; - case "vardec": + case "varDec": evalVariableDeclaration((VariableDeclaration)statement); break; + case "stringDec": + evalStringDeclaration((StringDeclaration)statement); + break; case "print": evalPrintStatement((PrintStatement)statement); break; @@ -52,31 +56,49 @@ public class Translator{ evaluateExpression(stmt.expr); } + private void evalStringDeclaration(StringDeclaration stringdec){ + environment.defineVariable(stringdec.name.text, "string"); + int size = (int)((Expression.Literal)stringdec.length).value.value; + size++; + CCode.add("char "+stringdec.name.text+"["+size+"];"); + } + private void evalVariableDeclaration(VariableDeclaration vardec){ environment.defineVariable(vardec.name.text, vardec.type); if(vardec.type.equals("int")){ CCode.add("int "+vardec.name.text+";"); } else if(vardec.type.equals("real")){ CCode.add("float "+vardec.name.text+";"); - } + } } private void evalPrintStatement(PrintStatement print){ - if(print.expr instanceof Expression.Literal){ - if (((Expression.Literal)print.expr).type.equals("int")){ - CCode.add("printf(\"%d\","+evaluateExpression(print.expr)+");"); - } else if (((Expression.Literal)print.expr).type.equals("double")){ - CCode.add("printf(\"%f\","+evaluateExpression(print.expr)+");"); + String types=""; + String values=""; + boolean first=true; + for(Expression expr:print.exprList){ + if(!first){ + values+=","; + }else{ + first=false; + } + String exprType=""; + if(expr instanceof Expression.Literal){ + exprType=((Expression.Literal)expr).type; + } + else if (expr instanceof Expression.Variable){ + exprType=(String)environment.getVariable((((Expression.Variable)expr).name).text); } - } else if (print.expr instanceof Expression.Variable){ - Object varValue = environment.getVariable((((Expression.Variable)print.expr).name).text); - if (varValue.equals("int")){ - CCode.add("printf(\"%d\","+evaluateExpression(print.expr)+");"); - } else if (varValue.equals("real")){ - CCode.add("printf(\"%f\","+evaluateExpression(print.expr)+");"); - } + if (exprType.equals("int")){ + types+="%d"; + } else if (exprType.equals("double")){ + types+="%f"; + } else if (exprType.equals("string")){ + types+="%s"; + } + values+=evaluateExpression(expr); } - + CCode.add("printf(\""+types+"\","+values+");"); } private void evalIfStatement(IfStatement ifstatement){ @@ -145,7 +167,14 @@ public class Translator{ } private void evaluateAssignmentExpression(AssignmentExpression expr){ - CCode.add(expr.name.text+"="+evaluateExpression(expr.value)+";"); + 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)+";"); + } } private String evaluateVariableExpression(Variable expr){ diff --git a/src/example.txt b/src/example.txt index 886e85c..8e10c72 100644 --- a/src/example.txt +++ b/src/example.txt @@ -1,6 +1,6 @@ -real :: a -a=6 -if a>2 then -a=a+0.5 +character (len=10)::hello +hello="hello" +if 5==5 then +hello="goodbye " endif -print a +print *,hello,6," test" endprint
\ No newline at end of file @@ -1,9 +1,10 @@ #include <stdio.h> +#include <string.h> int main(){ -float a; -a=6; -if(a>2){ -a=a+0.5; +char hello[11]; +strcpy(hello,"hello"); +if(5==5){ +strcpy(hello,"goodbye "); } -printf("%f",a); +printf("%s%d%s",hello,6," test"); } diff --git a/src/main.exe b/src/main.exe Binary files differindex 1dded0a..4f0961a 100644 --- a/src/main.exe +++ b/src/main.exe |