nitron

commit eec07557659c0356dc5c2f982e7fee16533cc2ed

Author: mesyeti <mesyeti@mesyeti.uk>

progress

 basic-boot/source/error.c | 45 +++
 basic-boot/source/error.h | 13 +
 basic-boot/source/lexer.c | 142 +++++++-----
 basic-boot/source/lexer.h | 20 +
 basic-boot/source/main.c | 21 -
 basic-boot/source/parser.c | 464 +++++++++++++++++++++++++++++++++------
 basic-boot/source/parser.h | 80 +++++-
 basic-boot/source/util.c | 1 
 basic-boot/source/util.h | 7 
 basic-boot/test.bas | 13 +


diff --git a/basic-boot/source/error.c b/basic-boot/source/error.c
new file mode 100644
index 0000000000000000000000000000000000000000..bb331eb8faa5d914f58d3ac7e7afe8ccc14b2b96
--- /dev/null
+++ b/basic-boot/source/error.c
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include "mem.h"
+#include "error.h"
+
+void PrintError(ErrorInfo err, const char* format, ...) {
+	char* ret = NULL;
+
+	int     n    = 0; 
+	size_t  size = 0; 
+	va_list ap; 
+
+	va_start(ap, format); 
+	n = vsnprintf(ret, size, format, ap); 
+	va_end(ap); 
+
+	assert(n >= 0); 
+
+	size = n + 1; 
+	ret = (char*) SafeMalloc(size); 
+	if (ret == NULL) { 
+		return; 
+	} 
+
+	va_start(ap, format); 
+	n = vsnprintf(ret, size, format, ap); 
+	va_end(ap); 
+
+	assert(n >= 0); 
+
+	#if 0
+		fprintf(stderr, "error: %s:%d: %s\n", err.file, (int) err.line, ret);
+	#else
+		#define RED   "\x1b[31m"
+		#define BLUE  "\x1b[34m"
+		#define RESET "\x1b[0m"
+		fprintf(
+			stderr, RED "error: " BLUE "%s:%d: " RESET "%s\n",
+			err.file, (int) err.line, ret
+		);
+	#endif
+
+	exit(1);
+}




diff --git a/basic-boot/source/error.h b/basic-boot/source/error.h
new file mode 100644
index 0000000000000000000000000000000000000000..e443d59abce632c0afc88b29cef90aeb7e064ffc
--- /dev/null
+++ b/basic-boot/source/error.h
@@ -0,0 +1,13 @@
+#ifndef N_ERROR_H
+#define N_ERROR_H
+
+#include "common.h"
+
+typedef struct {
+	const char* file;
+	size_t      line;
+} ErrorInfo;
+
+void PrintError(ErrorInfo err, const char* format, ...);
+
+#endif




diff --git a/basic-boot/source/lexer.c b/basic-boot/source/lexer.c
index 9124080b5035f0d28b8fc73f544990c85c4df3aa..4a7d7cfb66bad3283a4d8110e80d10d85210d0d4 100644
--- a/basic-boot/source/lexer.c
+++ b/basic-boot/source/lexer.c
@@ -1,11 +1,15 @@
 #include <stdio.h>
+#include <assert.h>
 #include <string.h>
 #include "lexer.h"
 #include "string.h"
 
-Lexer Lexer_Init(FILE* file) {
+Lexer Lexer_Init(FILE* file, const char* fileName) {
 	Lexer lexer;
-	lexer.file = file;
+	lexer.file     = file;
+	lexer.success  = true;
+	lexer.fileName = fileName;
+	lexer.line     = 1;
 	return lexer;
 }
 
@@ -45,16 +49,26 @@ 	return true;
 }
 
 #define GET_CHAR(VAR) \
-	if (fread(&VAR, 1, 1, lexer->file) != 1) { \
-		return LEXER_EOF; \
-	}
+	do { \
+		if (fread(&VAR, 1, 1, lexer->file) != 1) { \
+			return LEXER_EOF; \
+		} \
+		if (VAR == '\n') ++ lexer->line; \
+	} while (0);
 
 #define GET_CHAR_ERROR(VAR) \
-	if (fread(&VAR, 1, 1, lexer->file) != 1) { \
-		fprintf(stderr, "Unexpected EOF\n"); \
-		lexer->success = false; \
-		return LEXER_EOF; \
-	}
+	do { \
+		if (fread(&VAR, 1, 1, lexer->file) != 1) { \
+			ErrorInfo err = {lexer->fileName, lexer->line}; \
+			PrintError(err, "Unexpected EOF"); \
+			lexer->success = false; \
+			return LEXER_EOF; \
+		} \
+		if (VAR == '\n') ++ lexer->line; \
+	} while (0);
+
+#define TOKEN(TYPE, CONTENTS) ((Token) \
+	{(TYPE), (ErrorInfo) {lexer->fileName, lexer->line}, (CONTENTS)})
 
 int Lexer_Next(Lexer* lexer, Token* token) {
 	char ch;
@@ -72,26 +86,29 @@
 				String_AddChar(&string, ch);
 			}
 
-			*token = (Token) {TOKEN_STRING, string.contents};
+			*token = TOKEN(TOKEN_STRING, string.contents);
 			return LEXER_TOKEN;
 		}
-		case '(':  *token = (Token) {TOKEN_LPAREN,   NULL}; return LEXER_TOKEN;
-		case ')':  *token = (Token) {TOKEN_RPAREN,   NULL}; return LEXER_TOKEN;
-		case ',':  *token = (Token) {TOKEN_COMMA,    NULL}; return LEXER_TOKEN;
-		case '+':  *token = (Token) {TOKEN_ADD,      NULL}; return LEXER_TOKEN;
-		case '-':  *token = (Token) {TOKEN_SUBTRACT, NULL}; return LEXER_TOKEN;
-		case '*':  *token = (Token) {TOKEN_MULTIPLY, NULL}; return LEXER_TOKEN;
-		case '/':  *token = (Token) {TOKEN_DIVIDE,   NULL}; return LEXER_TOKEN;
-		case '%':  *token = (Token) {TOKEN_MOD,      NULL}; return LEXER_TOKEN;
-		case '=':  *token = (Token) {TOKEN_EQUAL,    NULL}; return LEXER_TOKEN;
-		case '<':  *token = (Token) {TOKEN_LESS,     NULL}; return LEXER_TOKEN;
-		case '>':  *token = (Token) {TOKEN_GREATER,  NULL}; return LEXER_TOKEN;
-		case '\n': *token = (Token) {TOKEN_LINE,     NULL}; return LEXER_TOKEN;
+		case '(':  *token = TOKEN(TOKEN_LPAREN,   NULL); return LEXER_TOKEN;
+		case ')':  *token = TOKEN(TOKEN_RPAREN,   NULL); return LEXER_TOKEN;
+		case ',':  *token = TOKEN(TOKEN_COMMA,    NULL); return LEXER_TOKEN;
+		case '+':  *token = TOKEN(TOKEN_ADD,      NULL); return LEXER_TOKEN;
+		case '-':  *token = TOKEN(TOKEN_SUBTRACT, NULL); return LEXER_TOKEN;
+		case '*':  *token = TOKEN(TOKEN_MULTIPLY, NULL); return LEXER_TOKEN;
+		case '/':  *token = TOKEN(TOKEN_DIVIDE,   NULL); return LEXER_TOKEN;
+		case '%':  *token = TOKEN(TOKEN_MOD,      NULL); return LEXER_TOKEN;
+		case '=':  *token = TOKEN(TOKEN_EQUAL,    NULL); return LEXER_TOKEN;
+		case '<':  *token = TOKEN(TOKEN_LESS,     NULL); return LEXER_TOKEN;
+		case '>':  *token = TOKEN(TOKEN_GREATER,  NULL); return LEXER_TOKEN;
+		case '\n': *token = TOKEN(TOKEN_LINE,     NULL); return LEXER_TOKEN;
 		case '\'': {
 			while (true) {
 				GET_CHAR(ch);
 
-				if (ch == '\n') return LEXER_NONE;
+				if (ch == '\n') {
+					fseek(lexer->file, -1, SEEK_CUR);
+					return LEXER_NONE;
+				}
 			}
 			return LEXER_EOF;
 		}
@@ -112,76 +129,83 @@ 				String_AddChar(&string, ch);
 			}
 
 			if (IsNumeric(string.contents)) {
-				*token = (Token) {TOKEN_INT, string.contents};
+				*token = TOKEN(TOKEN_INT, string.contents);
 				return LEXER_TOKEN;
 			}
 			if (!strcmp(string.contents, "extern")) {
-				*token = (Token) {TOKEN_EXTERN, NULL};
+				*token = TOKEN(TOKEN_EXTERN, NULL);
 				String_Free(&string);
 				return LEXER_TOKEN;
 			}
 			if (!strcmp(string.contents, "func") || !strcmp(string.contents, "function")) {
-				*token = (Token) {TOKEN_FUNC, NULL};
+				*token = TOKEN(TOKEN_FUNC, NULL);
 				String_Free(&string);
 				return LEXER_TOKEN;
 			}
 			if (!strcmp(string.contents, "sub")) {
-				*token = (Token) {TOKEN_SUB, NULL};
+				*token = TOKEN(TOKEN_SUB, NULL);
 				String_Free(&string);
 				return LEXER_TOKEN;
 			}
 			if (!strcmp(string.contents, "dim")) {
-				*token = (Token) {TOKEN_DIM, NULL};
+				*token = TOKEN(TOKEN_DIM, NULL);
 				String_Free(&string);
 				return LEXER_TOKEN;
 			}
 			if (!strcmp(string.contents, "as")) {
-				*token = (Token) {TOKEN_AS, NULL};
+				*token = TOKEN(TOKEN_AS, NULL);
 				String_Free(&string);
 				return LEXER_TOKEN;
 			}
 			if (!strcmp(string.contents, "quit")) {
-				*token = (Token) {TOKEN_QUIT, NULL};
+				*token = TOKEN(TOKEN_QUIT, NULL);
+				String_Free(&string);
+				return LEXER_TOKEN;
+			}
+			if (!strcmp(string.contents, "end")) {
+				*token = TOKEN(TOKEN_END, NULL);
 				String_Free(&string);
 				return LEXER_TOKEN;
 			}
 
-			*token = (Token) {TOKEN_IDENTIFIER, string.contents};
+			*token = TOKEN(TOKEN_IDENTIFIER, string.contents);
 			return LEXER_TOKEN;
 		}
 	}
 }
 
-void Lexer_PrintToken(Token* token) {
-	const char* typeStr = NULL;
-
+const char* Lexer_TypeAsString(Token* token) {
 	switch (token->type) {
-		case TOKEN_NULL:       typeStr = "null"; break;
-		case TOKEN_EXTERN:     typeStr = "extern"; break;
-		case TOKEN_FUNC:       typeStr = "func"; break;
-		case TOKEN_SUB:        typeStr = "sub"; break;
-		case TOKEN_DIM:        typeStr = "dim"; break;
-		case TOKEN_AS:         typeStr = "as"; break;
-		case TOKEN_QUIT:       typeStr = "quit"; break;
-		case TOKEN_PTR:        typeStr = "ptr"; break;
-		case TOKEN_IDENTIFIER: typeStr = "identifier"; break;
-		case TOKEN_STRING:     typeStr = "string"; break;
-		case TOKEN_INT:        typeStr = "int"; break;
-		case TOKEN_LINE:       typeStr = "line"; break;
-		case TOKEN_LPAREN:     typeStr = "lparen"; break;
-		case TOKEN_RPAREN:     typeStr = "rparen"; break;
-		case TOKEN_COMMA:      typeStr = "comma"; break;
-		case TOKEN_ADD:        typeStr = "add"; break;
-		case TOKEN_SUBTRACT:   typeStr = "subtract"; break;
-		case TOKEN_MULTIPLY:   typeStr = "multiply"; break;
-		case TOKEN_DIVIDE:     typeStr = "divide"; break;
-		case TOKEN_MOD:        typeStr = "mod"; break;
-		case TOKEN_EQUAL:      typeStr = "equal"; break;
-		case TOKEN_LESS:       typeStr = "less"; break;
-		case TOKEN_GREATER:    typeStr = "greater"; break;
+		case TOKEN_NULL:       return "null";
+		case TOKEN_EXTERN:     return "extern";
+		case TOKEN_FUNC:       return "func";
+		case TOKEN_SUB:        return "sub";
+		case TOKEN_DIM:        return "dim";
+		case TOKEN_AS:         return "as";
+		case TOKEN_QUIT:       return "quit";
+		case TOKEN_PTR:        return "ptr";
+		case TOKEN_END:        return "end";
+		case TOKEN_IDENTIFIER: return "identifier";
+		case TOKEN_STRING:     return "string";
+		case TOKEN_INT:        return "int";
+		case TOKEN_LINE:       return "line";
+		case TOKEN_LPAREN:     return "lparen";
+		case TOKEN_RPAREN:     return "rparen";
+		case TOKEN_COMMA:      return "comma";
+		case TOKEN_ADD:        return "add";
+		case TOKEN_SUBTRACT:   return "subtract";
+		case TOKEN_MULTIPLY:   return "multiply";
+		case TOKEN_DIVIDE:     return "divide";
+		case TOKEN_MOD:        return "mod";
+		case TOKEN_EQUAL:      return "equal";
+		case TOKEN_LESS:       return "less";
+		case TOKEN_GREATER:    return "greater";
+		default:               assert(0);
 	}
+}
 
-	printf("%s: %s\n", typeStr, token->contents);
+void Lexer_PrintToken(Token* token) {
+	printf("%s: %s\n", Lexer_TypeAsString(token), token->contents);
 }
 
 void Lexer_FreeToken(Token* token) {




diff --git a/basic-boot/source/lexer.h b/basic-boot/source/lexer.h
index cab9d32a9c3845510fa51650a411902537564ec3..039cf9d70327e5061db6802f9dfdb08abc5491e2 100644
--- a/basic-boot/source/lexer.h
+++ b/basic-boot/source/lexer.h
@@ -1,6 +1,7 @@
 #ifndef N_LEXER_H
 #define N_LEXER_H
 
+#include "error.h"
 #include "common.h"
 
 typedef enum {
@@ -14,6 +15,7 @@ 	TOKEN_DIM,
 	TOKEN_AS,
 	TOKEN_QUIT,
 	TOKEN_PTR,
+	TOKEN_END,
 
 	// misc
 	TOKEN_IDENTIFIER,
@@ -45,18 +47,22 @@ };
 
 typedef struct {
 	TokenType type;
+	ErrorInfo err;
 	char*     contents;
 } Token;
 
 typedef struct {
-	FILE* file;
-	bool  success;
+	FILE*       file;
+	bool        success;
+	const char* fileName;
+	size_t      line;
 } Lexer;
 
-Lexer Lexer_Init(FILE* file);
-void  Lexer_Free(Lexer* lexer);
-int   Lexer_Next(Lexer* lexer, Token* token);
-void  Lexer_PrintToken(Token* token);
-void  Lexer_FreeToken(Token* token);
+Lexer       Lexer_Init(FILE* file, const char* fileName);
+void        Lexer_Free(Lexer* lexer);
+int         Lexer_Next(Lexer* lexer, Token* token);
+const char* Lexer_TypeAsString(Token* token);
+void        Lexer_PrintToken(Token* token);
+void        Lexer_FreeToken(Token* token);
 
 #endif




diff --git a/basic-boot/source/main.c b/basic-boot/source/main.c
index 84bde89a30781c8e37196acda829ebddba9d3909..72c0dc0bfe9064fe3d305ded3c7091d1e0f7ec1b 100644
--- a/basic-boot/source/main.c
+++ b/basic-boot/source/main.c
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include "lexer.h"
+#include "parser.h"
 #include "common.h"
 
 int main(int argc, char** argv) {
@@ -38,24 +39,14 @@ 		fprintf(stderr, "Failed to open '%s'\n", source);
 		return 1;
 	}
 
-	Lexer lexer = Lexer_Init(sourceFile);
-
-	while (true) {
-		Token token;
+	Parser parser = Parser_Init(sourceFile, source);
 
-		int status = Lexer_Next(&lexer, &token);
+	size_t len;
+	Node*  ret = Parser_Parse(&parser, &len) ;
 
-		switch (status) {
-			case LEXER_TOKEN: {
-				Lexer_PrintToken(&token);
-				Lexer_FreeToken(&token);
-				break;
-			}
-			case LEXER_EOF:  goto end;
-			case LEXER_NONE: continue;
-		}
+	for (size_t i = 0; i < len; ++ i) {
+		Parser_PrintNode(&ret[i]);
 	}
-	end:
 
 	return 0;
 }




diff --git a/basic-boot/source/parser.c b/basic-boot/source/parser.c
index 799644e88061f7368948f83e2255a1c63fd270c3..904fc2179307fb02c938aba36b03b6acf92c1c16 100644
--- a/basic-boot/source/parser.c
+++ b/basic-boot/source/parser.c
@@ -1,9 +1,12 @@
+#include <assert.h>
+#include <string.h>
+#include "mem.h"
 #include "util.h"
 #include "parser.h"
 
-void Parser_Init(FILE* file) {
+Parser Parser_Init(FILE* file, const char* fileName) {
 	Parser ret;
-	Lexer  lexer = Lexer_Init(file);
+	Lexer  lexer = Lexer_Init(file, fileName);
 
 	Token* tokens    = SafeMalloc(64 * sizeof(Token));
 	size_t tokensLen = 0;
@@ -31,31 +34,40 @@ 			case LEXER_NONE: continue;
 		}
 	}
 
-	tokens        = SafeRealloc(tokens, tokensLen * sizeof(Token));
-	ret.tokens    = tokens;
-	ret.tokensNum = tokensLen;
-	ret.i         = 0;
+	tokens       = SafeRealloc(tokens, tokensLen * sizeof(Token));
+	ret.tokens   = tokens;
+	ret.tokenNum = tokensLen;
+	ret.i        = 0;
+
+	// for (size_t i = 0; i < tokensLen; ++ i) {
+	// 	Lexer_PrintToken(&tokens[i]);
+	// }
 	return ret;
 }
 
+#define INFO(TYPE) ((NodeInfo) {TYPE, p->tokens[p->i].err})
+
+static Node ParseBinary(Parser* p);
+static Node ParseNode(Parser* p);
+
 static void Advance(Parser* p) {
 	++ p->i;
+
 	if (p->i >= p->tokenNum) {
-		assert(0); // TODO: error
+		PrintError(p->tokens[p->tokenNum - 1].err, "Unexpected EOF");
 	}
 }
 
-static Node ParseIdentifier(Parser* p) {
-	Token* token = &p->tokens[p->i];
-	if (token->type != TOKEN_IDENTIFIER) {
-		assert(0); // TODO: error
+static void Expect(Parser* p, TokenType type) {
+	if (p->tokens[p->i].type != type) {
+		Token token2;
+		token2.type = type;
+
+		PrintError(
+			p->tokens[p->i].err, "Expected %s, got %s",
+			Lexer_TypeAsString(&token2), Lexer_TypeAsString(&p->tokens[p->i])
+		);
 	}
-
-	Advance(p);
-
-	Node ret;
-	ret.ident = (IdentifierNode) {NODE_IDENTIFIER, NewString(token->contents)};
-	return ret;
 }
 
 static Node ParseAtom(Parser* p) {
@@ -64,56 +76,60 @@ 	Node   ret;
 
 	Advance(p);
 
-	switch (token.type) {
+	switch (token->type) {
 		case TOKEN_IDENTIFIER: {
-			ret.ident = (IdentifierNode) {NODE_IDENTIFIER, NewString(token->contents)};
+			ret.ident = (IdentifierNode) {INFO(NODE_IDENTIFIER), NewString(token->contents)};
 			return ret;
 		}
 		case TOKEN_STRING: {
-			ret.string = (StringNode) {NODE_STRING, NewString(token->contents)};
+			ret.string = (StringNode) {INFO(NODE_STRING), NewString(token->contents)};
 			return ret;
 		}
 		case TOKEN_INT: {
-			ret.int = (IntNode) {NODE_INT, atoi(token->contents)};
+			ret.integer = (IntNode) {INFO(NODE_INT), atoi(token->contents)};
 			return ret;
 		}
-		default: assert(0); // TODO: error
+		case TOKEN_LPAREN: {
+			ret = ParseBinary(p);
+			Expect(p, TOKEN_RPAREN);
+			Advance(p);
+			return ret;
+		}
+		default: {
+			PrintError(
+				token->err, "Failed to parse atom, got %s",
+				Lexer_TypeAsString(token)
+			);
+			exit(1);
+		}
 	}
 }
 
 static bool IsUnaryOperator(Token* tok) {
-	case TOKEN_ADD:
-	case TOKEN_SUBTRACT: return true;
-	default:             return false;
+	switch (tok->type) {
+		case TOKEN_ADD:
+		case TOKEN_SUBTRACT: return true;
+		default:             return false;
+	}
 }
 
 static Node ParseUnary(Parser* p) {
-	Token* tok = &p->parser[p->i];
+	Token* tok = &p->tokens[p->i];
 
 	if (IsUnaryOperator(tok)) {
-		Node operand = ParseUnary();
+		Advance(p);
+		Node  operand    = ParseUnary(p);
+		Node* operandPtr = SafeMalloc(sizeof(Node));
+		*operandPtr      = operand;
+
 		Node ret;
 		ret.unary = (UnaryNode) {
-			NODE_UNARY_OP, operand, tok->type
+			INFO(NODE_UNARY_OP), operandPtr, tok->type
 		};
 		return ret;
 	}
 	else {
-		return ParseAtom();
-	}
-}
-
-static bool IsBinOperator(Token* tok) {
-	switch (tok->type) {
-		case TOKEN_ADD:
-		case TOKEN_SUBTRACT:
-		case TOKEN_MULTIPLY:
-		case TOKEN_DIVIDE:
-		case TOKEN_MOD:
-		case TOKEN_EQUAL:
-		case TOKEN_LESS:
-		case TOKEN_GREATER: return true;
-		default:            return false;
+		return ParseAtom(p);
 	}
 }
 
@@ -126,11 +142,16 @@ 		(p->tokens[p->i].type == TOKEN_DIVIDE) ||
 		(p->tokens[p->i].type == TOKEN_MOD)
 	) {
 		TokenType op = p->tokens[p->i].type;
-		Advance();
+		Advance(p);
 		Node right = ParseUnary(p);
+
+		Node* leftPtr  = SafeMalloc(sizeof(Node));
+		Node* rightPtr = SafeMalloc(sizeof(Node));
+		*leftPtr       = left;
+		*rightPtr      = right;
 
 		left.bin = (BinaryNode) {
-			NODE_BINARY_OP, left, right, op
+			INFO(NODE_BINARY_OP), leftPtr, rightPtr, op
 		};
 	}
 
@@ -145,11 +166,16 @@ 		(p->tokens[p->i].type == TOKEN_ADD) ||
 		(p->tokens[p->i].type == TOKEN_SUB)
 	) {
 		TokenType op = p->tokens[p->i].type;
-		Advance();
+		Advance(p);
 		Node right = ParseMulDivMod(p);
 
+		Node* leftPtr  = SafeMalloc(sizeof(Node));
+		Node* rightPtr = SafeMalloc(sizeof(Node));
+		*leftPtr       = left;
+		*rightPtr      = right;
+
 		left.bin = (BinaryNode) {
-			NODE_BINARY_OP, left, right, op
+			INFO(NODE_BINARY_OP), leftPtr, rightPtr, op
 		};
 	}
 
@@ -165,11 +191,16 @@ 		(p->tokens[p->i].type == TOKEN_LESS) ||
 		(p->tokens[p->i].type == TOKEN_GREATER)
 	) {
 		TokenType op = p->tokens[p->i].type;
-		Advance();
+		Advance(p);
 		Node right = ParseAddSub(p);
 
+		Node* leftPtr  = SafeMalloc(sizeof(Node));
+		Node* rightPtr = SafeMalloc(sizeof(Node));
+		*leftPtr       = left;
+		*rightPtr      = right;
+
 		left.bin = (BinaryNode) {
-			NODE_BINARY_OP, left, right, op
+			INFO(NODE_BINARY_OP), leftPtr, rightPtr, op
 		};
 	}
 
@@ -180,62 +211,339 @@ static Node ParseBinary(Parser* p) {
 	return ParseComparison(p);
 }
 
-static void Expect(Parser* p, TokenType type) {
-	if (p->tokens[p->i].type != type) {
-		assert(0); // TODO: error
-	}
-}
-
 static Node ParseType(Parser* p) {
 	Node ret;
 
 	switch (p->tokens[p->i].type) {
 		case TOKEN_PTR: {
-			Advance();
-			Expect(TOKEN_LPAREN);
-			ret.ptr = (PtrNode) {NODE_PTR, ParseType(p)};
-			Advance();
-			Expect(TOKEN_RPAREN);
+			Advance(p);
+			Expect(p, TOKEN_LPAREN);
+
+			Node innerType = ParseType(p);
+			ret.ptr = (PtrNode) {INFO(NODE_PTR), SafeMalloc(sizeof(Node))};
+			*ret.ptr.inner = innerType;
+
+			Advance(p);
+			Expect(p, TOKEN_RPAREN);
 			return ret;
 		}
 		case TOKEN_IDENTIFIER: {
-			ret.identifier = (IdentifierNode) {
-				NODE_IDENTIFIER, NewString(p->tokens[p->i].contents)
+			ret.ident = (IdentifierNode) {
+				INFO(NODE_IDENTIFIER), NewString(p->tokens[p->i].contents)
 			};
 			return ret;
 		}
 		default: {
-			assert(0); // TODO: error
+			PrintError(
+				p->tokens[p->i].err, "Unexpected %s token in type",
+				Lexer_TypeAsString(&p->tokens[p->i])
+			);
+			exit(1);
 		}
 	}
 }
 
-static Node ParseFunc(Parser* p) {
-	FuncNodeParam* params    = NULL;
-	size_t         paramsNum = 0;
+static FuncDec ParseFuncDec(Parser* p) {
+	FuncDecParam* params    = NULL;
+	size_t        paramsNum = 0;
 
 	bool sub = strcmp(p->tokens[p->i].contents, "sub") == 0;
 
-	Advance();
-	FuncNode ret;
+	Advance(p);
+	FuncDec ret;
 
-	Expect(TOKEN_IDENTIFIER);
+	Expect(p, TOKEN_IDENTIFIER);
 	ret.name = NewString(p->tokens[p->i].contents);
 
-	Advance();
-	Expect(TOKEN_LPAREN);
-	Advance();
+	Advance(p);
+	Expect(p, TOKEN_LPAREN);
+	Advance(p);
 
 	while (p->tokens[p->i].type != TOKEN_RPAREN) {
-		FuncNodeParam param;
-		Expect(TOKEN_IDENTIFIER);
+		FuncDecParam param;
+		Expect(p, TOKEN_IDENTIFIER);
 		param.name = NewString(p->tokens[p->i].contents);
 
-		Advance();
-		Expect(TOKEN_AS);
+		Advance(p);
+		Expect(p, TOKEN_AS);
+
+		Advance(p);
+		Node  typeNode = ParseType(p);
+		Node* typePtr  = SafeMalloc(sizeof(Node));
+		*typePtr       = typeNode;
+		param.type     = typePtr;
 
-		Advance();
-		param.type = ParseType(p);
+		++ paramsNum;
+		params = SafeRealloc(params, paramsNum * sizeof(FuncDecParam));
+		params[paramsNum - 1] = param;
+
+		Advance(p);
+		if (
+			(p->tokens[p->i].type != TOKEN_COMMA) &&
+			(p->tokens[p->i].type != TOKEN_RPAREN)
+		) {
+			PrintError(
+				p->tokens[p->i].err, "Unexpected %s token in parameter list",
+				Lexer_TypeAsString(&p->tokens[p->i])
+			);
+		}
+
+		if (p->tokens[p->i].type == TOKEN_COMMA) {
+			Advance(p);
+		}
 	}
+
+	ret.params    = params;
+	ret.paramsNum = paramsNum;
+
+	Advance(p);
+	Expect(p, TOKEN_LINE);
+
+	return ret;
 }
 
+static Node ParseFuncDef(Parser* p) {
+	FuncDefNode ret;
+	ret.i   = INFO(NODE_FUNC_DEF);
+	ret.dec = ParseFuncDec(p);
+	Advance(p);
+
+	ret.body    = NULL;
+	ret.bodyLen = 0;
+
+	while (p->tokens[p->i].type != TOKEN_END) {
+		if (p->tokens[p->i].type == TOKEN_LINE) {
+			Advance(p);
+			continue;
+		}
+
+		Node node = ParseNode(p);
+
+		++ ret.bodyLen;
+		ret.body = SafeRealloc(ret.body, ret.bodyLen * sizeof(Node));
+		ret.body[ret.bodyLen - 1] = node;
+	}
+
+	Advance(p);
+	Expect(p, TOKEN_LINE);
+
+	Node node;
+	node.funcDef = ret;
+	return node;
+}
+
+static Node ParseDim(Parser* p) {
+	DimNode ret;
+	ret.i = INFO(NODE_DIM);
+
+	Advance(p);
+	Expect(p, TOKEN_IDENTIFIER);
+	ret.name = NewString(p->tokens[p->i].contents);
+
+	Advance(p);
+	Expect(p, TOKEN_AS);
+
+	Advance(p);
+	Expect(p, TOKEN_IDENTIFIER);
+	ret.varType  = SafeMalloc(sizeof(Node));
+	*ret.varType = ParseType(p);
+
+	Advance(p);
+	Expect(p, TOKEN_LINE);
+
+	Node node;
+	node.dim = ret;
+	return node;
+}
+
+static Node ParseFuncCall(Parser* p) {
+	FuncCallNode ret;
+	ret.i    = INFO(NODE_FUNC_CALL);
+	ret.func = p->tokens[p->i].contents;
+
+	Advance(p);
+	Node*  params    = NULL;
+	size_t paramsNum = 0;
+
+	while (p->tokens[p->i].type != TOKEN_LINE) {
+		Node param = ParseBinary(p);
+
+		++ paramsNum;
+		params                = SafeRealloc(params, paramsNum * sizeof(Node));
+		params[paramsNum - 1] = param;
+
+		if (
+			(p->tokens[p->i].type != TOKEN_LINE) &&
+			(p->tokens[p->i].type != TOKEN_COMMA)
+		) {
+			PrintError(
+				p->tokens[p->i].err, "Unexpected %s token in parameter list",
+				Lexer_TypeAsString(&p->tokens[p->i])
+			);
+		}
+		if (p->tokens[p->i].type == TOKEN_COMMA) {
+			Advance(p);
+		}
+	}
+
+	ret.params    = params;
+	ret.paramsNum = paramsNum;
+
+	Node node;
+	node.funcCall = ret;
+	return node;
+}
+
+static Node ParseAssign(Parser* p) {
+	AssignNode ret;
+	ret.i        = INFO(NODE_ASSIGN);
+	ret.variable = p->tokens[p->i].contents;
+
+	Advance(p);
+	Expect(p, TOKEN_EQUAL);
+	Advance(p);
+
+	ret.rValue  = SafeMalloc(sizeof(Node));
+	*ret.rValue = ParseBinary(p);
+
+	Expect(p, TOKEN_LINE);
+
+	Node node;
+	node.assign = 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_IDENTIFIER: {
+			if (p->i == p->tokenNum - 1) {
+				PrintError(p->tokens[p->i].err, "Unexpected EOF");
+			}
+
+			if (p->tokens[p->i + 1].type == TOKEN_EQUAL) {
+				return ParseAssign(p);
+			}
+
+			return ParseFuncCall(p);
+		}
+		default: {
+			PrintError(
+				p->tokens[p->i].err, "Unexpected %s token",
+				Lexer_TypeAsString(&p->tokens[p->i])
+			);
+			exit(1);
+		}
+	}
+}
+
+void Parser_PrintNode(Node* node) {
+	switch (node->i.type) {
+		case NODE_INT: printf("%d", node->integer.value); break;
+		case NODE_STRING: printf("%s", node->string.value); break;
+		case NODE_IDENTIFIER: printf("%s", node->ident.name); break;
+		case NODE_BINARY_OP: {
+			printf("(");
+			Parser_PrintNode(node->bin.left);
+
+			switch (node->bin.op) {
+				case TOKEN_ADD:      printf("+"); break;
+				case TOKEN_SUBTRACT: printf("-"); break;
+				case TOKEN_MULTIPLY: printf("*"); break;
+				case TOKEN_DIVIDE:   printf("/"); break;
+				case TOKEN_MOD:      printf("%%"); break;
+				case TOKEN_EQUAL:    printf("="); break;
+				case TOKEN_LESS:     printf("<"); break;
+				case TOKEN_GREATER:  printf(">"); break;
+				default:             assert(0);
+			}
+
+			Parser_PrintNode(node->bin.right);
+			printf(")");
+			break;
+		}
+		case NODE_UNARY_OP: {
+			printf("(");
+
+			switch (node->unary.op) {
+				case TOKEN_ADD:      printf("+"); break;
+				case TOKEN_SUBTRACT: printf("-"); break;
+				default:             assert(0);
+			}
+
+			Parser_PrintNode(node->unary.operand);
+			printf(")");
+			break;
+		}
+		case NODE_PTR: {
+			printf("ptr(");
+			Parser_PrintNode(node->ptr.inner);
+			break;
+		}
+		case NODE_FUNC_DEF: {
+			printf("func %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");
+
+			for (size_t i = 0; i < node->funcDef.bodyLen; ++ i) {
+				printf("\t");
+				Parser_PrintNode(&node->funcDef.body[i]);
+				puts("");
+			}
+			puts("end");
+			break;
+		}
+		case NODE_DIM: {
+			printf("dim %s as ", node->dim.name);
+			Parser_PrintNode(node->dim.varType);
+			puts("");
+			break;
+		}
+		case NODE_FUNC_CALL: {
+			printf("%s ", node->funcCall.func);
+
+			for (size_t i = 0; i < node->funcCall.paramsNum; ++ i) {
+				Parser_PrintNode(&node->funcCall.params[i]);
+
+				if (i < node->funcCall.paramsNum - 1) {
+					printf(", ");
+				}
+			}
+			puts("");
+			break;
+		}
+		default: {
+			printf("unknown %d\n", node->i.type);
+			assert(0);
+		}
+	}
+}
+
+Node* Parser_Parse(Parser* p, size_t* lenOut) {
+	Node*  ret = NULL;
+	size_t len = 0;
+
+	for (p->i = 0; p->i < p->tokenNum; ++ p->i) {
+		if (p->tokens[p->i].type == TOKEN_LINE) continue;
+
+		Node node = ParseNode(p);
+
+		++ len;
+		ret          = SafeRealloc(ret, len * sizeof(Node));
+		ret[len - 1] = node;
+	}
+
+	*lenOut = len;
+	return ret;
+}




diff --git a/basic-boot/source/parser.h b/basic-boot/source/parser.h
index a0e71058d090735e36575c3514f7e02773bb4893..531a4de3e1c355bb9ed18fc6a09f0668a3cb8f3a 100644
--- a/basic-boot/source/parser.h
+++ b/basic-boot/source/parser.h
@@ -2,9 +2,10 @@ #ifndef N_PARSER_H
 #define N_PARSER_H
 
 #include "lexer.h"
+#include "error.h"
 #include "common.h"
 
-enum {
+typedef enum {
 	NODE_NONE,
 	NODE_INT,
 	NODE_STRING,
@@ -12,65 +13,102 @@ 	NODE_IDENTIFIER,
 	NODE_BINARY_OP,
 	NODE_UNARY_OP,
 	NODE_PTR,
-	NODE_FUNC,
+	NODE_FUNC_DEF,
+	NODE_DIM,
+	NODE_FUNC_CALL,
+	NODE_ASSIGN
 } NodeType;
 
+typedef struct {
+	NodeType  type;
+	ErrorInfo err;
+} NodeInfo;
+
 typedef union Node Node;
 
 typedef struct {
-	NodeType type;
+	NodeInfo i;
 	int      value;
 } IntNode;
 
 typedef struct {
-	NodeType type;
+	NodeInfo i;
 	char*    value;
 } StringNode;
 
 typedef struct {
-	NodeType type;
+	NodeInfo i;
 	char*    name;
 } IdentifierNode;
 
 typedef struct {
-	NodeType  type;
+	NodeInfo  i;
 	Node*     left;
 	Node*     right;
 	TokenType op;
 } BinaryNode;
 
 typedef struct {
-	NodeType  type;
+	NodeInfo  i;
 	Node*     operand;
 	TokenType op;
 } UnaryNode;
 
 typedef struct {
-	NodeType type;
-	Node     inner;
+	NodeInfo i;
+	Node*    inner;
 } PtrNode;
 
 typedef struct {
-	Node  type;
-	char* name;
-} FuncNodeParam;
+	Node*  type;
+	char*  name;
+} FuncDecParam;
 
 typedef struct {
-	NodeType       type;
-	FuncNodeParam* params;
-	size_t         paramsNum;
-	Node*          ret;
-	char*          name;
-} FuncNode;
+	FuncDecParam* params;
+	size_t        paramsNum;
+	Node*         ret;
+	char*         name;
+} FuncDec;
+
+typedef struct {
+	NodeInfo i;
+	FuncDec  dec;
+	Node*    body;
+	size_t   bodyLen;
+} FuncDefNode;
+
+typedef struct {
+	NodeInfo i;
+	char*    name;
+	Node*    varType;
+} DimNode;
+
+typedef struct {
+	NodeInfo i;
+	char*    func;
+	Node*    params;
+	size_t   paramsNum;
+} FuncCallNode;
+
+typedef struct {
+	NodeInfo i;
+	char*    variable;
+	Node*    rValue;
+} AssignNode;
 
 union Node {
-	NodeType       type;
+	NodeInfo       i;
 	IntNode        integer;
 	StringNode     string;
 	IdentifierNode ident;
 	BinaryNode     bin;
 	UnaryNode      unary;
 	PtrNode        ptr;
+	FuncDefNode    funcDef;
+	DimNode        dim;
+	FuncCallNode   funcCall;
+	AssignNode     assign;
 };
 
 typedef struct {
@@ -79,6 +117,8 @@ 	size_t tokenNum;
 	size_t i;
 } Parser;
 
-Parser Parser_Init(FILE* file);
+Parser Parser_Init(FILE* file, const char* fileName);
+void   Parser_PrintNode(Node* node);
+Node*  Parser_Parse(Parser* p, size_t* lenOut);
 
 #endif




diff --git a/basic-boot/source/util.c b/basic-boot/source/util.c
index 8a482524a41bd8789c94f93aea7e8e1cb37bb5d5..3524bb0b4c307b7a93a3b07c1c2c13fe438d9956 100644
--- a/basic-boot/source/util.c
+++ b/basic-boot/source/util.c
@@ -1,4 +1,5 @@
 #include <string.h>
+#include "mem.h"
 #include "common.h"
 
 char* NewString(const char* src) {




diff --git a/basic-boot/source/util.h b/basic-boot/source/util.h
index 4c84ba39c17a9af7662bc602e8f3b6ce7dd88b14..aa57880a037cf533331c0e4cdedfcef4953b4465 100644
--- a/basic-boot/source/util.h
+++ b/basic-boot/source/util.h
@@ -1,10 +1,7 @@
 #ifndef N_UTIL_H
 #define N_UTIL_H
 
-#include <math.h>
 #include <stdio.h>
-#include "log.h"
-#include "types.h"
 
 #define FUNCTION_POINTER(TYPE, NAME, ...) TYPE (*NAME)(__VA_ARGS__)
 #define MIN(A, B) (((A) < (B))? (A) : (B))
@@ -19,7 +16,7 @@ 		*macro##a = *macro##b; \
 		*macro##b = macro##tmp; \
 	} while (0);
 
-char*  NewString(const char* src);
-char*  ConcatString(const char* first, const char* second);
+char* NewString(const char* src);
+char* ConcatString(const char* first, const char* second);
 
 #endif




diff --git a/basic-boot/test.bas b/basic-boot/test.bas
new file mode 100644
index 0000000000000000000000000000000000000000..3af3568083c1c16a9f9bf9fb6568dd7c197ef799
--- /dev/null
+++ b/basic-boot/test.bas
@@ -0,0 +1,13 @@
+'NITRON
+
+dim foo as int
+
+func manul(foo as int, bar as int)
+	dim bar as u32
+end
+
+manul 1, (2 * 3) + -5 * 4
+
+func foo(bum bum bum bum)
+
+end