diff options
| -rw-r--r-- | src/.vscode/launch.json | 2 | ||||
| -rw-r--r-- | src/Compiler/Parser.java | 72 | ||||
| -rw-r--r-- | src/examples/recursive.ft | 14 | 
3 files changed, 48 insertions, 40 deletions
| diff --git a/src/.vscode/launch.json b/src/.vscode/launch.json index bc86f64..1008b15 100644 --- a/src/.vscode/launch.json +++ b/src/.vscode/launch.json @@ -23,7 +23,7 @@              "request": "launch",              "mainClass": "Compiler.Language",              "projectName": "src_1da2a030", -            "args": "examples/example.ft -c -e" +            "args": "examples/recursive.ft -c -e"          }      ]  }
\ No newline at end of file diff --git a/src/Compiler/Parser.java b/src/Compiler/Parser.java index c7b0165..0ac91d6 100644 --- a/src/Compiler/Parser.java +++ b/src/Compiler/Parser.java @@ -13,6 +13,7 @@ public class Parser {      private int currentToken = 0;      private final Map<String,String> definedVars = new HashMap<>();      List<Statement> statements =  new ArrayList<>(); +    private boolean foundReturn;      /**       * Constructor of a parser object @@ -48,7 +49,7 @@ public class Parser {          if(matchAndAdvance(TokenType.PROGRAM)){              matchOrError(TokenType.IDENTIFIER, "Expected program name");              Token programname = getPreviousToken(); -            Statement block = blockStatement(false); +            Statement block = blockStatement();              matchOrError(TokenType.PROGRAM,"Programs must end in 'program'");              matchOrError(TokenType.IDENTIFIER,"Expected program name"); @@ -80,7 +81,7 @@ public class Parser {              //Add function name to the list of defined values              definedVars.put(name.text, "function"); -            matchOrError(TokenType.LEFT_PAREN, "Expected '("); +            matchOrError(TokenType.LEFT_PAREN, "Expected '(' in function definition");              List<Expression> arguments=new ArrayList<>();              List<String> types = new ArrayList<>(); @@ -96,11 +97,13 @@ public class Parser {                      }                      arguments.add(expression());                  } while(matchAndAdvance(TokenType.COMMA)); -                matchOrError(TokenType.RIGHT_PAREN, "Expected ')'"); +                matchOrError(TokenType.RIGHT_PAREN, "Expected ')' in function definition"); +            } +            foundReturn=false; +            Statement block = blockStatement(); +            if(isfunction&&!foundReturn){ +                throw error(name, "Function must contain a return statement");              } - -            Statement block = blockStatement(isfunction); -              //Add the function declaration to the start of the list of statements              statements.add(0,new Statement.FunctionDeclaration(name,types,returntype));              return new Statement.Function(name,block,arguments,types,returntype); @@ -225,7 +228,7 @@ public class Parser {       * @return A statement representing the array declaration       */      private Statement arrayDeclaration(String type){ -        matchOrError(TokenType.LEFT_PAREN,"Expected ')'"); +        matchOrError(TokenType.LEFT_PAREN,"Expected ')' for array definition");          //Extract the size of the array          List<Expression> dimensions = new ArrayList<>(); @@ -236,9 +239,9 @@ public class Parser {              dimensions.add(dimension);          } while(matchAndAdvance(TokenType.COMMA)); -        matchOrError(TokenType.RIGHT_PAREN, "Expected ')'"); -        matchOrError(TokenType.DEFINE, ":: Required for variable definition"); -        matchOrError(TokenType.IDENTIFIER,"Expected variable name."); +        matchOrError(TokenType.RIGHT_PAREN, "Expected ')' for array definition"); +        matchOrError(TokenType.DEFINE, ":: Required for array definition"); +        matchOrError(TokenType.IDENTIFIER,"Expected array name.");          Token varName = getPreviousToken();          //Ensure that a variable with the same name has not been defined @@ -255,8 +258,7 @@ public class Parser {       * @param isFunction whether the block is for a function and so must contain a return statement       * @return a statement representing a block       */ -    private Statement blockStatement(boolean isFunction){ -        boolean hasReturn=false; +    private Statement blockStatement(){          List<Statement> statements = new ArrayList<>();          //Match statement until an end or else token has been reached @@ -266,15 +268,8 @@ public class Parser {                  throw error(getCurrentToken(),"end missing from block");              }              Statement statement = statement(); -            if(statement.getStatmentType()=="return"){ -                hasReturn=true; -            }              statements.add(statement);          } -        //Ensure that a function block contains a return statement -        if(isFunction&&!hasReturn){ -            throw error(getPreviousToken(), "Function must contain a return statement"); -        }          return new Statement.BlockStatement(statements);      } @@ -289,7 +284,7 @@ public class Parser {          //Get the list of printed values          while(matchAndAdvance(TokenType.COMMA)){              if(checkEOF()){ -                throw error(getCurrentToken(),"reached end of file"); +                throw error(getCurrentToken(),"reached end of file scanning print statement");              }              Expression expr = expression();              exprList.add(expr); @@ -303,20 +298,18 @@ public class Parser {       */      private Statement ifStatement(){          Expression condition = expression(); -        if(matchOrError(TokenType.THEN, "then expected after if statement")){ -            //Extract if block -            Statement ifBlock = blockStatement(false); -            Statement elseBlock=null; +        matchOrError(TokenType.THEN, "then expected after if statement"); +        //Extract if block +        Statement ifBlock = blockStatement(); +        Statement elseBlock=null; -            //Extract else block if required -            if(matchAndAdvance(TokenType.ELSE)){ -                elseBlock=blockStatement(false); -            } -            matchOrError(TokenType.IF, "If statements end with if"); -            Statement ifstatement = new Statement.IfStatement(condition, ifBlock,elseBlock); -            return ifstatement; +        //Extract else block if required +        if(matchAndAdvance(TokenType.ELSE)){ +            elseBlock=blockStatement();          } -        return null; +        matchOrError(TokenType.IF, "If statements end with if"); +        Statement ifstatement = new Statement.IfStatement(condition, ifBlock,elseBlock); +        return ifstatement;      }      /** @@ -329,17 +322,17 @@ public class Parser {              return whileStatement();          }          Expression variable =expression(); -        matchOrError(TokenType.EQUALS, "'=' missing"); +        matchOrError(TokenType.EQUALS, "'=' missing from do statement assignment");          //Extract start, stop, and step variables          Expression start = expression(); -        matchOrError(TokenType.COMMA, " use ',' between values"); +        matchOrError(TokenType.COMMA, " use ',' between values in do statement");          Expression stop = expression();          Expression step = null;          if(matchAndAdvance(TokenType.COMMA)){             step = expression();          } -        Statement codeBlock = blockStatement(false); +        Statement codeBlock = blockStatement();          matchOrError(TokenType.DO, "Do statements end with do");          return new Statement.DoStatement(variable, start, stop, step,codeBlock); @@ -351,10 +344,10 @@ public class Parser {       */      private Statement whileStatement(){          //Extract condition -        matchOrError(TokenType.LEFT_PAREN, " missing '(' for do statement condition"); +        matchOrError(TokenType.LEFT_PAREN, " missing '(' for do while statement condition");          Expression condition = expression(); -        matchOrError(TokenType.RIGHT_PAREN, " missing ')' for do  condition"); -        Statement codeBlock = blockStatement(false); +        matchOrError(TokenType.RIGHT_PAREN, " missing ')' for do while condition"); +        Statement codeBlock = blockStatement();          matchOrError(TokenType.DO, "Do while statements end with do");          return new Statement.DoWhileStatement(condition,codeBlock);      } @@ -364,6 +357,7 @@ public class Parser {       * @return a return statement object       */      private Statement returnStatement(){ +        foundReturn=true;          Expression returnValue = expression();          return new Statement.ReturnStatement(returnValue);      } @@ -543,7 +537,7 @@ public class Parser {          //Parse bracketed expressions          if (matchAndAdvance(TokenType.LEFT_PAREN)){              Expression expr = expression(); -            matchOrError(TokenType.RIGHT_PAREN,"Expected ')'"); +            matchOrError(TokenType.RIGHT_PAREN,"Expected ')' after bracketed expression");              return new Expression.BracketedExpression(expr);          }          //Throw an error if the expression was not recognised diff --git a/src/examples/recursive.ft b/src/examples/recursive.ft new file mode 100644 index 0000000..d6f7a69 --- /dev/null +++ b/src/examples/recursive.ft @@ -0,0 +1,14 @@ +program recursive +int::value +int::final +value=5 +final=factorial(value) +print*,"The factorial of ",value," is ",final +end program recursive + +function int factorial(int x) +if x==1 then +return 1 +end if  +return x*factorial(x-1) +end
\ No newline at end of file | 
