nitron

commit 448c6fe50571f5468f418821b0635b1c446f0220

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