Author: mesyeti <mesyeti@mesyeti.uk>
add array accesses to NitronBASIC
basic/source/frontend/c89.c | 39 ++++++++++++++++++++++++++-- basic/source/lexer.c | 4 ++ basic/source/parser.c | 6 ++++ basic/source/semanticAnalysis.c | 48 +++++++++++++++++++++++++++++++++++ basic/test.bas | 5 +++ basic/test2.bas | 4 ++
diff --git a/basic/source/frontend/c89.c b/basic/source/frontend/c89.c
index fb57b83b093a8ee2c84562b6ade60f08b24286c4..33d890c1094c16e7ac0a8ff60ecef41f9496f0d7 100644
--- a/basic/source/frontend/c89.c
+++ b/basic/source/frontend/c89.c
@@ -64,7 +64,7 @@ fprintf(out, "%s(", dec.name);
for (size_t i = 0; i < dec.paramsNum; ++ i) {
CompileType(dec.params[i].type);
- fprintf(out, " %s", dec.params[i].name);
+ fprintf(out, " nitron_%s", dec.params[i].name);
if (i < dec.paramsNum - 1) {
fprintf(out, ", ");
@@ -117,7 +117,27 @@
switch (node->i.type) {
case NODE_INT: fprintf(out, "%d", node->integer.value); break;
case NODE_STRING: fprintf(out, "\"%s\"", node->string.value); break;
- case NODE_IDENTIFIER: fprintf(out, "%s", node->ident.name); break;
+ case NODE_IDENTIFIER: {
+ Var* var = State_GetVar(node->ident.name);
+
+ bool func = false;
+
+ if (var) {
+ Type* type = State_GetTypeFromUsed(var->type);
+
+ if ((var->type.ptr == 0) && (var->type.array == 0) && (type->type == TYPE_FUNC)) {
+ func = true;
+ }
+ }
+
+ if (func) {
+ fprintf(out, "%s", node->ident.name);
+ }
+ else {
+ fprintf(out, "nitron_%s", node->ident.name);
+ }
+ break;
+ }
case NODE_BINARY_OP: {
fprintf(out, "(");
CompileExprNode(node->bin.left);
@@ -145,10 +165,16 @@ }
break;
}
case TOKEN_LPAREN: break; // function call, nothing to do
+ case TOKEN_LSQUARE: fprintf(out, "["); break;
default: assert(0);
}
CompileExprNode(node->bin.right);
+
+ if (node->bin.op == TOKEN_LSQUARE) {
+ fprintf(out, "]");
+ }
+
fprintf(out, ")");
break;
}
@@ -314,7 +340,14 @@
if (varType->type == TYPE_FUNC) continue;
CompileUsedType(var->type);
- fprintf(out, " nitron_%s;\n", var->name);
+ fprintf(out, " nitron_%s", var->name);
+
+ if (var->type.array) {
+ fprintf(out, "[%d];\n", (int) var->type.array);
+ }
+ else {
+ fprintf(out, ";\n");
+ }
}
// declare all functions
diff --git a/basic/source/lexer.c b/basic/source/lexer.c
index 9d5185d1937492c9c9dcf83cf7da9c350119df2a..1a385bd5a17d1a8f766f19be16866d59ebf55b6f 100644
--- a/basic/source/lexer.c
+++ b/basic/source/lexer.c
@@ -37,7 +37,9 @@ case '>':
case '\'':
case '^':
case '&':
- case ';': return true;
+ case ';':
+ case '[':
+ case ']': return true;
default: return false;
}
}
diff --git a/basic/source/parser.c b/basic/source/parser.c
index 6f2750e3c2bb090b3e1cb9887cf3957f318fbcac..a71dc8d423b5fd1d7423df351e5a29485862c3fc 100644
--- a/basic/source/parser.c
+++ b/basic/source/parser.c
@@ -812,10 +812,16 @@ case TOKEN_GREATER: printf(">"); break;
case TOKEN_ASSIGN: printf("="); break;
case TOKEN_DOT: printf("."); break;
case TOKEN_LPAREN: break;
+ case TOKEN_LSQUARE: printf("["); break;
default: assert(0);
}
Parser_PrintNode(node->bin.right);
+
+ if (node->bin.op == TOKEN_LSQUARE) {
+ printf("]");
+ }
+
printf(")");
if (node->bin.op == TOKEN_ASSIGN) {
diff --git a/basic/source/semanticAnalysis.c b/basic/source/semanticAnalysis.c
index 1a382c2409465ec9bcad45e6b8db88e0ddc5e8d2..8363fbc73b6da5348e71e8c4ce888d427084c49c 100644
--- a/basic/source/semanticAnalysis.c
+++ b/basic/source/semanticAnalysis.c
@@ -190,6 +190,39 @@ return func->ret;
}
}
+static UsedType EvalArrayAccess(Node* node, UsedType left, UsedType right) {
+ Type* leftType = State_GetTypeFromUsed(left);
+ Type* rightType = State_GetTypeFromUsed(right);
+
+ if ((left.array > 0) || (left.ptr > 0)) {
+ if (
+ (right.ptr > 0) || (right.array > 0) || (rightType->type != TYPE_PRIM)
+ ) {
+ PrintError(node->i.err, "Only integers can be used to index an array");
+ }
+
+ if ((rightType->primType != PRIM_UINT) && (rightType->primType != PRIM_INT)) {
+ PrintError(node->i.err, "Only integers can be used to index an array");
+ }
+
+ UsedType ret = left;
+
+ if (left.array > 0) {
+ -- ret.array;
+ }
+ else if (left.ptr > 0) {
+ -- ret.ptr;
+ }
+
+ return ret;
+ }
+ else {
+ PrintError(node->i.err, "Cannot use array access operator on this type");
+ }
+
+ assert(0);
+}
+
static UsedType EvalBinOp(Node* node) {
UsedType left = SemanticAnalysis_EvalType(node->bin.left);
@@ -201,6 +234,10 @@ return EvalFuncCall(node, left);
}
UsedType right = SemanticAnalysis_EvalType(node->bin.right);
+
+ if (node->bin.op == TOKEN_LSQUARE) {
+ return EvalArrayAccess(node, left, right);
+ }
Type* leftType = State_GetTypeFromUsed(left);
Type* rightType = State_GetTypeFromUsed(right);
@@ -444,6 +481,17 @@ case NODE_DIM: {
Var var;
var.type = SemanticAnalysis_NodeAsUsedType(node->dim.varType);
var.name = NewString(node->dim.name);
+
+ if (node->dim.array) {
+ if (node->dim.arrayLen->i.type != NODE_INT) {
+ // this will be changed at some point
+ // TODO
+ PrintError(node->dim.arrayLen->i.err, "Array length must be a constant integer");
+ }
+
+ var.type.array = node->dim.arrayLen->integer.value;
+ }
+
State_AddVar(var);
return GET_PRIM("unit", 0);
}
diff --git a/basic/test.bas b/basic/test.bas
index 5efc554e8f2f83da16dc67a388ca4deac79a44ac..a42885304b30f991aedef977e1263ff2acb719e9 100644
--- a/basic/test.bas
+++ b/basic/test.bas
@@ -11,3 +11,8 @@ end
printf("2 + 2 = %d\n", add(2, 2))
printf("2 + 3 = %d\n", add(2, 3))
+
+dim myArray[5] as i32
+
+myArray[0] = 4
+printf("myArray[0] = %d\n", myArray[0])
diff --git a/basic/test2.bas b/basic/test2.bas
index cda0b34274133fe1842785c47369fd4b40b13e5e..ce689966335a9e5beb787432f296c18e3f53bf4d 100644
--- a/basic/test2.bas
+++ b/basic/test2.bas
@@ -1,3 +1,5 @@
'NITRON
-print("hello")
+dim myArray[5] as u32
+
+myArray[0] = 5