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