nitron

commit ae2d5ca1d2fe70cb8e914bd6d5131868f38c9641

Author: mesyeti <mesyeti@mesyeti.uk>

hello world achieved

 basic/.gitignore | 2 
 basic/Makefile | 5 
 basic/example.bas | 6 
 basic/source/compiler.c | 80 ++++++++++++
 basic/source/compiler.h | 34 +++++
 basic/source/frontend/c89.c | 222 +++++++++++++++++++++++++++++++++++
 basic/source/frontend/c89.h | 8 +
 basic/source/main.c | 5 
 basic/source/parser.c | 64 ++++++---
 basic/source/parser.h | 9 +
 basic/source/semanticAnalysis.c | 94 ++++++++------
 basic/source/semanticAnalysis.h | 3 
 basic/source/state.c | 4 
 basic/source/state.h | 1 
 basic/test.bas | 19 --


diff --git a/basic/.gitignore b/basic/.gitignore
index 631d23f7093ec4d51a6bf2ededb3b33c0630dd30..b90a85c211481d2cb7ba7b0a32c146c7ad776785 100644
--- a/basic/.gitignore
+++ b/basic/.gitignore
@@ -1 +1,3 @@
 nitronb
+out
+out.c




diff --git a/basic/Makefile b/basic/Makefile
index 785906776db0027224492a1270d26eb186a99c75..50851ae95c50284161fc2542734b430db4db7734 100644
--- a/basic/Makefile
+++ b/basic/Makefile
@@ -37,7 +37,10 @@
 bin/:
 	mkdir -p bin
 
-bin/%.o: source/%.c $(call deps,source/%.c) | bin/
+bin/frontend:
+	mkdir -p bin/frontend
+
+bin/%.o: source/%.c $(call deps,source/%.c) | bin/ bin/frontend
 	$(CC) $(CFLAGS) $(CPPFLAGS) $< -c -o $@
 
 clean:




diff --git a/basic/example.bas b/basic/example.bas
index 2267bac07513ff4c398f934c27ab667969854ed0..3f5370765d92e62b5eed64bb0c6a601a4b0ce3da 100644
--- a/basic/example.bas
+++ b/basic/example.bas
@@ -1,10 +1,8 @@
 'NITRON
 
-extern C func puts(ptr(char)) int
+extern func puts(str as ptr(char)) int
 
 puts "Hello, world!"
 
 dim ret as int
-ret = puts("Hello again, world!")
-
-quit ret
+ret = 4




diff --git a/basic/source/compiler.c b/basic/source/compiler.c
new file mode 100644
index 0000000000000000000000000000000000000000..6ac6c1818c1a418820ccbb9af6385a2f98a33589
--- /dev/null
+++ b/basic/source/compiler.c
@@ -0,0 +1,80 @@
+#include "compiler.h"
+
+static Frontend frontend;
+static Compiler compiler;
+
+void Frontend_Init(Frontend p_frontend) {
+	frontend = p_frontend;
+}
+
+void Frontend_Finish(void) {
+	frontend.finish();
+}
+
+void Frontend_BeginMain(void) {
+	frontend.beginMain();
+}
+
+void Frontend_CompileFuncDef(FuncDefNode* node) {
+	frontend.compileFuncDef(node);
+}
+
+void Frontend_CompileDim(DimNode* node) {
+	frontend.compileDim(node);
+}
+
+void Frontend_CompileFuncCall(FuncCallNode* node) {
+	frontend.compileFuncCall(node);
+}
+
+void Frontend_CompileAssign(AssignNode* node) {
+	frontend.compileAssign(node);
+}
+
+void Frontend_CompileExtern(ExternNode* node) {
+	frontend.compileExtern(node);
+}
+
+void Compiler_Init(Node* nodes, size_t len) {
+	compiler.nodes = nodes;
+	compiler.len   = len;
+}
+
+void Compiler_Compile(Node* node, bool inMain) {
+	if (inMain) {
+		switch (node->i.type) {
+			case NODE_FUNC_DEF:  break;
+			case NODE_DIM:       break;
+			case NODE_FUNC_CALL: Frontend_CompileFuncCall(&node->funcCall); break;
+			case NODE_ASSIGN:    Frontend_CompileAssign(&node->assign); break;
+			case NODE_EXTERN:    Frontend_CompileExtern(&node->external); break;
+			default: {
+				PrintError(node->i.err, "Unexpected '%s'", Parser_TypeStr(node->i.type));
+			}
+		}
+	}
+	else {
+		switch (node->i.type) {
+			case NODE_FUNC_DEF: Frontend_CompileFuncDef(&node->funcDef); break;
+			case NODE_DIM:      Frontend_CompileDim(&node->dim); break;
+			default:            break;
+		}
+	}
+}
+
+void Compiler_Run(void) {
+	for (size_t i = 0; i < compiler.len; ++ i) {
+		Node* node = &compiler.nodes[i];
+		Compiler_Compile(node, false);
+	}
+
+	Frontend_BeginMain();
+
+	for (size_t i = 0; i < compiler.len; ++ i) {
+		Node* node = &compiler.nodes[i];
+
+		Compiler_Compile(node, true);
+	}
+
+	Frontend_Finish();
+}




diff --git a/basic/source/compiler.h b/basic/source/compiler.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d00872338df8c25bdd2f28c73284b786324b51a
--- /dev/null
+++ b/basic/source/compiler.h
@@ -0,0 +1,34 @@
+#ifndef N_COMPILER_H
+#define N_COMPILER_H
+
+#include "parser.h"
+
+typedef struct {
+	void (*finish)(void);
+	void (*beginMain)(void);
+	void (*compileFuncDef)(FuncDefNode* node);
+	void (*compileDim)(DimNode* node);
+	void (*compileFuncCall)(FuncCallNode* node);
+	void (*compileAssign)(AssignNode* node);
+	void (*compileExtern)(ExternNode* node);
+} Frontend;
+
+void Frontend_Init(Frontend p_frontend);
+void Frontend_Finish(void);
+void Frontend_BeginMain(void);
+void Frontend_CompileFuncDef(FuncDefNode* node);
+void Frontend_CompileDim(DimNode* node);
+void Frontend_CompileFuncCall(FuncCallNode* node);
+void Frontend_CompileAssign(AssignNode* node);
+void Frontend_CompileExtern(ExternNode* node);
+
+typedef struct {
+	Node*  nodes;
+	size_t len;
+} Compiler;
+
+void Compiler_Init(Node* nodes, size_t len);
+void Compiler_Compile(Node* node, bool inMain);
+void Compiler_Run(void);
+
+#endif




diff --git a/basic/source/frontend/c89.c b/basic/source/frontend/c89.c
new file mode 100644
index 0000000000000000000000000000000000000000..1cf6d655b1c753f97e829db8fe88c95d50529ef8
--- /dev/null
+++ b/basic/source/frontend/c89.c
@@ -0,0 +1,222 @@
+#include <stdio.h>
+#include <assert.h>
+#include "c89.h"
+#include "../state.h"
+#include "../semanticAnalysis.h"
+
+static FILE* out;
+static bool  inMain;
+
+static void Finish(void) {
+	fprintf(out, "}\n");
+	fflush(out);
+
+	const char* cmd = "gcc out.c -o out";
+	puts(cmd);
+	system(cmd);
+}
+
+static void BeginMain(void) {
+	inMain = true;
+
+	fprintf(out, "int main(int argc, char** argv) {\n");
+}
+
+static void Unexpected(ErrorInfo err, NodeType type) {
+	PrintError(err, "Unexpected '%s'", Parser_TypeStr(type));
+}
+
+static void CompileUsedType(UsedType used) {
+	Type* type = State_GetTypeFromUsed(used);
+
+	fprintf(out, "nitron_%s", type->name);
+
+	for (size_t i = 0; i < used.ptr; ++ i) {
+		fprintf(out, "*");
+	}
+}
+
+static void CompileType(Node* node) {
+	UsedType used = SemanticAnalysis_NodeAsUsedType(node);
+	CompileUsedType(used);
+}
+
+static void CompileDec(FuncDec dec) {
+	if (dec.ret) {
+		CompileType(dec.ret);
+		fprintf(out, " ");
+	}
+	else {
+		fprintf(out, "void ");
+	}
+
+	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);
+
+		if (i < dec.paramsNum - 1) {
+			fprintf(out, ", ");
+		}
+	}
+
+	fprintf(out, ")");
+}
+
+static void CompileFuncDef(FuncDefNode* node) {
+	CompileDec(node->dec);
+	fprintf(out, " {\n");
+
+	for (size_t i = 0; i < node->bodyLen; ++ i) {
+		Compiler_Compile(&node->body[i], false);
+	}
+
+	fprintf(out, "}\n");
+}
+
+static void CompileDim(DimNode* node) {
+	if (inMain) return;
+
+	CompileType(node->varType);
+	fprintf(out, " nitron_%s;\n", node->name);
+}
+
+static void CompileExprNode(Node* node);
+
+static void CompileFuncCallExpr(FuncCallNode* node) {
+	fprintf(out, "%s(", node->func);
+
+	for (size_t i = 0; i < node->paramsNum; ++ i) {
+		CompileExprNode(&node->params[i]);
+
+		if (i < node->paramsNum - 1){
+			fprintf(out, ", ");
+		}
+	}
+
+	fprintf(out, ")");
+}
+
+static void CompileExprNode(Node* node) {
+	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, "nitron_%s", node->ident.name); break;
+		case NODE_BINARY_OP: {
+			fprintf(out, "(");
+			CompileExprNode(node->bin.left);
+
+			switch (node->bin.op) {
+				case TOKEN_ADD:      fprintf(out, "+");  break;
+				case TOKEN_SUBTRACT: fprintf(out, "-");  break;
+				case TOKEN_MULTIPLY: fprintf(out, "*");  break;
+				case TOKEN_DIVIDE:   fprintf(out, "/");  break;
+				case TOKEN_MOD:      fprintf(out, "%%");  break;
+				case TOKEN_EQUAL:    fprintf(out, "=="); break;
+				case TOKEN_LESS:     fprintf(out, "<");  break;
+				case TOKEN_GREATER:  fprintf(out, ">");  break;
+				default:             assert(0);
+			}
+
+			CompileExprNode(node->bin.right);
+			fprintf(out, ")");
+			break;
+		}
+		case NODE_UNARY_OP: {
+			fprintf(out, "(");
+
+			switch (node->unary.op) {
+				case TOKEN_ADD:      fprintf(out, "+"); break;
+				case TOKEN_SUBTRACT: fprintf(out, "-"); break;
+				default: assert(0);
+			}
+
+			fprintf(out, ")");
+			break;
+		}
+		case NODE_FUNC_CALL: CompileFuncCallExpr(&node->funcCall); break;
+		default: assert(0);
+	}
+}
+
+static void CompileFuncCall(FuncCallNode* node) {
+	CompileFuncCallExpr(node);
+	fprintf(out, ";\n");
+}
+
+static void CompileAssign(AssignNode* node) {
+	
+}
+
+static void CompileExtern(ExternNode* node) {
+	CompileDec(node->dec);
+	fprintf(out, ";\n");
+}
+
+static void CompilePrim(Type* type) {
+	switch (type->primType) {
+		case PRIM_UINT: {
+			switch (type->size) {
+				case 1: fprintf(out, "typedef uint8_t nitron_%s;\n", type->name); break;
+				case 2: fprintf(out, "typedef uint16_t nitron_%s;\n", type->name); break;
+				case 4: fprintf(out, "typedef uint32_t nitron_%s;\n", type->name); break;
+				case 8: fprintf(out, "typedef uint64_t nitron_%s;\n", type->name); break;
+			}
+			break;
+		}
+		case PRIM_INT: {
+			switch (type->size) {
+				case 1: fprintf(out, "typedef int8_t nitron_%s;\n", type->name); break;
+				case 2: fprintf(out, "typedef int16_t nitron_%s;\n", type->name); break;
+				case 4: fprintf(out, "typedef int32_t nitron_%s;\n", type->name); break;
+				case 8: fprintf(out, "typedef int64_t nitron_%s;\n", type->name); break;
+			}
+			break;
+		}
+		case PRIM_FLOAT: {
+			switch (type->size) {
+				case 4: fprintf(out, "typedef float nitron_%s;\n", type->name); break;
+				case 8: fprintf(out, "typedef double nitron_%s;\n", type->name); break;
+			}
+			break;
+		}
+	}
+}
+
+Frontend Frontend_C89(void) {
+	out    = fopen("out.c", "w");
+	inMain = false;
+
+	fprintf(out, "#include <stdint.h>\n");
+	fprintf(out, "#include <stdlib.h>\n");
+
+	// define all types
+	for (size_t i = 0; i < state.typeNum; ++ i) {
+		Type* type = &state.types[i];
+
+		switch (type->type) {
+			case TYPE_PRIM: CompilePrim(type); break;
+			case TYPE_UNIT: break;
+			default: assert(0);
+		}
+	}
+
+	// declare all globals
+	for (size_t i = 0; i < state.scopeSize[0]; ++ i) {
+		Var* var = &state.scopes[0][i];
+
+		CompileUsedType(var->type);
+		fprintf(out, " nitron_%s;\n", var->name);
+	}
+
+	return (Frontend) {
+		.finish          = &Finish,
+		.beginMain       = &BeginMain,
+		.compileFuncDef  = &CompileFuncDef,
+		.compileDim      = &CompileDim,
+		.compileFuncCall = &CompileFuncCall,
+		.compileAssign   = &CompileAssign,
+		.compileExtern   = &CompileExtern
+	};
+}




diff --git a/basic/source/frontend/c89.h b/basic/source/frontend/c89.h
new file mode 100644
index 0000000000000000000000000000000000000000..6edada43c8f3f07c258e762f901b999433737a98
--- /dev/null
+++ b/basic/source/frontend/c89.h
@@ -0,0 +1,8 @@
+#ifndef N_FRONTEND_C89_H
+#define N_FRONTEND_C89_H
+
+#include "../compiler.h"
+
+Frontend Frontend_C89(void);
+
+#endif




diff --git a/basic/source/main.c b/basic/source/main.c
index a8e3fa95d0afaa3a9ac44b0c75f86f336a150b30..6c2baa46efe19dc613bea1c4f69f295514d9fa0a 100644
--- a/basic/source/main.c
+++ b/basic/source/main.c
@@ -5,6 +5,7 @@ #include "state.h"
 #include "parser.h"
 #include "common.h"
 #include "semanticAnalysis.h"
+#include "frontend/c89.h"
 
 int main(int argc, char** argv) {
 	const char* source = NULL;
@@ -70,7 +71,9 @@ 	for (size_t i = 0; i < len; ++ i){
 		SemanticAnalysis_Analyse(&ret[i]);
 	}
 
-	State_DumpInfo();
+	Compiler_Init(ret, len);
+	Frontend_Init(Frontend_C89());
+	Compiler_Run();
 
 	return 0;
 }




diff --git a/basic/source/parser.c b/basic/source/parser.c
index 2ae234724509cccb38c4a2cc5db7aacef610e5c1..d8fe1957fdb7a916fb3bef3758776721086b4de5 100644
--- a/basic/source/parser.c
+++ b/basic/source/parser.c
@@ -428,11 +428,24 @@ 	node.assign = ret;
 	return node;
 }
 
+static Node ParseExtern(Parser* p) {
+	Advance(p);
+
+	ExternNode ret;
+	ret.i   = INFO(NODE_EXTERN);
+	ret.dec = ParseFuncDec(p);
+
+	Node node;
+	node.external = ret;
+	return node;
+}
+
 static Node ParseNode(Parser* p) {
 	switch (p->tokens[p->i].type) {
 		case TOKEN_FUNC:
-		case TOKEN_SUB: return ParseFuncDef(p);
-		case TOKEN_DIM: return ParseDim(p);
+		case TOKEN_SUB:    return ParseFuncDef(p);
+		case TOKEN_DIM:    return ParseDim(p);
+		case TOKEN_EXTERN: return ParseExtern(p);
 		case TOKEN_IDENTIFIER: {
 			if (p->i == p->tokenNum - 1) {
 				PrintError(p->tokens[p->i].err, "Unexpected EOF");
@@ -454,6 +467,28 @@ 		}
 	}
 }
 
+static void PrintDec(FuncDec dec) {
+	if (dec.ret) {
+		printf("func ");
+	}
+	else {
+		printf("sub ");
+	}
+
+	printf("%s(", dec.name);
+
+	for (size_t i = 0; i < dec.paramsNum; ++ i) {
+		printf("%s as ", dec.params[i].name);
+		Parser_PrintNode(dec.params[i].type);
+
+		if (i < dec.paramsNum - 1) {
+			printf(", ");
+		}
+	}
+
+	printf(")\n");
+}
+
 void Parser_PrintNode(Node* node) {
 	switch (node->i.type) {
 		case NODE_INT: printf("%d", node->integer.value); break;
@@ -498,25 +533,7 @@ 			Parser_PrintNode(node->ptr.inner);
 			break;
 		}
 		case NODE_FUNC_DEF: {
-			if (node->funcDef.dec.ret) {
-				printf("func ");
-			}
-			else {
-				printf("sub ");
-			}
-
-			printf("%s(", node->funcDef.dec.name);
-
-			for (size_t i = 0; i < node->funcDef.dec.paramsNum; ++ i) {
-				printf("%s as ", node->funcDef.dec.params[i].name);
-				Parser_PrintNode(node->funcDef.dec.params[i].type);
-
-				if (i < node->funcDef.dec.paramsNum - 1) {
-					printf(", ");
-				}
-			}
-
-			printf(")\n");
+			PrintDec(node->funcDef.dec);
 
 			for (size_t i = 0; i < node->funcDef.bodyLen; ++ i) {
 				printf("\t");
@@ -549,6 +566,11 @@ 		case NODE_ASSIGN: {
 			printf("%s = ", node->assign.variable);
 			Parser_PrintNode(node->assign.rValue);
 			puts("");
+			break;
+		}
+		case NODE_EXTERN: {
+			printf("extern ");
+			PrintDec(node->external.dec);
 			break;
 		}
 		default: {




diff --git a/basic/source/parser.h b/basic/source/parser.h
index 9e643df70c4de70613cbcd791b17f86efca21126..2a3183738fdda807fa4471325c70c89e02a7ce9b 100644
--- a/basic/source/parser.h
+++ b/basic/source/parser.h
@@ -16,7 +16,8 @@ 	NODE_PTR,
 	NODE_FUNC_DEF,
 	NODE_DIM,
 	NODE_FUNC_CALL,
-	NODE_ASSIGN
+	NODE_ASSIGN,
+	NODE_EXTERN
 } NodeType;
 
 typedef struct {
@@ -97,6 +98,11 @@ 	char*    variable;
 	Node*    rValue;
 } AssignNode;
 
+typedef struct {
+	NodeInfo i;
+	FuncDec  dec;
+} ExternNode;
+
 union Node {
 	NodeInfo       i;
 	IntNode        integer;
@@ -109,6 +115,7 @@ 	FuncDefNode    funcDef;
 	DimNode        dim;
 	FuncCallNode   funcCall;
 	AssignNode     assign;
+	ExternNode     external;
 };
 
 typedef struct {




diff --git a/basic/source/semanticAnalysis.c b/basic/source/semanticAnalysis.c
index c275153bb71bcc85fc06e2e5a9372f795796eb04..7a6ca3ddc77eca434ebfe3d4384815fc9c2fbe7f 100644
--- a/basic/source/semanticAnalysis.c
+++ b/basic/source/semanticAnalysis.c
@@ -46,7 +46,7 @@ void Unexpected(Node* node) {
 	PrintError(node->i.err, "Unexpected %s", Parser_TypeStr(node->i.type));
 }
 
-static UsedType NodeAsUsedType(Node* node) {
+UsedType SemanticAnalysis_NodeAsUsedType(Node* node) {
 	UsedType ret;
 	ret.ptr   = 0;
 	ret.array = false; // no arrays yet
@@ -76,21 +76,15 @@ 		}
 	}
 }
 
-static Type* GetTypeFromUsed(UsedType type) {
-	return &state.types[type.typeIdx];
-}
-
 #define GET_PRIM(NAME, PTR) \
 	((UsedType) {(PTR), State_GetType(NAME) - state.types, 0})
 
-static UsedType EvalType(Node* node);
-
 static UsedType EvalBinOp(Node* node) {
-	UsedType left  = EvalType(node->bin.left);
-	UsedType right = EvalType(node->bin.right);
+	UsedType left  = SemanticAnalysis_EvalType(node->bin.left);
+	UsedType right = SemanticAnalysis_EvalType(node->bin.right);
 
-	Type* leftType  = GetTypeFromUsed(left);
-	Type* rightType = GetTypeFromUsed(right);
+	Type* leftType  = State_GetTypeFromUsed(left);
+	Type* rightType = State_GetTypeFromUsed(right);
 
 	if ((leftType->type != TYPE_PRIM) || (rightType->type != TYPE_PRIM)) {
 		PrintError(node->i.err, "You can only use primitive types in binary expressions");
@@ -198,7 +192,29 @@
 	exit(1);
 }
 
-static UsedType EvalType(Node* node) {
+static Function DecToFunc(FuncDec dec) {
+	Function func;
+	func.sub = dec.ret != NULL;
+
+	if (!func.sub) {
+		func.ret = SemanticAnalysis_NodeAsUsedType(dec.ret);
+	}
+
+	func.paramsLen = dec.paramsNum;
+	func.params    = SafeMalloc(func.paramsLen * sizeof(FuncParam));
+
+	for (size_t i = 0; i < func.paramsLen; ++ i) {
+		func.params[i].type = SemanticAnalysis_NodeAsUsedType(
+			dec.params[i].type
+		);
+		func.params[i].name = dec.params[i].name;
+	}
+
+	func.name = NewString(dec.name);
+	return func;
+}
+
+UsedType SemanticAnalysis_EvalType(Node* node) {
 	static bool inFunc = false;
 
 	switch (node->i.type) {
@@ -217,8 +233,8 @@ 			return var->type;
 		}
 		case NODE_BINARY_OP: return EvalBinOp(node);
 		case NODE_UNARY_OP: {
-			UsedType operand = EvalType(node->unary.operand);
-			Type*    type    = GetTypeFromUsed(operand);
+			UsedType operand = SemanticAnalysis_EvalType(node->unary.operand);
+			Type*    type    = State_GetTypeFromUsed(operand);
 
 			if (type->type != TYPE_PRIM) {
 				PrintError(node->i.err,
@@ -233,7 +249,7 @@
 			return operand;
 		}
 		case NODE_PTR: {
-			UsedType type = EvalType(node->ptr.inner);
+			UsedType type = SemanticAnalysis_EvalType(node->ptr.inner);
 			++ type.ptr;
 			return type;
 		}
@@ -242,24 +258,7 @@ 			if (inFunc) {
 				PrintError(node->i.err, "Nested function definitions are not allowed");
 			}
 
-			Function func;
-			func.sub = node->funcDef.dec.ret != NULL;
-
-			if (!func.sub) {
-				func.ret = NodeAsUsedType(node->funcDef.dec.ret);
-			}
-
-			func.paramsLen = node->funcDef.dec.paramsNum;
-			func.params    = SafeMalloc(func.paramsLen * sizeof(FuncParam));
-
-			for (size_t i = 0; i < func.paramsLen; ++ i) {
-				func.params[i].type = NodeAsUsedType(
-					node->funcDef.dec.params[i].type
-				);
-				func.params[i].name = node->funcDef.dec.params[i].name;
-			}
-
-			func.name = NewString(node->funcDef.dec.name);
+			Function func = DecToFunc(node->funcDef.dec);
 			State_AddFunc(func);
 
 			// now analyse the body
@@ -275,7 +274,7 @@ 				State_AddVar(var);
 			}
 
 			for (size_t i = 0; i < node->funcDef.bodyLen; ++ i) {
-				EvalType(&node->funcDef.body[i]);
+				SemanticAnalysis_EvalType(&node->funcDef.body[i]);
 			}
 			inFunc = false;
 			State_FreeScope();
@@ -295,10 +294,10 @@ 				);
 			}
 
 			for (size_t i = 0; i < func->paramsLen; ++ i) {
-				UsedType type      = EvalType(&node->funcCall.params[i]);
+				UsedType type      = SemanticAnalysis_EvalType(&node->funcCall.params[i]);
 				UsedType param     = func->params[i].type;
-				Type*    paramType = GetTypeFromUsed(param);
-				Type*    callType  = GetTypeFromUsed(type);
+				Type*    paramType = State_GetTypeFromUsed(param);
+				Type*    callType  = State_GetTypeFromUsed(type);
 
 				bool paramLit = strcmp(callType->name, "__lit") == 0;
 
@@ -329,7 +328,7 @@ 			}
 		}
 		case NODE_DIM: {
 			Var var;
-			var.type = NodeAsUsedType(node->dim.varType);
+			var.type = SemanticAnalysis_NodeAsUsedType(node->dim.varType);
 			var.name = NewString(node->dim.name);
 			State_AddVar(var);
 			return GET_PRIM("unit", 0);
@@ -345,10 +344,10 @@ 				);
 			}
 
 			UsedType left  = var->type;
-			UsedType right = EvalType(node->assign.rValue);
+			UsedType right = SemanticAnalysis_EvalType(node->assign.rValue);
 
-			Type* leftType  = GetTypeFromUsed(left);
-			Type* rightType = GetTypeFromUsed(right);
+			Type* leftType  = State_GetTypeFromUsed(left);
+			Type* rightType = State_GetTypeFromUsed(right);
 
 			bool compatible = true;
 
@@ -363,12 +362,21 @@
 			if (!compatible) {
 				PrintError(
 					node->i.err, "Type '%s' cannot be assigned to '%s' variable",
-					GetTypeFromUsed(left)->name, GetTypeFromUsed(right)->name
+					State_GetTypeFromUsed(left)->name, State_GetTypeFromUsed(right)->name
 				);
 			}
 
 			return GET_PRIM("unit", 0);
 		}
+		case NODE_EXTERN: {
+			if (inFunc) {
+				PrintError(node->i.err, "Nested function definitions are not allowed");
+			}
+
+			Function func = DecToFunc(node->funcDef.dec);
+			State_AddFunc(func);
+			return GET_PRIM("unit", 0);
+		}
 		default: {
 			Unexpected(node);
 		}
@@ -378,5 +386,5 @@ 	assert(0);
 }
 
 void SemanticAnalysis_Analyse(Node* node) {
-	EvalType(node);
+	SemanticAnalysis_EvalType(node);
 }




diff --git a/basic/source/semanticAnalysis.h b/basic/source/semanticAnalysis.h
index 341ccb8ac4a96ebcd1d94b58b4aad9fa914a881e..b6b03e78938a703a3ad6b14b48db10a91cc0ee84 100644
--- a/basic/source/semanticAnalysis.h
+++ b/basic/source/semanticAnalysis.h
@@ -6,4 +6,7 @@
 void SemanticAnalysis_Init(size_t wordSize);
 void SemanticAnalysis_Analyse(Node* node);
 
+UsedType SemanticAnalysis_NodeAsUsedType(Node* node);
+UsedType SemanticAnalysis_EvalType(Node* node);
+
 #endif




diff --git a/basic/source/state.c b/basic/source/state.c
index c2d901ca81d47638cf32a652631f8562859bda74..e3af9ad34f6183431adfe58cb1b6f1f8a5882b05 100644
--- a/basic/source/state.c
+++ b/basic/source/state.c
@@ -125,3 +125,7 @@ 		printf("- %s\n", state.funcs[i].name);
 	}
 	puts("\n");
 }
+
+Type* State_GetTypeFromUsed(UsedType type) {
+	return &state.types[type.typeIdx];
+}




diff --git a/basic/source/state.h b/basic/source/state.h
index bff6a6faeea769784107c85cb53b3b8e1e1da066..fcdc210ea2c966a5ad728911dd116899fd68d4b9 100644
--- a/basic/source/state.h
+++ b/basic/source/state.h
@@ -76,5 +76,6 @@ Function* State_GetFunc(const char* name);
 void      State_MakePrimitive(const char* name, size_t size, int primType);
 bool      State_UsedTypeEq(UsedType a, UsedType b);
 void      State_DumpInfo(void);
+Type*     State_GetTypeFromUsed(UsedType type);
 
 #endif




diff --git a/basic/test.bas b/basic/test.bas
index af13a8b74c4cbcb49dd5ac303c39c0578ebf48fb..f8cce0e700c79dff0671a0cf3685cc543aeb28fe 100644
--- a/basic/test.bas
+++ b/basic/test.bas
@@ -1,20 +1,5 @@
 'NITRON
 
-dim foo as int
-
-func manul(foo as int, bar as int) int
-	dim bar as u32
-end
+extern func puts(str as ptr(char)) int
 
-manul 1, (2 * 3) + -5 * 4
-
-foo = 3 + 4
-
-dim a as int
-dim b as f32
-dim c as int
-
-manul a + c, 5
-
-dim myPtr as ptr(int)
-myPtr = myPtr * 5
+puts "Hello, world!"