summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAidenRushbrooke <72034940+AidenRushbrooke@users.noreply.github.com>2021-11-07 22:35:33 +0000
committerAidenRushbrooke <72034940+AidenRushbrooke@users.noreply.github.com>2021-11-07 22:35:33 +0000
commit975fb6f000918085d1f5ba4ac6eb95c60411dae9 (patch)
tree8dab2d0447e9e2dca9dc1b06d42d5331d55c4547 /src
parentf8b888716211b78900db62ede497fa4ac2100c00 (diff)
downloadesotericFORTRAN-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.json3
-rw-r--r--src/.vscode/tasks.json68
-rw-r--r--src/Compiler/Parser.java60
-rw-r--r--src/Compiler/Statement.java25
-rw-r--r--src/Compiler/TokenScanner.java15
-rw-r--r--src/Compiler/TokenType.java6
-rw-r--r--src/Compiler/Translator.java61
-rw-r--r--src/example.txt10
-rw-r--r--src/main.c11
-rw-r--r--src/main.exebin297800 -> 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
diff --git a/src/main.c b/src/main.c
index 055bc9d..1e6ed2b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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
index 1dded0a..4f0961a 100644
--- a/src/main.exe
+++ b/src/main.exe
Binary files differ