diff options
Diffstat (limited to 'src/Compiler/Parser.java')
-rw-r--r-- | src/Compiler/Parser.java | 140 |
1 files changed, 120 insertions, 20 deletions
diff --git a/src/Compiler/Parser.java b/src/Compiler/Parser.java index eba3513..ae2ed23 100644 --- a/src/Compiler/Parser.java +++ b/src/Compiler/Parser.java @@ -1,22 +1,25 @@ package Compiler; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class Parser { private final List<Token> tokens; private int currentToken = 0; + private final Map<String,String> definedVars = new HashMap<>(); + List<Statement> statements = new ArrayList<>(); Parser(List<Token> tokens){ this.tokens=tokens; } List<Statement> parse(){ - List<Statement> statements = new ArrayList<>(); try{ while (!checkEOF()){ - statements.add(statement()); + statements.add(functionCalls()); } }catch (Error e){ return null; @@ -25,6 +28,52 @@ public class Parser { } + private Statement functionCalls(){ + if(matchAndAdvance(TokenType.PROGRAM)){ + matchOrError(TokenType.IDENTIFIER, "Expected program name"); + Token programname = getPreviousToken(); + Statement block = blockStatement(false); + matchOrError(TokenType.PROGRAM,"Programs must end in 'program'"); + matchOrError(TokenType.IDENTIFIER,"Expected program name"); + if(!(getPreviousToken().text.equals(programname.text))){ + throw error(getPreviousToken(), "Program names do not match"); + } + return new Statement.MainFunction(block); + } else if(matchAndAdvance(TokenType.FUNCTION)){ + String returntype=null; + if(matchAndAdvance(TokenType.INT)){ + returntype="int"; + } else if (matchAndAdvance(TokenType.REAL)){ + returntype="real"; + }else{ + throw error(getCurrentToken(), "Expected function return type"); + } + matchOrError(TokenType.IDENTIFIER, "Expected function name"); + Token name = getPreviousToken(); + definedVars.put(name.text, "function"); + matchOrError(TokenType.LEFT_PAREN, "Expected '("); + List<Expression> arguments=new ArrayList<>(); + List<String> types = new ArrayList<>(); + if(!matchAndAdvance(TokenType.RIGHT_PAREN)){ + do{ + if(matchAndAdvance(TokenType.INT)){ + types.add("int"); + } else if (matchAndAdvance(TokenType.REAL)){ + types.add("float"); + } else if (matchAndAdvance(TokenType.STRING)){ + types.add("char*"); + } + arguments.add(expression()); + } while(matchAndAdvance(TokenType.COMMA)); + matchOrError(TokenType.RIGHT_PAREN, "Expected ')'"); + } + Statement block = blockStatement(true); + statements.add(0,new Statement.FunctionDeclaration(name,types,returntype)); + return new Statement.Function(name,block,arguments,types,returntype); + } + throw error(getCurrentToken(), "Expected program or function"); + } + private Statement statement(){ if(checkToken(TokenType.INT)||checkToken(TokenType.REAL)||checkToken(TokenType.STRING)){ return declaration(); @@ -35,6 +84,8 @@ public class Parser { return ifStatement(); }else if (matchAndAdvance(TokenType.DO)){ return doStatement(); + }else if (matchAndAdvance(TokenType.RETURN)){ + return returnStatement(); } return expressionStatement(); } @@ -49,7 +100,12 @@ public class Parser { matchOrError(TokenType.DEFINE, ":: Required for variable definition"); matchOrError(TokenType.IDENTIFIER,"Expected variable name."); Token varName = getPreviousToken(); - return new Statement.VariableDeclaration(varName,"int"); + if(definedVars.containsKey(varName.text)){ + throw error(varName, "Cannot define multiple variables with the same name"); + }else{ + definedVars.put(varName.text,"int"); + return new Statement.VariableDeclaration(varName,"int"); + } } else if (matchAndAdvance(TokenType.REAL)){ if(matchAndAdvance(TokenType.DIMENSION)){ return arrayDeclaration("real"); @@ -57,7 +113,12 @@ public class Parser { matchOrError(TokenType.DEFINE, ":: Required for variable definition"); matchOrError(TokenType.IDENTIFIER,"Expected variable name."); Token varName = getPreviousToken(); - return new Statement.VariableDeclaration(varName,"real"); + if(definedVars.containsKey(varName.text)){ + throw error(varName, "Cannot define multiple variables with the same name"); + }else{ + definedVars.put(varName.text,"real"); + return new Statement.VariableDeclaration(varName,"real"); + } //Could be improved significatly when verifiying length is a positive integer } else if (matchAndAdvance(TokenType.STRING)){ @@ -79,7 +140,12 @@ public class Parser { matchOrError(TokenType.DEFINE, ":: Required for variable definition"); matchOrError(TokenType.IDENTIFIER,"Expected variable name."); Token varName = getPreviousToken(); - return new Statement.StringDeclaration(varName,length); + if(definedVars.containsKey(varName.text)){ + throw error(varName, "Cannot define multiple variables with the same name"); + }else{ + definedVars.put(varName.text,"string"); + return new Statement.StringDeclaration(varName,length); + } } return null; } @@ -97,16 +163,29 @@ public class Parser { matchOrError(TokenType.DEFINE, ":: Required for variable definition"); matchOrError(TokenType.IDENTIFIER,"Expected variable name."); Token varName = getPreviousToken(); - return new Statement.ArrayDeclaration(varName, type, dimensions); + if(definedVars.containsKey(varName.text)){ + throw error(varName, "Cannot define multiple variables with the same name"); + }else{ + definedVars.put(varName.text,"array"); + return new Statement.ArrayDeclaration(varName, type, dimensions); + } } - private Statement blockStatement(){ + private Statement blockStatement(boolean isFunction){ + boolean hasReturn=false; List<Statement> statements = new ArrayList<>(); while(!matchAndAdvance(TokenType.END)&&!checkToken(TokenType.ELSE)){ if(checkEOF()){ throw error(getCurrentToken(),"end missing from block"); } - statements.add(statement()); + Statement statement = statement(); + if(statement.getStatmentType()=="return"){ + hasReturn=true; + } + statements.add(statement); + } + if(isFunction&&!hasReturn){ + throw error(getPreviousToken(), "Function must contain a return statement"); } return new Statement.BlockStatement(statements); } @@ -128,11 +207,11 @@ public class Parser { private Statement ifStatement(){ Expression condition = expression(); if(matchOrError(TokenType.THEN, "then expected after if statement")){ - Statement ifBlock = blockStatement(); + Statement ifBlock = blockStatement(false); Statement elseBlock=null; if(matchAndAdvance(TokenType.ELSE)){ - elseBlock=blockStatement(); + elseBlock=blockStatement(false); } matchOrError(TokenType.IF, "If statements end with if"); Statement ifstatement = new Statement.IfStatement(condition, ifBlock,elseBlock); @@ -154,7 +233,7 @@ public class Parser { if(matchAndAdvance(TokenType.COMMA)){ step = expression(); } - Statement codeBlock = blockStatement(); + Statement codeBlock = blockStatement(false); matchOrError(TokenType.DO, "Do statements end with do"); return new Statement.DoStatement(variable, start, stop, step,codeBlock); @@ -164,11 +243,16 @@ public class Parser { matchOrError(TokenType.LEFT_PAREN, " missing '(' for do statement condition"); Expression condition = expression(); matchOrError(TokenType.RIGHT_PAREN, " missing ')' for do condition"); - Statement codeBlock = blockStatement(); + Statement codeBlock = blockStatement(false); matchOrError(TokenType.DO, "Do while statements end with do"); return new Statement.DoWhileStatement(condition,codeBlock); } + private Statement returnStatement(){ + Expression returnValue = expression(); + return new Statement.ReturnStatement(returnValue); + } + private Statement expressionStatement(){ Expression expression = assignment(); return new Statement.ExpressionStatement(expression); @@ -259,15 +343,31 @@ public class Parser { if (matchAndAdvance(TokenType.IDENTIFIER)) { Token name= getPreviousToken(); if(matchAndAdvance(TokenType.LEFT_PAREN)){ - List<Expression> positions = new ArrayList<>(); - Expression position = expression(); - positions.add(position); - while(matchAndAdvance(TokenType.COMMA)){ - position = expression(); - positions.add(position); + if(definedVars.containsKey(name.text)){ + if(definedVars.get(name.text).equals("array")){ + List<Expression> positions = new ArrayList<>(); + Expression position = expression(); + positions.add(position); + while(matchAndAdvance(TokenType.COMMA)){ + position = expression(); + positions.add(position); + } + matchOrError(TokenType.RIGHT_PAREN,"Expected ')'"); + return new Expression.ArrayVariable(name, positions); + } } - matchOrError(TokenType.RIGHT_PAREN,"Expected ')'"); - return new Expression.ArrayVariable(name, positions); + List<Token> arguments = new ArrayList<>(); + do{ + matchOrError(TokenType.IDENTIFIER, "Expected argument"); + Token argumentValue = getPreviousToken(); + if(definedVars.containsKey(argumentValue.text)){ + arguments.add(argumentValue); + }else{ + throw error(argumentValue, "Argument undefined"); + } + }while(matchAndAdvance(TokenType.COMMA)); + matchOrError(TokenType.RIGHT_PAREN, "Expected ')"); + return new Expression.FunctionCall(name, arguments); } return new Expression.Variable(getPreviousToken()); } |