Author: mesyeti <mesyeti@mesyeti.uk>
add constants
basic-std/std/file.bas | 9 +++ basic/source/compiler.c | 1 basic/source/frontend/c89.c | 24 ++++++++++ basic/source/lexer.c | 4 + basic/source/lexer.h | 1 basic/source/parser.c | 76 +++++++++++++++++++++++++++----- basic/source/parser.h | 10 +++ basic/source/semanticAnalysis.c | 82 ++++++++++++++++++++++++++++++++-- basic/source/state.c | 19 ++++++++ basic/source/state.h | 10 ++++ basic/test.bas | 16 -----
diff --git a/basic/source/compiler.c b/basic/source/compiler.c index ad14a7482ad0738f79589c9ed02bdc5e08e51b54..dd435480437f24639ef387bdb81e65b6b7b815cf 100644 --- a/basic/source/compiler.c +++ b/basic/source/compiler.c @@ -48,6 +48,7 @@ case NODE_PROGRAM: break; case NODE_IMPORT: break; case NODE_IF: frontend.compileIf(&node->ifStat); break; case NODE_WHILE: frontend.compileWhile(&node->whileStat); break; + case NODE_CONST: break; case NODE_BINARY_OP: { if (node->bin.op == TOKEN_ASSIGN) { frontend.compileAssign(&node->bin); diff --git a/basic/source/frontend/c89.c b/basic/source/frontend/c89.c index 01888d5ff283b8e04a9b31989986df439fb80629..7b42d247cb1fc5f0cd9097d02342d8feb23f9a09 100644 --- a/basic/source/frontend/c89.c +++ b/basic/source/frontend/c89.c @@ -168,6 +168,18 @@ fprintf(out, ")"); } +static void CompileCast(Node* node) { + UsedType type = SemanticAnalysis_NodeAsUsedType(node->bin.right); + + fprintf(out, "(("); + CompileUsedType(type); + fprintf(out, ") "); + + CompileExprNode(node->bin.left); + + fprintf(out, ")"); +} + static void CompileExprNode(Node* node) { assert(node); @@ -177,6 +189,13 @@ case NODE_STRING: fprintf(out, "\"%s\"", node->string.value); break; case NODE_IDENTIFIER: { Var* var = State_GetVar(node->ident.name); + if (!var) { + Const* constant = State_GetConst(node->ident.name); + + fprintf(out, "%lld", constant->value); + break; + } + bool func = false; if (var) { @@ -196,6 +215,11 @@ } break; } case NODE_BINARY_OP: { + if (node->bin.op == TOKEN_AS) { + CompileCast(node); + return; + } + Node* left = node->bin.left; Node leftNode; // set `left` to this if it's a method diff --git a/basic/source/lexer.c b/basic/source/lexer.c index cf4355ddf929d399241d489a12283a9d928cd4c7..2986ed79bb635f290b2027d788d3c4237f4b5f8f 100644 --- a/basic/source/lexer.c +++ b/basic/source/lexer.c @@ -203,7 +203,8 @@ {"import", TOKEN_IMPORT}, {"return", TOKEN_RETURN}, {"not", TOKEN_NOT}, {"and", TOKEN_AND}, - {"or", TOKEN_OR} + {"or", TOKEN_OR}, + {"const", TOKEN_CONST} }; for (size_t i = 0; i < sizeof(keywords) / sizeof(Keyword); ++ i) { @@ -244,6 +245,7 @@ case TOKEN_RETURN: return "return"; case TOKEN_NOT: return "not"; case TOKEN_AND: return "and"; case TOKEN_OR: return "or"; + case TOKEN_CONST: return "const"; case TOKEN_IDENTIFIER: return "identifier"; case TOKEN_STRING: return "string"; case TOKEN_INT: return "int"; diff --git a/basic/source/lexer.h b/basic/source/lexer.h index 13c65731d6b8dec21001e81d54eac723105584a1..a3ffa1c3ec96c91d1ac64d5dece90bd07e6c647a 100644 --- a/basic/source/lexer.h +++ b/basic/source/lexer.h @@ -30,6 +30,7 @@ TOKEN_RETURN, TOKEN_NOT, TOKEN_AND, TOKEN_OR, + TOKEN_CONST, // misc TOKEN_IDENTIFIER, diff --git a/basic/source/parser.c b/basic/source/parser.c index 820ae36e28455159876ff29ccb94bb197d36b3f6..659863a3a28de7bf5e7ce9f963427f2931bcb678 100644 --- a/basic/source/parser.c +++ b/basic/source/parser.c @@ -272,8 +272,29 @@ return left; } +static Node ParseCast(Parser* p) { + Node left = ParseBitwise(p); + + while (p->tokens[p->i].type == TOKEN_AS) { + TokenType op = p->tokens[p->i].type; + Advance(p); + Node right = ParseBitwise(p); + + Node* leftPtr = SafeMalloc(sizeof(Node)); + Node* rightPtr = SafeMalloc(sizeof(Node)); + *leftPtr = left; + *rightPtr = right; + + left.bin = (BinaryNode) { + INFO(NODE_BINARY_OP), leftPtr, rightPtr, op + }; + } + + return left; +} + static Node ParseComparison(Parser* p) { - Node left = ParseBitwise(p); + Node left = ParseCast(p); while ( (p->tokens[p->i].type == TOKEN_EQUAL) || @@ -283,7 +304,7 @@ (p->tokens[p->i].type == TOKEN_NOT_EQUAL) ) { TokenType op = p->tokens[p->i].type; Advance(p); - Node right = ParseBitwise(p); + Node right = ParseCast(p); Node* leftPtr = SafeMalloc(sizeof(Node)); Node* rightPtr = SafeMalloc(sizeof(Node)); @@ -766,26 +787,42 @@ node.ret = ret; return node; } -static Node ParseNode(Parser* p) { - static int level = 0; +static Node ParseConst(Parser* p) { + ConstNode ret; + ret.i = INFO(NODE_CONST); - Token* token = &p->tokens[p->i]; + Advance(p); + Expect(p, TOKEN_IDENTIFIER); + ret.name = NewString(p->tokens[p->i].contents); - ++ level; + Advance(p); + Expect(p, TOKEN_ASSIGN); + Advance(p); + ret.value = NodeToHeap(ParseBinary(p)); + + Expect(p, TOKEN_LINE); + + Node node; + node.constant = ret; + return node; +} + +static Node ParseNode(Parser* p) { Node ret; switch (p->tokens[p->i].type) { case TOKEN_FUNC: case TOKEN_SUB: ret = ParseFuncDef(p); break; - case TOKEN_DIM: ret = ParseDim(p); break; - case TOKEN_EXTERN: ret = ParseExtern(p); break; - case TOKEN_IF: ret = ParseIf(p); break; - case TOKEN_WHILE: ret = ParseWhile(p); break; + case TOKEN_DIM: ret = ParseDim(p); break; + case TOKEN_EXTERN: ret = ParseExtern(p); break; + case TOKEN_IF: ret = ParseIf(p); break; + case TOKEN_WHILE: ret = ParseWhile(p); break; case TOKEN_TYPE: ret = ParseTypeDef(p); break; case TOKEN_PROGRAM: ret = ParseProgram(p); break; - case TOKEN_IMPORT: ret = ParseImport(p); break; - case TOKEN_RETURN: ret = ParseReturn(p); break; + case TOKEN_IMPORT: ret = ParseImport(p); break; + case TOKEN_RETURN: ret = ParseReturn(p); break; + case TOKEN_CONST: ret = ParseConst(p); break; case TOKEN_LPAREN: case TOKEN_ACCESS_XOR: case TOKEN_IDENTIFIER: { @@ -864,6 +901,7 @@ case TOKEN_ASSIGN: printf("="); break; case TOKEN_DOT: printf("."); break; case TOKEN_LPAREN: break; case TOKEN_LSQUARE: printf("["); break; + case TOKEN_AS: printf(" as "); break; default: assert(0); } @@ -1013,6 +1051,12 @@ Parser_PrintNode(node->array.idx); putchar(']'); break; } + case NODE_CONST: { + printf("const %s = ", node->constant.name); + Parser_PrintNode(node->constant.value); + puts(""); + break; + } default: { printf("unknown %d\n", node->i.type); assert(0); @@ -1153,6 +1197,11 @@ Parser_FreeNode(node->array.array); Parser_FreeNode(node->array.idx); break; } + case NODE_CONST: { + free(node->constant.name); + Parser_FreeNode(node->constant.value); + break; + } default: return; } } @@ -1176,6 +1225,9 @@ case NODE_TYPE_DEF: return "type def"; case NODE_TYPE_BLOCK: return "type block"; case NODE_PROGRAM: return "program"; case NODE_IMPORT: return "import"; + case NODE_RETURN: return "return"; + case NODE_ARRAY: return "array"; + case NODE_CONST: return "const"; default: return "???"; } } diff --git a/basic/source/parser.h b/basic/source/parser.h index 15a947e63cb6672b56c65b0162bdac7cbe1bd583..70071ca547155ac1acd6bdec1151188d0665a9e9 100644 --- a/basic/source/parser.h +++ b/basic/source/parser.h @@ -24,7 +24,8 @@ NODE_TYPE_BLOCK, NODE_PROGRAM, NODE_IMPORT, NODE_RETURN, - NODE_ARRAY + NODE_ARRAY, + NODE_CONST } NodeType; typedef struct { @@ -158,6 +159,12 @@ Node* array; Node* idx; } ArrayNode; +typedef struct { + NodeInfo i; + char* name; + Node* value; +} ConstNode; + union Node { NodeInfo i; IntNode integer; @@ -177,6 +184,7 @@ TypeBlockNode typeBlock; ImportNode import; ReturnNode ret; ArrayNode array; + ConstNode constant; }; typedef struct { diff --git a/basic/source/semanticAnalysis.c b/basic/source/semanticAnalysis.c index 108a458fbb9b6896d6c5a764e782746e175656da..fcccab2144310a0cd934e5417fceff18c952f89f 100644 --- a/basic/source/semanticAnalysis.c +++ b/basic/source/semanticAnalysis.c @@ -8,6 +8,7 @@ #include "parser.h" #include "semanticAnalysis.h" static Function* thisFunc = NULL; +static size_t wordSize; #define GET_PRIM(NAME, PTR) \ ((UsedType) {(PTR), State_GetType(NAME) - state.types, 0, false}) @@ -15,7 +16,8 @@ #define NEW_VAR(TYPE, NAME, PTR, STATIC) \ ((Var) {GET_PRIM(TYPE, PTR), NAME, STATIC}) -void SemanticAnalysis_Init(size_t wordSize) { +void SemanticAnalysis_Init(size_t p_wordSize) { + wordSize = p_wordSize; State_Init(); // add primitive types @@ -99,6 +101,8 @@ if ((left.ptr != right.ptr) || (leftType->type != rightType->type)) { return false; } else if (leftType->type == TYPE_PRIM) { + if (rightType->size == 0) return true; // __lit + if (leftType->primType != rightType->primType) return false; else if (leftType->size < rightType->size) return false; } @@ -112,7 +116,7 @@ if (!compatible) { PrintError( node->i.err, "Type '%s' cannot be assigned to '%s' variable", - State_GetTypeFromUsed(left)->name, State_GetTypeFromUsed(right)->name + State_GetTypeFromUsed(right)->name, State_GetTypeFromUsed(left)->name ); } @@ -252,6 +256,51 @@ assert(0); } +static UsedType EvalCast(Node* node, UsedType left) { + Type* leftType = State_GetTypeFromUsed(left); + UsedType right = SemanticAnalysis_NodeAsUsedType(node->bin.right); + Type* rightType = State_GetTypeFromUsed(right); + + if (left.ptr) { + if (right.ptr) { + return right; + } + else { + if (rightType->type != TYPE_PRIM) { + PrintError(node->i.err, "Cannot cast pointer to this type"); + } + if (rightType->primType != PRIM_UINT) { + PrintError(node->i.err, "Cannot cast pointer to this type"); + } + if (rightType->size != wordSize) { + PrintError(node->i.err, "Type too small to cast a pointer to"); + } + + return right; + } + } + else if (right.ptr) { + if (leftType->type != TYPE_PRIM) { + PrintError(node->i.err, "Cannot cast pointer to this type"); + } + if (leftType->primType != PRIM_UINT) { + PrintError(node->i.err, "Cannot cast pointer to this type"); + } + if (leftType->size != wordSize) { + PrintError(node->i.err, "Type too small to cast a pointer to"); + } + + return right; + } + else { + if ((leftType->type != TYPE_PRIM) || (rightType->type != TYPE_PRIM)) { + PrintError(node->i.err, "Can only cast primitive types or pointers"); + } + + return right; + } +} + static UsedType EvalBinOp(Node* node) { UsedType left = SemanticAnalysis_EvalType(node->bin.left); @@ -260,6 +309,9 @@ return EvalDot(node, left); } if (node->bin.op == TOKEN_LPAREN) { return EvalFuncCall(node, left); + } + if (node->bin.op == TOKEN_AS) { + return EvalCast(node, left); } UsedType right = SemanticAnalysis_EvalType(node->bin.right); @@ -460,9 +512,15 @@ case NODE_IDENTIFIER: { Var* var = State_GetVar(node->ident.name); if (!var) { - PrintError( - node->i.err, "Variable '%s' doesn't exist", node->ident.name - ); + Const* constant = State_GetConst(node->ident.name); + + if (!constant) { + PrintError( + node->i.err, "Variable '%s' doesn't exist", node->ident.name + ); + } + + return constant->type; } return var->type; @@ -697,11 +755,25 @@ PrintError(node->i.err, "Return type does not match function type"); } return GET_PRIM("unit", 0); } + case NODE_CONST: { + if (node->constant.value->i.type != NODE_INT) { + PrintError(node->i.err, "Constant value must be integer"); + } + + Const constant; + constant.type = GET_PRIM("__lit", 0); + constant.name = NewString(node->constant.name); + constant.value = (long long) node->constant.value->integer.value; + + State_AddConst(constant); + return GET_PRIM("unit", 0); + } default: { Unexpected(node); } } + assert(0); } diff --git a/basic/source/state.c b/basic/source/state.c index b137474190ac3a1f250a5378eae8bae9353681aa..407217d8c0262973793fc4d43c2a4d9ebe5c5ce7 100644 --- a/basic/source/state.c +++ b/basic/source/state.c @@ -15,6 +15,8 @@ state.typeNum = 0; state.scopes[0] = NULL; state.scopeSize[0] = 0; state.scopeNum = 1; + state.consts = NULL; + state.constNum = 0; } size_t State_AddType(Type type) { @@ -33,6 +35,13 @@ state.scopes[scope] = SafeRealloc( state.scopes[scope], state.scopeSize[scope] * sizeof(Var) ); state.scopes[scope][state.scopeSize[scope] - 1] = var; +} + +void State_AddConst(Const constant) { + ++ state.constNum; + state.consts = SafeRealloc(state.consts, state.constNum * sizeof(Const)); + + state.consts[state.constNum - 1] = constant; } bool State_AddScope(void) { @@ -61,6 +70,16 @@ for (size_t j = 0; j < state.scopeSize[i]; ++ j) { if (strcmp(state.scopes[i][j].name, name) == 0) { return &state.scopes[i][j]; } + } + } + + return NULL; +} + +Const* State_GetConst(const char* name) { + for (size_t i = 0; i < state.constNum; ++ i) { + if (strcmp(state.consts[i].name, name) == 0) { + return &state.consts[i]; } } diff --git a/basic/source/state.h b/basic/source/state.h index d061f217182188b328501d040e97b40a85cf72dc..f7d32e3f1a1dd34bcbab2ae4f26064b6e7e86e89 100644 --- a/basic/source/state.h +++ b/basic/source/state.h @@ -68,11 +68,19 @@ bool isStatic; } Var; typedef struct { + UsedType type; + char* name; + long long value; +} Const; + +typedef struct { Type* types; size_t typeNum; Var* scopes[16]; size_t scopeSize[16]; size_t scopeNum; + Const* consts; + size_t constNum; } State; extern State state; @@ -80,9 +88,11 @@ void State_Init(void); size_t State_AddType(Type type); void State_AddVar(Var var); +void State_AddConst(Const constant); bool State_AddScope(void); void State_FreeScope(void); Var* State_GetVar(const char* name); +Const* State_GetConst(const char* name); Type* State_GetType(const char* name); void State_MakePrimitive(const char* name, size_t size, int primType); bool State_UsedTypeEq(UsedType a, UsedType b); diff --git a/basic/test.bas b/basic/test.bas index 62cae97c6aa1aae3353f57b20ce0c913d4a6663d..a7df0bb0c547a76c9436626fef9eed00a0bf16e6 100644 --- a/basic/test.bas +++ b/basic/test.bas @@ -5,18 +5,6 @@ extern func puts(str as ptr(char)) i32 extern func printf(str as ptr(char), val as int) i32 -func add(a as int, b as int) int - return a + b -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]) - -printf("127 ^ 4 = %d\n", 127 ^ 4) +const FOO_BAR = 5 -dim foo as ptr(unit) +printf("FOO_BAR = %d\n", FOO_BAR) diff --git a/basic-std/std/file.bas b/basic-std/std/file.bas index cd5d4346748ed2c6feacdaf5d6bedf65d357c2ec..9d2e5320c1cb4ccc85b8bc67d7c22998cec93da0 100644 --- a/basic-std/std/file.bas +++ b/basic-std/std/file.bas @@ -2,6 +2,7 @@ 'NITRON extern func fopen(path as ptr(char), mode as ptr(char)) ptr(unit) extern func fclose(file as ptr(unit)) i32 +extern func fread(output as ptr(unit), size as uint, n as uint, file as ptr(unit)) uint type File file as ptr(unit) @@ -30,3 +31,11 @@ func File_Close(this as ptr(File)) bool return fclose(this.file) == 0 end + +func File_Read(this as ptr(File), size as uint, output as ptr(unit)) uint + return fread(output, 1, size, this.file) +end + +func File_Peek(this as ptr(File)) uint + return ftell(this.file) as uint +end