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/Compiler | |
| parent | f8b888716211b78900db62ede497fa4ac2100c00 (diff) | |
| download | esotericFORTRAN-975fb6f000918085d1f5ba4ac6eb95c60411dae9.tar.gz esotericFORTRAN-975fb6f000918085d1f5ba4ac6eb95c60411dae9.zip | |
Added support for strings and improved print statement syntax
Diffstat (limited to 'src/Compiler')
| -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 | 
5 files changed, 131 insertions, 36 deletions
| 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){ | 
