summaryrefslogtreecommitdiffstats
path: root/src/Compiler/Parser.java
diff options
context:
space:
mode:
authorAidenRushbrooke <72034940+AidenRushbrooke@users.noreply.github.com>2021-12-04 05:24:43 +0000
committerAidenRushbrooke <72034940+AidenRushbrooke@users.noreply.github.com>2021-12-04 05:24:43 +0000
commit43909b350b9084ed33f121a15c5770224cbdc79f (patch)
treeaff7f471784fbb1d1a3597acfeb43624d4ed94ad /src/Compiler/Parser.java
parentcc1f6e712520793d5a8c638a6e995c018917eadb (diff)
downloadesotericFORTRAN-43909b350b9084ed33f121a15c5770224cbdc79f.tar.gz
esotericFORTRAN-43909b350b9084ed33f121a15c5770224cbdc79f.zip
Added basic function support
Diffstat (limited to 'src/Compiler/Parser.java')
-rw-r--r--src/Compiler/Parser.java140
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());
}