From 69b2253c34917c1981d537c96413d7de85b66258 Mon Sep 17 00:00:00 2001 From: samsonium Date: Thu, 15 Oct 2026 17:20:43 +0300 Subject: [PATCH] feat: enhance compiler - Add comments and test for it - Add semicolon as required end of some expressions - Add new arguments parser - Add multi-file compilation - Add colors in output --- CMakeLists.txt | 10 ++ exl/base_math.fzs | 12 +- exl/comment.fzs | 2 +- exl/conditions.fzs | 10 +- exl/fn.fzs | 20 +-- exl/hw.fzs | 2 +- exl/print_empty.fzs | 2 +- exl/problematic_hw.fzs | 2 +- exl/variables.fzs | 18 +-- include/common/fzl_colors.h | 10 ++ include/compiler/fzl_reader.h | 7 +- include/compiler/fzl_token.h | 3 +- include/compiler/utils/fzl_linked.h | 49 +++++++ include/compiler/utils/fzl_options.h | 25 ++++ src/compiler/fzl_parser.c | 208 +++++++++++++++++---------- src/compiler/fzl_reader.c | 123 +++++++++++----- src/compiler/fzl_token.c | 3 +- src/compiler/fzl_walker.c | 70 ++++----- src/compiler/main.c | 198 ++++++++----------------- src/compiler/utils/fzl_linked.c | 159 ++++++++++++++++++++ src/compiler/utils/fzl_options.c | 131 +++++++++++++++++ src/vm/fzl_vm.c | 2 - 22 files changed, 739 insertions(+), 327 deletions(-) create mode 100644 include/common/fzl_colors.h create mode 100644 include/compiler/utils/fzl_linked.h create mode 100644 include/compiler/utils/fzl_options.h create mode 100644 src/compiler/utils/fzl_linked.c create mode 100644 src/compiler/utils/fzl_options.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ff03fc..c6692f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,8 @@ add_executable(fzc src/compiler/fzl_writer.c src/compiler/utils/fzl_const_pool.c src/compiler/utils/fzl_symtable.c + src/compiler/utils/fzl_linked.c + src/compiler/utils/fzl_options.c src/compiler/main.c) # Virtual machine @@ -59,6 +61,10 @@ add_test( NAME compile_fn COMMAND fzc -o "${CMAKE_CURRENT_BINARY_DIR}/fn.fzb" "${CMAKE_CURRENT_SOURCE_DIR}/exl/fn.fzs" ) +add_test( + NAME compile_comment + COMMAND fzc -o "${CMAKE_CURRENT_BINARY_DIR}/comment.fzb" "${CMAKE_CURRENT_SOURCE_DIR}/exl/comment.fzs" +) set_tests_properties(compile_problematic_hw PROPERTIES WILL_FAIL TRUE) @@ -90,4 +96,8 @@ add_test( NAME runtime_fn COMMAND fz "${CMAKE_CURRENT_BINARY_DIR}/fn.fzb" ) +add_test( + NAME runtime_comment + COMMAND fz "${CMAKE_CURRENT_BINARY_DIR}/comment.fzb" +) diff --git a/exl/base_math.fzs b/exl/base_math.fzs index b5e368c..b7e15c7 100644 --- a/exl/base_math.fzs +++ b/exl/base_math.fzs @@ -1,7 +1,7 @@ -printline(2 + 2 * 2) -printline(-1 + 1) -printline(2 ^ 2) -printline(1 + 1 * 1 / 1) -printline(4 % 2) -printline(10 / 2) +printline(2 + 2 * 2); +printline(-1 + 1); +printline(2 ^ 2); +printline(1 + 1 * 1 / 1); +printline(4 % 2); +printline(10 / 2); diff --git a/exl/comment.fzs b/exl/comment.fzs index 883dc04..0fd39ee 100644 --- a/exl/comment.fzs +++ b/exl/comment.fzs @@ -1,3 +1,3 @@ // I'm a comment -printline("Comment is skipped") +printline("Comment is skipped");;;;; diff --git a/exl/conditions.fzs b/exl/conditions.fzs index 4e7dbf4..b7c5a83 100644 --- a/exl/conditions.fzs +++ b/exl/conditions.fzs @@ -1,16 +1,16 @@ -bool flag = true +bool flag = true; if (!flag) - printline("buhhh, flag is not true") + printline("buhhh, flag is not true"); else if (2 + 2 >= 4) { - printline ("two plus two is four") + printline ("two plus two is four"); } else { - printline("gotcha") + printline("gotcha"); } { - printline("block after") + printline("block after"); } diff --git a/exl/fn.fzs b/exl/fn.fzs index b08dec2..e919ada 100644 --- a/exl/fn.fzs +++ b/exl/fn.fzs @@ -1,24 +1,24 @@ int fib(int n) { if (n <= 1) - return n + return n; - return fib(n - 1) + fib(n - 2) + return fib(n - 1) + fib(n - 2); } uint sum(uint a, uint b) { - return a + b + return a + b; } -printline("Test #1: fibonacci") -int result = fib(7) +printline("Test #1: fibonacci"); +int result = fib(7); if (result == 13) - printline("Recurse test passed") -else printline("Recurse test failed") + printline("Recurse test passed"); +else printline("Recurse test failed"); -printline("Test #2: sum") +printline("Test #2: sum"); if (sum(2, 2) == 4) - printline("Sum test passed") -else printline("Sum test failed") + printline("Sum test passed"); +else printline("Sum test failed"); diff --git a/exl/hw.fzs b/exl/hw.fzs index 173a105..131b32e 100644 --- a/exl/hw.fzs +++ b/exl/hw.fzs @@ -1,2 +1,2 @@ -printline('hello, world') +printline('hello, world'); diff --git a/exl/print_empty.fzs b/exl/print_empty.fzs index a9baaa0..67c1545 100644 --- a/exl/print_empty.fzs +++ b/exl/print_empty.fzs @@ -1 +1 @@ -printline("") +printline(""); diff --git a/exl/problematic_hw.fzs b/exl/problematic_hw.fzs index 88c437d..ec0ce93 100644 --- a/exl/problematic_hw.fzs +++ b/exl/problematic_hw.fzs @@ -1 +1 @@ -printline("hello) +printline("hello); diff --git a/exl/variables.fzs b/exl/variables.fzs index 18216b8..6ba588d 100644 --- a/exl/variables.fzs +++ b/exl/variables.fzs @@ -1,13 +1,13 @@ -uint work_it = 21 * 2 ^ 2 -int make_it = 10 +uint work_it = 21 * 2 ^ 2; +int make_it = 10; -u64 do_it -do_it = 15 +u64 do_it; +do_it = 15; -printline(work_it) -printline(make_it + do_it) +printline(work_it); +printline(make_it + do_it); -char make_us -str floyd = "hello, Pink Floyd!" -printline(floyd) +char make_us; +str floyd = "hello, Pink Floyd!"; +printline(floyd); diff --git a/include/common/fzl_colors.h b/include/common/fzl_colors.h new file mode 100644 index 0000000..528537d --- /dev/null +++ b/include/common/fzl_colors.h @@ -0,0 +1,10 @@ +#ifndef FZL_COLORS_H +#define FZL_COLORS_H + +#define FZL_CERROR "\033[0;31m" +#define FZL_CWARNING "\033[0;33m" +#define FZL_COK "\033[0;32m" +#define FZL_CDEBUG "\033[0;34m" +#define FZL_CRST "\033[0m" + +#endif // FZL_COLORS_H diff --git a/include/compiler/fzl_reader.h b/include/compiler/fzl_reader.h index 2a85dac..140b0f3 100644 --- a/include/compiler/fzl_reader.h +++ b/include/compiler/fzl_reader.h @@ -2,6 +2,7 @@ #define FZL_READER_H #include +#include #include #include #include @@ -19,16 +20,16 @@ typedef struct fzl_reader_ll_t *first; fzl_reader_ll_t *last; + fzl_linked_t *linked; + char *source; size_t size; size_t position; - size_t line_start; - size_t line_n; } fzl_reader_t; // Allocate new reader -fzl_reader_t *fzl_mkreader(char *source); +fzl_reader_t *fzl_mkreader(fzl_linked_t *linked); // Read source file int fzl_read(fzl_reader_t *reader); diff --git a/include/compiler/fzl_token.h b/include/compiler/fzl_token.h index ce60c69..bb9a5de 100644 --- a/include/compiler/fzl_token.h +++ b/include/compiler/fzl_token.h @@ -61,11 +61,12 @@ typedef struct bool store_value; void *value; uint16_t value_sz; + char *filename; } fzl_token_t; // Allocate new token fzl_token_t *fzl_mktoken(const fzl_toktype_t type, size_t line, size_t col, - void *value, size_t value_sz); + void *value, size_t value_sz, char *filename); // Free token and its contents void fzl_freetoken(fzl_token_t *token); diff --git a/include/compiler/utils/fzl_linked.h b/include/compiler/utils/fzl_linked.h new file mode 100644 index 0000000..0c7c360 --- /dev/null +++ b/include/compiler/utils/fzl_linked.h @@ -0,0 +1,49 @@ +#ifndef FZL_LINKED_H +#define FZL_LINKED_H + +#include +#include + +// Linked file descriptor +typedef struct +{ + char *name; + size_t start; + size_t end; +} fzl_linked_entry_t; + +// Linked descriptor +typedef struct +{ + fzl_linked_entry_t *entries; + size_t entries_count; + + char *source; + size_t total_sz; +} fzl_linked_t; + +// Position in file +typedef struct +{ + size_t line; + size_t col; + + char *filename; +} fzl_file_loc; + +// Allocated new linked +fzl_linked_t *fzl_mklinked(); + +// Read specified files +bool fzl_linked_add_files(fzl_linked_t *l, char **files, size_t files_count); + +// Get last error from linked +char *fzl_linked_geterror(); + +// Get filename and position in it by reader cursor +bool fzl_linked_getpos(fzl_linked_t *l, size_t pos, fzl_file_loc *res); + +// Free linked obj +void fzl_freelinked(fzl_linked_t *linked); + +#endif // FZL_LINKED_H diff --git a/include/compiler/utils/fzl_options.h b/include/compiler/utils/fzl_options.h new file mode 100644 index 0000000..896693c --- /dev/null +++ b/include/compiler/utils/fzl_options.h @@ -0,0 +1,25 @@ +#ifndef FZL_OPTIONS_H +#define FZL_OPTIONS_H + +#include +#include + +// Compiler options +typedef struct +{ + char **files; + size_t files_count; + + char *outname; + + bool should_continue; + bool verbose; +} fzl_options_t; + +// Parse command line arguments +fzl_options_t *fzl_mkoptions(int argc, char **argv); + +// Free options +void fzl_freeoptions(fzl_options_t *options); + +#endif // FZL_OPTIONS_H diff --git a/src/compiler/fzl_parser.c b/src/compiler/fzl_parser.c index a581727..0bb7dae 100644 --- a/src/compiler/fzl_parser.c +++ b/src/compiler/fzl_parser.c @@ -7,6 +7,7 @@ #include char plast_err[256]; +fzl_token_t *last_known_tok = NULL; fzl_parser_t *fzl_mkparser(fzl_reader_ll_t *first) { @@ -50,6 +51,8 @@ static fzl_token_t *peek(fzl_parser_t *parser) { if (!parser || !parser->cursor) return NULL; + + last_known_tok = parser->cursor->token; return parser->cursor->token; } @@ -157,8 +160,8 @@ fzl_node_t *parse_primary(fzl_parser_t *parser) fzl_node_t *node = parse_expression(parser); if (!is(parser, FZL_TOKTYPE_RPAREN)) { - snprintf(plast_err, sizeof(plast_err), "expected ')' at %ld:%ld", - parser->cursor->token->ln, parser->cursor->token->cn); + snprintf(plast_err, sizeof(plast_err), "'%s': expected ')' at %ld:%ld", + peek(parser)->filename, peek(parser)->ln, peek(parser)->cn); return NULL; } consume(parser); @@ -169,9 +172,28 @@ fzl_node_t *parse_primary(fzl_parser_t *parser) fzl_token_t *name = consume(parser); return fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); } + else if (is(parser, FZL_TOKTYPE_TYPE)) + { + fzl_token_t *type = consume(parser); + fzl_token_t *name = consume(parser); + if (name->type != FZL_TOKTYPE_NAME) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': expected name after type at %ld:%ld", type->filename, + type->ln, type->cn); + return NULL; + } - snprintf(plast_err, sizeof(plast_err), "failed to parse primary at %ld:%ld", - peek(parser)->ln, peek(parser)->cn); + fzl_node_t *decl = fzl_mknode(FZL_NODETYPE_DECLARATION, type); + decl->var.type = type; + decl->var.identifier = fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); + return decl; + } + + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': failed to parse primary at %ld:%ld", peek(parser)->filename, + peek(parser)->ln, peek(parser)->cn); return NULL; } @@ -186,8 +208,10 @@ fzl_node_t *parse_postfix(fzl_parser_t *parser) if (!left) { - snprintf(plast_err, sizeof(plast_err), "failed to parse postfix at %ld:%ld", - peek(parser)->ln, peek(parser)->cn); + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': failed to parse postfix at %ld:%ld", + peek(parser)->filename, peek(parser)->ln, peek(parser)->cn); return NULL; } @@ -226,8 +250,8 @@ fzl_node_t *parse_postfix(fzl_parser_t *parser) { free(args); snprintf(plast_err, sizeof(plast_err), - "expected ')' after argument list at %ld:%ld", peek(parser)->ln, - peek(parser)->cn); + "'%s': expected ')' after argument list at %ld:%ld", + peek(parser)->filename, peek(parser)->ln, peek(parser)->cn); return NULL; } @@ -274,8 +298,10 @@ fzl_node_t *parse_power(fzl_parser_t *parser) if (!left) { - snprintf(plast_err, sizeof(plast_err), "failed to parse power at %ld:%ld", - peek(parser)->ln, peek(parser)->cn); + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': failed to parse power at %ld:%ld", peek(parser)->filename, + peek(parser)->ln, peek(parser)->cn); return NULL; } @@ -286,9 +312,10 @@ fzl_node_t *parse_power(fzl_parser_t *parser) right = parse_unary(parser); if (!right) { - snprintf(plast_err, sizeof(plast_err), - "failed to parse right side of power at %ld:%ld", - peek(parser)->ln, peek(parser)->cn); + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': failed to parse right side of power at %ld:%ld", + peek(parser)->filename, peek(parser)->ln, peek(parser)->cn); return NULL; } @@ -314,8 +341,9 @@ fzl_node_t *parse_factor(fzl_parser_t *parser) if (!left) { if (!plast_err[0]) - snprintf(plast_err, sizeof(plast_err), "invalid expression at %ld:%ld", - parser->cursor->token->ln, parser->cursor->token->cn); + snprintf(plast_err, sizeof(plast_err), + "'%s': invalid expression at %ld:%ld", peek(parser)->filename, + peek(parser)->ln, peek(parser)->cn); return NULL; } @@ -327,9 +355,10 @@ fzl_node_t *parse_factor(fzl_parser_t *parser) right = parse_factor(parser); if (!right) { - snprintf(plast_err, sizeof(plast_err), - "unfinished factor (mul/div) expression at %ld:%ld", - left->token->ln, left->token->cn); + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': unfinished factor (mul/div) expression at %ld:%ld", + left->token->filename, left->token->ln, left->token->cn); return NULL; } @@ -353,8 +382,10 @@ fzl_node_t *parse_term(fzl_parser_t *parser) if (!left) { - snprintf(plast_err, sizeof(plast_err), "invalid expression at %ld:%ld", - parser->cursor->token->ln, parser->cursor->token->cn); + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': invalid expression at %ld:%ld", peek(parser)->filename, + peek(parser)->ln, peek(parser)->cn); return NULL; } @@ -365,9 +396,10 @@ fzl_node_t *parse_term(fzl_parser_t *parser) right = parse_factor(parser); if (!right) { - snprintf(plast_err, sizeof(plast_err), - "unfinished term (add/sub) expression at %ld:%ld", - left->token->ln, left->token->cn); + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': unfinished term (add/sub) expression at %ld:%ld", + left->token->filename, left->token->ln, left->token->cn); return NULL; } @@ -400,8 +432,10 @@ fzl_node_t *parse_cond(fzl_parser_t *parser) right = parse_term(parser); if (!right) { - snprintf(plast_err, sizeof(plast_err), "unfinished expression at %ld:%ld", - op->ln, op->cn); + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': unfinished expression at %ld:%ld", op->filename, op->ln, + op->cn); return NULL; } @@ -456,8 +490,10 @@ fzl_node_t *parse_and(fzl_parser_t *parser) right = parse_cond(parser); if (!right) { - snprintf(plast_err, sizeof(plast_err), "unfinished expression at %ld:%ld", - or->ln, or->cn); + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': unfinished expression at %ld:%ld", or->filename, or->ln, + or->cn); return NULL; } @@ -488,8 +524,10 @@ fzl_node_t *parse_or(fzl_parser_t *parser) right = parse_and(parser); if (!right) { - snprintf(plast_err, sizeof(plast_err), "unfinished expression at %ld:%ld", - or->ln, or->cn); + if (!plast_err[0]) + snprintf(plast_err, sizeof(plast_err), + "'%s': unfinished expression at %ld:%ld", or->filename, or->ln, + or->cn); return NULL; } @@ -508,6 +546,8 @@ fzl_node_t *parse_expression(fzl_parser_t *parser) { return parse_and(parser); } // Statement parsing fzl_node_t *parse_statement(fzl_parser_t *parser) { + fzl_node_t *res = NULL; + if (is(parser, FZL_TOKTYPE_TYPE)) { fzl_token_t *type = peek(parser); @@ -521,8 +561,8 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) if (tok->type != FZL_TOKTYPE_NAME) { snprintf(plast_err, sizeof(plast_err), - "expected name in function definition at %ld:%ld", tok->ln, - tok->cn); + "'%s': expected name in function definition at %ld:%ld", + tok->filename, tok->ln, tok->cn); return NULL; } @@ -530,7 +570,8 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) if (lparen->type != FZL_TOKTYPE_LPAREN) { snprintf(plast_err, sizeof(plast_err), - "expected '(' after name at %ld:%ld", lparen->ln, lparen->cn); + "'%s': expected '(' after name at %ld:%ld", lparen->filename, + lparen->ln, lparen->cn); return NULL; } @@ -540,7 +581,7 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) while (peek(parser) && !is(parser, FZL_TOKTYPE_RPAREN)) { - fzl_node_t *arg = parse_statement(parser); + fzl_node_t *arg = parse_expression(parser); if (!arg) return NULL; @@ -560,16 +601,16 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) if (rparen->type != FZL_TOKTYPE_RPAREN) { snprintf(plast_err, sizeof(plast_err), - "expected ')' after argument list at %ld:%ld", rparen->ln, - rparen->cn); + "'%s': expected ')' after argument list at %ld:%ld", + rparen->filename, rparen->ln, rparen->cn); return NULL; } if (!is(parser, FZL_TOKTYPE_LBRACE)) { fzl_token_t *tok = peek(parser); - snprintf(plast_err, sizeof(plast_err), "expected '{' at %ld:%ld", - tok->ln, tok->cn); + snprintf(plast_err, sizeof(plast_err), "'%s': expected '{' at %ld:%ld", + tok->filename, tok->ln, tok->cn); return NULL; } @@ -586,14 +627,15 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) return node; } - - if (type->type == FZL_TOKTYPE_TYPE || next(parser)->type == FZL_TOKTYPE_EQ) + else if (type->type == FZL_TOKTYPE_TYPE || + next(parser)->type == FZL_TOKTYPE_EQ) { fzl_node_t *identifier = parse_primary(parser); if (!identifier || identifier->type != FZL_NODETYPE_IDENTIFIER) { - snprintf(plast_err, sizeof(plast_err), "expected identifier at %ld:%ld", + snprintf(plast_err, sizeof(plast_err), + "'%s': expected identifier at %ld:%ld", type->filename, type->ln, type->cn); return NULL; } @@ -602,29 +644,28 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) left->var.type = type; left->var.identifier = identifier; - if (!is(parser, FZL_TOKTYPE_EQ)) - return left; - - fzl_node_t *right; - while (is(parser, FZL_TOKTYPE_EQ)) + if (is(parser, FZL_TOKTYPE_EQ)) { - fzl_token_t *asn = consume(parser); - right = parse_expression(parser); - if (!right) - return NULL; + fzl_node_t *right; + while (is(parser, FZL_TOKTYPE_EQ)) + { + fzl_token_t *asn = consume(parser); + right = parse_expression(parser); + if (!right) + return NULL; - fzl_node_t *node = fzl_mknode(FZL_NODETYPE_ASSIGN, asn); - node->binary_op.left = left; - node->binary_op.right = right; + fzl_node_t *node = fzl_mknode(FZL_NODETYPE_ASSIGN, asn); + node->binary_op.left = left; + node->binary_op.right = right; - left = node; + left = node; + } } - return left; + res = left; } } - - if (is(parser, FZL_TOKTYPE_NAME) && next(parser)->type == FZL_TOKTYPE_EQ) + else if (is(parser, FZL_TOKTYPE_NAME) && next(parser)->type == FZL_TOKTYPE_EQ) { fzl_token_t *name = consume(parser); fzl_node_t *left = fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); @@ -644,37 +685,33 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) left = assn; } - return left; + res = left; } - - if (is(parser, FZL_TOKTYPE_RETURN)) + else if (is(parser, FZL_TOKTYPE_RETURN)) { fzl_token_t *ret = consume(parser); fzl_node_t *node = fzl_mknode(FZL_NODETYPE_RETURN, ret); - if (is(parser, FZL_TOKTYPE_DOT)) + if (!is(parser, FZL_TOKTYPE_SEMICOLON)) { - consume(parser); - return node; + fzl_node_t *retval = parse_expression(parser); + if (!retval) + return NULL; + + node->ret.value = retval; } - fzl_node_t *retval = parse_expression(parser); - if (!retval) - return NULL; - - node->ret.value = retval; - return node; + res = node; } - - if (is(parser, FZL_TOKTYPE_IF)) + else if (is(parser, FZL_TOKTYPE_IF)) { fzl_token_t *if_tok = consume(parser); fzl_token_t *lparen = consume(parser); if (lparen->type != FZL_TOKTYPE_LPAREN) { snprintf(plast_err, sizeof(plast_err), - "expected '(' before condition at %ld:%ld", lparen->ln, - lparen->cn); + "'%s': expected '(' before condition at %ld:%ld", + lparen->filename, lparen->ln, lparen->cn); return NULL; } @@ -686,8 +723,8 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) if (rparen->type != FZL_TOKTYPE_RPAREN) { snprintf(plast_err, sizeof(plast_err), - "expected ')' after condition at %ld:%ld", rparen->ln, - rparen->cn); + "'%s': expected ')' after condition at %ld:%ld", + rparen->filename, rparen->ln, rparen->cn); return NULL; } @@ -711,8 +748,7 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) return stmt_node; } - - if (is(parser, FZL_TOKTYPE_LBRACE)) + else if (is(parser, FZL_TOKTYPE_LBRACE)) { fzl_token_t *block_tok = consume(parser); @@ -735,10 +771,11 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) stmts[count++] = node; } fzl_token_t *rbrace = consume(parser); - if (!rbrace || rbrace->type != FZL_TOKTYPE_RBRACE) + if (rbrace && rbrace->type != FZL_TOKTYPE_RBRACE) { snprintf(plast_err, sizeof(plast_err), - "missing '}' after block at %ld:%ld", rbrace->ln, rbrace->cn); + "'%s': missing '}' after block at %ld:%ld", rbrace->filename, + rbrace->ln, rbrace->cn); return NULL; } @@ -748,7 +785,20 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) return node; } - return parse_expression(parser); + if (!res) + res = parse_expression(parser); + + if (!is(parser, FZL_TOKTYPE_SEMICOLON)) + { + printf("Current token are %d\n", last_known_tok->type); + snprintf(plast_err, sizeof(plast_err), "'%s': missing ';' at %ld:%ld", + last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); + return NULL; + } + while (is(parser, FZL_TOKTYPE_SEMICOLON)) + consume(parser); + + return res; } // Internal parsing entry point diff --git a/src/compiler/fzl_reader.c b/src/compiler/fzl_reader.c index adbf95e..15752a1 100644 --- a/src/compiler/fzl_reader.c +++ b/src/compiler/fzl_reader.c @@ -1,4 +1,5 @@ #include "compiler/fzl_token.h" +#include "compiler/utils/fzl_linked.h" #include #include #include @@ -9,7 +10,7 @@ // Last error from reader static char last_err[256] = {0}; -fzl_reader_t *fzl_mkreader(char *source) +fzl_reader_t *fzl_mkreader(fzl_linked_t *linked) { fzl_reader_ll_t *first_node = malloc(sizeof(fzl_reader_ll_t)); first_node->token = NULL; @@ -18,11 +19,10 @@ fzl_reader_t *fzl_mkreader(char *source) fzl_reader_t *reader = malloc(sizeof(fzl_reader_t)); reader->first = first_node; reader->last = first_node; - reader->source = source; - reader->size = strlen(source); + reader->linked = linked; + reader->source = linked->source; + reader->size = linked->total_sz; reader->position = 0; - reader->line_n = 1; - reader->line_start = 0; return reader; } @@ -30,21 +30,12 @@ fzl_reader_t *fzl_mkreader(char *source) // --- Read zone --- // Move cursor forward +// @deprecated static size_t move(fzl_reader_t *reader, size_t len) { if (!reader) return 0; - char *src = reader->source; - for (size_t i = 0; i < len; i++) - { - if (src[reader->position + i] == '\n') - { - reader->line_n++; - reader->line_start = reader->position + i + 1; - } - } - return reader->position += len; } @@ -71,17 +62,24 @@ fzl_token_t *parse_name(fzl_reader_t *reader) move(reader, size); fzl_token_t *tok; - size_t line = reader->line_n; - size_t pos = start - reader->line_start; + fzl_file_loc l; + bool ok = fzl_linked_getpos(reader->linked, start, &l); + if (!ok) + { + snprintf(last_err, sizeof(last_err), "failed to locate line:col"); + return NULL; + } if (strcmp(value, "return") == 0) - tok = fzl_mktoken(FZL_TOKTYPE_RETURN, line, pos, value, size); + tok = + fzl_mktoken(FZL_TOKTYPE_RETURN, l.line, l.col, value, size, l.filename); else if (strcmp(value, "if") == 0) - tok = fzl_mktoken(FZL_TOKTYPE_IF, line, pos, value, size); + tok = fzl_mktoken(FZL_TOKTYPE_IF, l.line, l.col, value, size, l.filename); else if (strcmp(value, "else") == 0) - tok = fzl_mktoken(FZL_TOKTYPE_ELSE, line, pos, value, size); + tok = fzl_mktoken(FZL_TOKTYPE_ELSE, l.line, l.col, value, size, l.filename); else if (strcmp(value, "true") == 0 || strcmp(value, "false") == 0) - tok = fzl_mktoken(FZL_TOKTYPE_BOOL_LITERAL, line, pos, value, size); + tok = fzl_mktoken(FZL_TOKTYPE_BOOL_LITERAL, l.line, l.col, value, size, + l.filename); else if (strcmp(value, "str") == 0 || strcmp(value, "char") == 0 || strcmp(value, "bool") == 0 || strcmp(value, "uint") == 0 || strcmp(value, "int") == 0 || strcmp(value, "i8") == 0 || @@ -89,9 +87,9 @@ fzl_token_t *parse_name(fzl_reader_t *reader) strcmp(value, "i64") == 0 || strcmp(value, "u8") == 0 || strcmp(value, "u16") == 0 || strcmp(value, "u32") == 0 || strcmp(value, "u64") == 0) - tok = fzl_mktoken(FZL_TOKTYPE_TYPE, line, pos, value, size); + tok = fzl_mktoken(FZL_TOKTYPE_TYPE, l.line, l.col, value, size, l.filename); else - tok = fzl_mktoken(FZL_TOKTYPE_NAME, line, pos, value, size); + tok = fzl_mktoken(FZL_TOKTYPE_NAME, l.line, l.col, value, size, l.filename); free(value); return tok; @@ -120,26 +118,33 @@ fzl_token_t *parse_string_literal(fzl_reader_t *reader) } while (reader->source[lpos] != open_symbol && lpos < reader->size); size++; + fzl_file_loc l; + bool ok = fzl_linked_getpos(reader->linked, reader->position, &l); + if (!ok) + { + snprintf(last_err, sizeof(last_err), "failed to locate line:col"); + return NULL; + } + if (close_symbol != open_symbol) { - snprintf(last_err, sizeof(last_err), "unterminated string at %ld:%ld", - reader->line_n, reader->position - reader->line_start); + snprintf(last_err, sizeof(last_err), "'%s': unterminated string at %ld:%ld", + l.filename, l.line, l.col); return NULL; } if (size == 2) { fzl_token_t *tok = - fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, reader->line_n, - reader->position - reader->line_start, "", 0); + fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, l.line, l.col, "", 0, l.filename); move(reader, 2); return tok; } char *value = malloc(size - 2); memcpy(value, reader->source + reader->position + 1, size - 2); - fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, reader->line_n, - lpos - reader->line_start, value, size - 2); + fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, l.line, l.col, value, + size - 2, l.filename); free(value); move(reader, size); @@ -166,8 +171,16 @@ fzl_token_t *parse_number(fzl_reader_t *reader) memcpy(value, reader->source + reader->position, size); value[size] = '\0'; - fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_NUM_LITERAL, reader->line_n, - lpos - reader->line_start, value, size); + fzl_file_loc l; + bool ok = fzl_linked_getpos(reader->linked, reader->position, &l); + if (!ok) + { + snprintf(last_err, sizeof(last_err), "failed to locate line:col"); + return NULL; + } + + fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_NUM_LITERAL, l.line, l.col, value, + size, l.filename); free(value); if (!tok) @@ -181,14 +194,31 @@ fzl_token_t *parse_number(fzl_reader_t *reader) fzl_token_t *add_single(fzl_reader_t *reader, fzl_toktype_t type) { size_t p = move(reader, 1); - return fzl_mktoken(type, reader->line_n, p - reader->line_start, NULL, 0); + fzl_file_loc l; + bool ok = fzl_linked_getpos(reader->linked, p, &l); + if (!ok) + { + snprintf(last_err, sizeof(last_err), "failed to locate line:col"); + return NULL; + } + + return fzl_mktoken(type, l.line, l.col, NULL, 0, l.filename); } // Add double-char token fzl_token_t *add_double(fzl_reader_t *reader, fzl_toktype_t type) { size_t p = move(reader, 2); - return fzl_mktoken(type, reader->line_n, p - reader->line_start, NULL, 0); + fzl_file_loc l; + bool ok = fzl_linked_getpos(reader->linked, p, &l); + if (!ok) + { + snprintf(last_err, sizeof(last_err), "failed to locate line:col"); + return NULL; + } + + return fzl_mktoken(type, l.line, l.col, NULL, 0, l.filename); +} // Skip symbols until '\n' or EOF void skip_comment(fzl_reader_t *reader) @@ -277,16 +307,35 @@ int fzl_read(fzl_reader_t *reader) token = parse_number(reader); else { - sprintf(last_err, "undefined token '%c' at %ld:%ld", curr, reader->line_n, - p - reader->line_start); + fzl_file_loc l; + bool ok = fzl_linked_getpos(reader->linked, p, &l); + if (!ok) + { + snprintf(last_err, sizeof(last_err), "failed to locate line:col"); + return -1; + } + + sprintf(last_err, "'%s': undefined token '%c' at %ld:%ld", l.filename, + curr, l.line, l.col); return -1; } if (!token) { if (!last_err[0]) - sprintf(last_err, "cannot parse token at %ld:%ld", reader->line_n, - p - reader->line_start); + { + fzl_file_loc l; + bool ok = fzl_linked_getpos(reader->linked, p, &l); + if (!ok) + { + snprintf(last_err, sizeof(last_err), "failed to locate line:col"); + return -1; + } + + sprintf(last_err, "'%s': cannot parse token at %ld:%ld", l.filename, + l.line, l.col); + } + return -1; } diff --git a/src/compiler/fzl_token.c b/src/compiler/fzl_token.c index 96e761e..8ba49a7 100644 --- a/src/compiler/fzl_token.c +++ b/src/compiler/fzl_token.c @@ -4,7 +4,7 @@ #include fzl_token_t *fzl_mktoken(const fzl_toktype_t type, size_t line, size_t col, - void *value, size_t value_len) + void *value, size_t value_len, char *filename) { char *valholder = malloc(value_len + 1); memcpy(valholder, value, value_len); @@ -17,6 +17,7 @@ fzl_token_t *fzl_mktoken(const fzl_toktype_t type, size_t line, size_t col, token->store_value = value_len > 0; token->value = valholder; token->value_sz = value_len; + token->filename = filename; return token; } diff --git a/src/compiler/fzl_walker.c b/src/compiler/fzl_walker.c index 8daeadb..eb46f75 100644 --- a/src/compiler/fzl_walker.c +++ b/src/compiler/fzl_walker.c @@ -167,12 +167,14 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) if (putres != FZL_SYMTABLE_RESULT_OK) { if (putres == FZL_SYMTABLE_RESULT_EXISTS) - snprintf(wlast_err, sizeof(wlast_err), - "cannot define already declared name '%s' at %ld:%ld", - (char *)node->fn.name->value, node->token->ln, - node->token->cn); + snprintf( + wlast_err, sizeof(wlast_err), + "'%s': cannot define already declared name '%s' at %ld:%ld", + node->token->filename, (char *)node->fn.name->value, + node->token->ln, node->token->cn); else - snprintf(wlast_err, sizeof(wlast_err), "failed to store name '%s'", + snprintf(wlast_err, sizeof(wlast_err), + "'%s': failed to store name '%s'", node->fn.name->filename, (char *)node->fn.name->value); return (fzl_walk_res_t){.error = true}; @@ -216,8 +218,10 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) { if (!walker->ctx) { - snprintf(wlast_err, sizeof(wlast_err), - "return cannot be used outside of functions"); + snprintf( + wlast_err, sizeof(wlast_err), + "'%s': return cannot be used outside of functions (at %ld:%ld)", + node->token->filename, node->token->ln, node->token->cn); return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; } @@ -230,10 +234,11 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) if (!is_compatible(retres.type, tok_to_type(walker->ctx->fn->fn.type))) { - snprintf(wlast_err, sizeof(wlast_err), - "incompatible types between return and function type at " - "%ld:%ld", - node->token->ln, node->token->cn); + snprintf( + wlast_err, sizeof(wlast_err), + "'%s': incompatible types between return and function type at " + "%ld:%ld", + node->token->filename, node->token->ln, node->token->cn); return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; } @@ -278,8 +283,8 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) if (!is_compatible(left.type, right.type)) { snprintf(wlast_err, sizeof(wlast_err), - "incompatible types at %ld:%ld", node->token->ln, - node->token->cn); + "'%s': incompatible types at %ld:%ld", node->token->filename, + node->token->ln, node->token->cn); return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; } @@ -325,8 +330,8 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) if (!is_compatible(left.type, right.type)) { snprintf(wlast_err, sizeof(wlast_err), - "incompatible types at %ld:%ld", node->token->ln, - node->token->cn); + "'%s': incompatible types at %ld:%ld", node->token->filename, + node->token->ln, node->token->cn); return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; } @@ -400,9 +405,9 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) if (!exists) { snprintf(wlast_err, sizeof(wlast_err), - "cannot find symbol '%s' at %ld:%ld", - (char *)node->token->value, node->token->ln, - node->token->cn); + "'%s': cannot find symbol '%s' at %ld:%ld", + node->token->filename, (char *)node->token->value, + node->token->ln, node->token->cn); return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; } @@ -446,8 +451,8 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) if (node->call.args_count < 1) { snprintf(wlast_err, sizeof(wlast_err), - "'printline' call with zero arguments at %ld:%ld", - node->token->ln, node->token->cn); + "'%s': 'printline' call with zero arguments at %ld:%ld", + node->token->filename, node->token->ln, node->token->cn); return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; } current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false}; @@ -534,18 +539,19 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) { fzl_token_t *ltok = node->binary_op.left->token; snprintf(wlast_err, sizeof(wlast_err), - "left operand at %ld:%ld is not compatible to integer types", - ltok->ln, ltok->cn); + "'%s': left operand at %ld:%ld is not compatible to integer " + "types", + ltok->filename, ltok->ln, ltok->cn); return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; } if (rres.type < FZL_TYPE_INT8) { fzl_token_t *rtok = node->binary_op.right->token; - snprintf( - wlast_err, sizeof(wlast_err), - "right operand at %ld:%ld is not compatible to integer types", - rtok->ln, rtok->cn); + snprintf(wlast_err, sizeof(wlast_err), + "'%s': right operand at %ld:%ld is not compatible to " + "integer types", + rtok->filename, rtok->ln, rtok->cn); return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; } @@ -586,8 +592,8 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) { fzl_token_t *tok = node->unary_op.operand->token; snprintf(wlast_err, sizeof(wlast_err), - "incompatible with unary operator type at %ld:%ld", tok->ln, - tok->cn); + "'%s': incompatible with unary operator type at %ld:%ld", + tok->filename, tok->ln, tok->cn); return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; } @@ -645,8 +651,8 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) { fzl_token_t *tok = node->binary_op.left->token->value; snprintf(wlast_err, sizeof(wlast_err), - "name '%s' is not exists at %ld:%ld", (char *)tok->value, - tok->ln, tok->cn); + "'%s': name '%s' is not exists at %ld:%ld", tok->filename, + (char *)tok->value, tok->ln, tok->cn); return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; } @@ -654,8 +660,8 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) { fzl_token_t *tok = node->binary_op.right->token; snprintf(wlast_err, sizeof(wlast_err), - "R-Value is not compatible with L-Value at %ld:%ld", - tok->ln, tok->cn); + "'%s': R-Value is not compatible with L-Value at %ld:%ld", + tok->filename, tok->ln, tok->cn); return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; } diff --git a/src/compiler/main.c b/src/compiler/main.c index f8b52e3..305a83c 100644 --- a/src/compiler/main.c +++ b/src/compiler/main.c @@ -1,147 +1,69 @@ +#include #include #include #include #include #include +#include +#include #include #include #include #include -// Build arguments setup descriptor -typedef struct -{ - char *filepath; - char *outpath; - bool verbose; - bool help; -} build_args_t; - -// Print command usage hint -void print_usage() -{ - printf("Usage: fzc [flags] \n"); - printf("Flags:\n"); - printf("\t-v\t--verbose\tdisplay debug information\n"); - printf("\t-h\t--help\t\tprint usage hint (which you're looking at)\n"); -} - -// Read the arguments and build `build_args_t` struct -build_args_t *getargs(int argc, char **argv) -{ - build_args_t *args = malloc(sizeof(build_args_t)); - if (!args) - return NULL; - - args->filepath = NULL; - args->outpath = NULL; - args->verbose = false; - args->help = false; - - size_t args_total = 0; - if (argc > 2) - { - for (int i = 1; i < argc; i++) - { - if (argv[i][0] != '-') - continue; - - args_total++; - - if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) - { - args->help = true; - } - else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) - { - args->verbose = true; - } - else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--out") == 0) - { - if (!argv[i + 1] || argv[i + 1][0] == '-') - { - printf("Error: file path is not specified.\n"); - return NULL; - } - args->outpath = argv[++i]; - } - else - { - printf("Error: unknown argument '%s'\n", argv[i]); - return NULL; - } - } - } - - if (argc - 1 - args_total < 1) - { - printf("Error: source code file is not specified.\n"); - print_usage(); - return NULL; - } - - if (argv[argc - 1][0] == '-') - { - printf("Error: last argument MUST be a path to file.\n"); - printf("Write 'fzc --help' to read help\n"); - return NULL; - } - - args->filepath = argv[argc - 1]; - return args; -} - int main(int argc, char **argv) { - build_args_t *args = getargs(argc, argv); - if (args == NULL) + fzl_options_t *opts = fzl_mkoptions(argc, argv); + if (!opts) return -1; - else if (args->help) + else if (!opts->should_continue) return 0; - if (args->verbose) - printf("> analyze\n-> reading file..."); + if (opts->verbose) + printf("%s> analyze\n-> reading file...%s", FZL_CDEBUG, FZL_CRST); - char *source; - FILE *fd = fopen(args->filepath, "r"); - if (!fd) + fzl_linked_t *linked = fzl_mklinked(); + if (!linked) { - printf("Error: failed to open file '%s'\n", args->filepath); + char *lasterr = fzl_linked_geterror(); + if (lasterr[0]) + printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, lasterr); return -1; } - fseek(fd, 0L, SEEK_END); - size_t fsz = ftell(fd); - rewind(fd); - - source = malloc(fsz + 1); - fread(source, fsz, 1, fd); - fclose(fd); - source[fsz] = '\0'; - - if (args->verbose) + bool read_result = + fzl_linked_add_files(linked, opts->files, opts->files_count); + if (!read_result) { - printf("ok!\n"); - printf("--> Red %ld bytes\n", fsz); - printf("-> tokenizing..."); + char *lasterr = fzl_linked_geterror(); + if (lasterr[0]) + printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, lasterr); + return -1; } - fzl_reader_t *rd = fzl_mkreader(source); - int result = fzl_read(rd); + if (opts->verbose) + { + printf("%sok%s!\n", FZL_COK, FZL_CRST); + printf("%s--> Red %ld bytes%s\n", FZL_CDEBUG, linked->total_sz, FZL_CRST); + printf("%s-> tokenizing...%s", FZL_CDEBUG, FZL_CRST); + } + + fzl_reader_t *rd = fzl_mkreader(linked); + int result = fzl_read(rd); if (result != 0) { - printf("error: %s\n", fzl_reader_geterror()); + printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_reader_geterror()); return -1; } - if (args->verbose) - printf("ok!\n"); + if (opts->verbose) + printf("%sok%s!\n", FZL_COK, FZL_CRST); fzl_reader_ll_t *entry = rd->first; - if (args->verbose) + if (opts->verbose) { - printf("--> structure: "); + printf("%s--> structure: %s", FZL_CDEBUG, FZL_CRST); while (entry) { if (entry->token) @@ -157,42 +79,42 @@ int main(int argc, char **argv) } printf("\n"); - printf("-> parsing..."); + printf("%s-> parsing...%s", FZL_CDEBUG, FZL_CRST); } fzl_parser_t *parser = fzl_mkparser(rd->first); - result = fzl_parse(parser); + result = fzl_parse(parser); if (result != 0) { - printf("Error: %s\n", fzl_parser_geterror()); + printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_parser_geterror()); return -1; } - if (args->verbose) + if (opts->verbose) { - printf("ok!\n"); + printf("%sok%s!\n", FZL_COK, FZL_CRST); fzl_debug_print_ast(parser->root); - printf("> building\n"); - printf("-> walking AST...\n"); + printf("%s> building%s\n", FZL_CDEBUG, FZL_CRST); + printf("%s-> walking AST...%s\n", FZL_CDEBUG, FZL_CRST); } fzl_walker_t *walker = fzl_mkwalker(parser->root); - result = fzl_walk(walker); + result = fzl_walk(walker); if (result != 0) { - printf("Error: %s\n", fzl_walker_geterror()); + printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_walker_geterror()); return -1; } - if (args->verbose) + if (opts->verbose) { - printf("ok!\n"); + printf("%sok%s!\n", FZL_COK, FZL_CRST); - printf("--> Constants table:\n"); + printf("%s--> Constants table%s:\n", FZL_CDEBUG, FZL_CRST); for (size_t i = 0; i < walker->consts->size; i++) printf("---> %s\n", walker->consts->array[i].as.string.chars); - printf("--> Ops:\n"); + printf("%s--> Ops%s:\n", FZL_CDEBUG, FZL_CRST); printf("---> "); for (size_t i = 0; i < walker->op_count; i++) { @@ -202,40 +124,40 @@ int main(int argc, char **argv) } printf("\n"); - printf("-> preparing final write\n"); + printf("%s-> preparing final write%s\n", FZL_CDEBUG, FZL_CRST); } char outpath[256]; - if (args->outpath) - strcpy(outpath, args->outpath); + if (opts->outname) + strcpy(outpath, opts->outname); else strcpy(outpath, "a.fzb"); - if (args->verbose) + if (opts->verbose) { - printf("-> output file path is: %s\n", outpath); - printf("-> writing file..."); + printf("%s-> output file path is%s: %s\n", FZL_CDEBUG, FZL_CRST, outpath); + printf("%s-> writing file...%s", FZL_CDEBUG, FZL_CRST); } fzl_writer_t *writer = fzl_mkwriter(outpath); - result = fzl_write(writer, walker); + result = fzl_write(writer, walker); if (result != 0) { - printf("Error: %s\n", fzl_writer_geterror()); + printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_writer_geterror()); return -1; } - if (args->verbose) - printf("ok!\n"); + if (opts->verbose) + printf("%sok%s!\n", FZL_COK, FZL_CRST); - free(source); - free(args); + fzl_freeoptions(opts); + fzl_freelinked(linked); fzl_freereader(rd); fzl_freeast(parser->root); fzl_freeparser(parser); fzl_freewalker(walker); fzl_freewriter(writer); - printf("done.\n"); + printf("%sCompiled successfully%s.\n", FZL_COK, FZL_CRST); return 0; } diff --git a/src/compiler/utils/fzl_linked.c b/src/compiler/utils/fzl_linked.c new file mode 100644 index 0000000..f7414eb --- /dev/null +++ b/src/compiler/utils/fzl_linked.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include +#include + +char llast_err[256]; + +fzl_linked_t *fzl_mklinked() +{ + fzl_linked_t *l = malloc(sizeof(fzl_linked_t)); + if (!l) + { + snprintf(llast_err, sizeof(llast_err), "potato PC..."); + return NULL; + } + + l->entries = NULL; + l->entries_count = 0; + l->source = NULL; + l->total_sz = 0; + + return l; +} + +bool fzl_linked_add_files(fzl_linked_t *l, char **files, size_t files_count) +{ + if (!l) + return false; + + size_t eremainder = 2; + size_t ecount = 0; + fzl_linked_entry_t *entries = malloc(eremainder * sizeof(fzl_linked_entry_t)); + + size_t current_start = 0; + for (size_t i = 0; i < files_count; i++) + { + char *source; + FILE *fd = fopen(files[i], "r"); + if (!fd) + { + snprintf(llast_err, sizeof(llast_err), "failed to open file '%s'\n", + files[i]); + free(entries); + return false; + } + + fseek(fd, 0L, SEEK_END); + size_t file_sz = ftell(fd); + rewind(fd); + + source = malloc(file_sz + 1); + fread(source, file_sz, 1, fd); + fclose(fd); + source[file_sz] = 0; + + if (eremainder <= ecount) + { + eremainder *= 2; + entries = realloc(entries, eremainder * sizeof(fzl_linked_entry_t)); + if (!entries) + { + snprintf(llast_err, sizeof(llast_err), "potato pc..."); + free(source); + return NULL; + } + } + entries[ecount++] = + (fzl_linked_entry_t){.name = files[i], + .start = current_start, + .end = current_start + file_sz - 1}; + + if (!l->source) + l->source = malloc(file_sz); + else + l->source = realloc(l->source, current_start + file_sz); + + if (!l->source) + { + snprintf(llast_err, sizeof(llast_err), + "failed to allocate space for source code holder"); + free(entries); + free(source); + return NULL; + } + + strcpy(l->source + current_start, source); + current_start += file_sz; + } + + l->source = realloc(l->source, current_start + 1); + if (!l->source) + { + snprintf(llast_err, sizeof(llast_err), + "not enough space for entire source\n"); + free(entries); + return NULL; + } + + l->source[current_start] = 0; + + l->entries = entries; + l->entries_count = ecount; + l->total_sz = current_start; + return true; +} + +char *fzl_linked_geterror() { return llast_err; } + +bool fzl_linked_getpos(fzl_linked_t *l, size_t pos, fzl_file_loc *res) +{ + if (!l) + return false; + + bool found = false; + fzl_linked_entry_t e; + for (size_t i = 0; i < l->entries_count; i++) + { + e = l->entries[i]; + if (pos >= e.start && pos <= e.end) + { + found = true; + break; + } + } + + if (!found) + return NULL; + + size_t line = 1; + size_t line_start = e.start; + for (size_t p = e.start; p < pos; p++) + { + if (l->source[p] == '\n') + { + line++; + line_start = p + 1; + } + } + + *res = + (fzl_file_loc){.filename = e.name, .line = line, .col = pos - line_start}; + return true; +} + +void fzl_freelinked(fzl_linked_t *linked) +{ + if (!linked) + return; + + if (linked->source) + free(linked->source); + + if (linked->entries) + free(linked->entries); + + free(linked); +} diff --git a/src/compiler/utils/fzl_options.c b/src/compiler/utils/fzl_options.c new file mode 100644 index 0000000..4060189 --- /dev/null +++ b/src/compiler/utils/fzl_options.c @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include + +const char version[] = "FZL Compiler 1.0"; + +void print_help() +{ + printf("Usage: fzc [flags] \n"); + printf("Available flags:\n"); + printf("\t-h\t--help\t\tPrint help\n"); + printf("\t-v\t--verbose\tDisplay compilation info (tokens, AST, consts " + "table, etc)\n"); + printf("\t-V\t--version\tPrint compiler version\n"); + printf("\t-o\t--out\t\tSet compiled file name\n"); +} + +fzl_options_t *fzl_mkoptions(int argc, char **argv) +{ + fzl_options_t *opts = malloc(sizeof(fzl_options_t)); + if (!opts) + { + printf("%sBruh... Potato PC%s\n", FZL_CERROR, FZL_CRST); + return NULL; + } + + memset(opts, 0, sizeof(fzl_options_t)); + + if (argc < 2) + { + print_help(); + opts->should_continue = false; + return opts; + } + + size_t i; + for (i = 1; i < argc; i++) + { + if (argv[i][0] != '-') + break; + + if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) + { + print_help(); + opts->should_continue = false; + break; + } + else if (strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) + { + printf("%s\n", version); + opts->should_continue = false; + break; + } + else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) + { + opts->verbose = true; + } + else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--out") == 0) + { + if (i == argc - 1) + { + printf("%sError%s: missing out file name\n", FZL_CERROR, FZL_CRST); + free(opts); + return NULL; + } + + char *filename = argv[++i]; + opts->outname = filename; + } + else + { + printf("%sError%s: undefined flag '%s'\n", FZL_CERROR, FZL_CRST, argv[i]); + free(opts); + return NULL; + } + } + + size_t fremainder = 2; + size_t fcount = 0; + char **files = malloc(fremainder * sizeof(char *)); + + for (; i < argc; i++) + { + if (argv[i][0] == '-') + { + printf( + "%sWarning%s: unhandled flag '%s' (should be defined before sources " + "list)\n", + FZL_CWARNING, FZL_CRST, argv[i]); + continue; + } + + if (fremainder <= fcount) + { + fremainder *= 2; + files = realloc(files, fremainder * sizeof(char *)); + } + + files[fcount++] = argv[i]; + } + + opts->files = files; + opts->files_count = fcount; + + if (i < argc - 1) + { + printf("%sError%s: flags should go before source files list.\n", FZL_CERROR, + FZL_CRST); + printf("Remain %zu arguments are not handled.\n", argc - 1 - i); + + free(files); + free(opts); + return NULL; + } + + opts->should_continue = true; + return opts; +} + +void fzl_freeoptions(fzl_options_t *options) +{ + if (!options) + return; + + if (options->files) + free(options->files); + + free(options); +} diff --git a/src/vm/fzl_vm.c b/src/vm/fzl_vm.c index 662dd2f..899c82b 100644 --- a/src/vm/fzl_vm.c +++ b/src/vm/fzl_vm.c @@ -11,8 +11,6 @@ #include #include -// NOTE: need to add optimized arithmetics in near future - char last_err[256]; static char *expect_hdr = "FZL\0\1";