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
This commit is contained in:
samsonium
2026-10-15 17:20:43 +03:00
parent 1035b9193c
commit 69b2253c34
22 changed files with 739 additions and 327 deletions
+10
View File
@@ -16,6 +16,8 @@ add_executable(fzc
src/compiler/fzl_writer.c src/compiler/fzl_writer.c
src/compiler/utils/fzl_const_pool.c src/compiler/utils/fzl_const_pool.c
src/compiler/utils/fzl_symtable.c src/compiler/utils/fzl_symtable.c
src/compiler/utils/fzl_linked.c
src/compiler/utils/fzl_options.c
src/compiler/main.c) src/compiler/main.c)
# Virtual machine # Virtual machine
@@ -59,6 +61,10 @@ add_test(
NAME compile_fn NAME compile_fn
COMMAND fzc -o "${CMAKE_CURRENT_BINARY_DIR}/fn.fzb" "${CMAKE_CURRENT_SOURCE_DIR}/exl/fn.fzs" 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) set_tests_properties(compile_problematic_hw PROPERTIES WILL_FAIL TRUE)
@@ -90,4 +96,8 @@ add_test(
NAME runtime_fn NAME runtime_fn
COMMAND fz "${CMAKE_CURRENT_BINARY_DIR}/fn.fzb" COMMAND fz "${CMAKE_CURRENT_BINARY_DIR}/fn.fzb"
) )
add_test(
NAME runtime_comment
COMMAND fz "${CMAKE_CURRENT_BINARY_DIR}/comment.fzb"
)
+6 -6
View File
@@ -1,7 +1,7 @@
printline(2 + 2 * 2) printline(2 + 2 * 2);
printline(-1 + 1) printline(-1 + 1);
printline(2 ^ 2) printline(2 ^ 2);
printline(1 + 1 * 1 / 1) printline(1 + 1 * 1 / 1);
printline(4 % 2) printline(4 % 2);
printline(10 / 2) printline(10 / 2);
+1 -1
View File
@@ -1,3 +1,3 @@
// I'm a comment // I'm a comment
printline("Comment is skipped") printline("Comment is skipped");;;;;
+5 -5
View File
@@ -1,16 +1,16 @@
bool flag = true bool flag = true;
if (!flag) if (!flag)
printline("buhhh, flag is not true") printline("buhhh, flag is not true");
else if (2 + 2 >= 4) else if (2 + 2 >= 4)
{ {
printline ("two plus two is four") printline ("two plus two is four");
} }
else { else {
printline("gotcha") printline("gotcha");
} }
{ {
printline("block after") printline("block after");
} }
+10 -10
View File
@@ -1,24 +1,24 @@
int fib(int n) int fib(int n)
{ {
if (n <= 1) 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) uint sum(uint a, uint b)
{ {
return a + b return a + b;
} }
printline("Test #1: fibonacci") printline("Test #1: fibonacci");
int result = fib(7) int result = fib(7);
if (result == 13) if (result == 13)
printline("Recurse test passed") printline("Recurse test passed");
else printline("Recurse test failed") else printline("Recurse test failed");
printline("Test #2: sum") printline("Test #2: sum");
if (sum(2, 2) == 4) if (sum(2, 2) == 4)
printline("Sum test passed") printline("Sum test passed");
else printline("Sum test failed") else printline("Sum test failed");
+1 -1
View File
@@ -1,2 +1,2 @@
printline('hello, world') printline('hello, world');
+1 -1
View File
@@ -1 +1 @@
printline("") printline("");
+1 -1
View File
@@ -1 +1 @@
printline("hello) printline("hello);
+9 -9
View File
@@ -1,13 +1,13 @@
uint work_it = 21 * 2 ^ 2 uint work_it = 21 * 2 ^ 2;
int make_it = 10 int make_it = 10;
u64 do_it u64 do_it;
do_it = 15 do_it = 15;
printline(work_it) printline(work_it);
printline(make_it + do_it) printline(make_it + do_it);
char make_us char make_us;
str floyd = "hello, Pink Floyd!" str floyd = "hello, Pink Floyd!";
printline(floyd) printline(floyd);
+10
View File
@@ -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
+4 -3
View File
@@ -2,6 +2,7 @@
#define FZL_READER_H #define FZL_READER_H
#include <compiler/fzl_token.h> #include <compiler/fzl_token.h>
#include <compiler/utils/fzl_linked.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@@ -19,16 +20,16 @@ typedef struct
fzl_reader_ll_t *first; fzl_reader_ll_t *first;
fzl_reader_ll_t *last; fzl_reader_ll_t *last;
fzl_linked_t *linked;
char *source; char *source;
size_t size; size_t size;
size_t position; size_t position;
size_t line_start;
size_t line_n;
} fzl_reader_t; } fzl_reader_t;
// Allocate new reader // Allocate new reader
fzl_reader_t *fzl_mkreader(char *source); fzl_reader_t *fzl_mkreader(fzl_linked_t *linked);
// Read source file // Read source file
int fzl_read(fzl_reader_t *reader); int fzl_read(fzl_reader_t *reader);
+2 -1
View File
@@ -61,11 +61,12 @@ typedef struct
bool store_value; bool store_value;
void *value; void *value;
uint16_t value_sz; uint16_t value_sz;
char *filename;
} fzl_token_t; } fzl_token_t;
// Allocate new token // Allocate new token
fzl_token_t *fzl_mktoken(const fzl_toktype_t type, size_t line, size_t col, 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 // Free token and its contents
void fzl_freetoken(fzl_token_t *token); void fzl_freetoken(fzl_token_t *token);
+49
View File
@@ -0,0 +1,49 @@
#ifndef FZL_LINKED_H
#define FZL_LINKED_H
#include <stdbool.h>
#include <stddef.h>
// 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
+25
View File
@@ -0,0 +1,25 @@
#ifndef FZL_OPTIONS_H
#define FZL_OPTIONS_H
#include <stdbool.h>
#include <stddef.h>
// 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
+111 -61
View File
@@ -7,6 +7,7 @@
#include <string.h> #include <string.h>
char plast_err[256]; char plast_err[256];
fzl_token_t *last_known_tok = NULL;
fzl_parser_t *fzl_mkparser(fzl_reader_ll_t *first) 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) if (!parser || !parser->cursor)
return NULL; return NULL;
last_known_tok = parser->cursor->token;
return 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); fzl_node_t *node = parse_expression(parser);
if (!is(parser, FZL_TOKTYPE_RPAREN)) if (!is(parser, FZL_TOKTYPE_RPAREN))
{ {
snprintf(plast_err, sizeof(plast_err), "expected ')' at %ld:%ld", snprintf(plast_err, sizeof(plast_err), "'%s': expected ')' at %ld:%ld",
parser->cursor->token->ln, parser->cursor->token->cn); peek(parser)->filename, peek(parser)->ln, peek(parser)->cn);
return NULL; return NULL;
} }
consume(parser); consume(parser);
@@ -169,8 +172,27 @@ fzl_node_t *parse_primary(fzl_parser_t *parser)
fzl_token_t *name = consume(parser); fzl_token_t *name = consume(parser);
return fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); 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", 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); peek(parser)->ln, peek(parser)->cn);
return NULL; return NULL;
} }
@@ -186,8 +208,10 @@ fzl_node_t *parse_postfix(fzl_parser_t *parser)
if (!left) if (!left)
{ {
snprintf(plast_err, sizeof(plast_err), "failed to parse postfix at %ld:%ld", if (!plast_err[0])
peek(parser)->ln, peek(parser)->cn); 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; return NULL;
} }
@@ -226,8 +250,8 @@ fzl_node_t *parse_postfix(fzl_parser_t *parser)
{ {
free(args); free(args);
snprintf(plast_err, sizeof(plast_err), snprintf(plast_err, sizeof(plast_err),
"expected ')' after argument list at %ld:%ld", peek(parser)->ln, "'%s': expected ')' after argument list at %ld:%ld",
peek(parser)->cn); peek(parser)->filename, peek(parser)->ln, peek(parser)->cn);
return NULL; return NULL;
} }
@@ -274,7 +298,9 @@ fzl_node_t *parse_power(fzl_parser_t *parser)
if (!left) if (!left)
{ {
snprintf(plast_err, sizeof(plast_err), "failed to parse power at %ld:%ld", 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); peek(parser)->ln, peek(parser)->cn);
return NULL; return NULL;
} }
@@ -286,9 +312,10 @@ fzl_node_t *parse_power(fzl_parser_t *parser)
right = parse_unary(parser); right = parse_unary(parser);
if (!right) if (!right)
{ {
if (!plast_err[0])
snprintf(plast_err, sizeof(plast_err), snprintf(plast_err, sizeof(plast_err),
"failed to parse right side of power at %ld:%ld", "'%s': failed to parse right side of power at %ld:%ld",
peek(parser)->ln, peek(parser)->cn); peek(parser)->filename, peek(parser)->ln, peek(parser)->cn);
return NULL; return NULL;
} }
@@ -314,8 +341,9 @@ fzl_node_t *parse_factor(fzl_parser_t *parser)
if (!left) if (!left)
{ {
if (!plast_err[0]) if (!plast_err[0])
snprintf(plast_err, sizeof(plast_err), "invalid expression at %ld:%ld", snprintf(plast_err, sizeof(plast_err),
parser->cursor->token->ln, parser->cursor->token->cn); "'%s': invalid expression at %ld:%ld", peek(parser)->filename,
peek(parser)->ln, peek(parser)->cn);
return NULL; return NULL;
} }
@@ -327,9 +355,10 @@ fzl_node_t *parse_factor(fzl_parser_t *parser)
right = parse_factor(parser); right = parse_factor(parser);
if (!right) if (!right)
{ {
if (!plast_err[0])
snprintf(plast_err, sizeof(plast_err), snprintf(plast_err, sizeof(plast_err),
"unfinished factor (mul/div) expression at %ld:%ld", "'%s': unfinished factor (mul/div) expression at %ld:%ld",
left->token->ln, left->token->cn); left->token->filename, left->token->ln, left->token->cn);
return NULL; return NULL;
} }
@@ -353,8 +382,10 @@ fzl_node_t *parse_term(fzl_parser_t *parser)
if (!left) if (!left)
{ {
snprintf(plast_err, sizeof(plast_err), "invalid expression at %ld:%ld", if (!plast_err[0])
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; return NULL;
} }
@@ -365,9 +396,10 @@ fzl_node_t *parse_term(fzl_parser_t *parser)
right = parse_factor(parser); right = parse_factor(parser);
if (!right) if (!right)
{ {
if (!plast_err[0])
snprintf(plast_err, sizeof(plast_err), snprintf(plast_err, sizeof(plast_err),
"unfinished term (add/sub) expression at %ld:%ld", "'%s': unfinished term (add/sub) expression at %ld:%ld",
left->token->ln, left->token->cn); left->token->filename, left->token->ln, left->token->cn);
return NULL; return NULL;
} }
@@ -400,8 +432,10 @@ fzl_node_t *parse_cond(fzl_parser_t *parser)
right = parse_term(parser); right = parse_term(parser);
if (!right) if (!right)
{ {
snprintf(plast_err, sizeof(plast_err), "unfinished expression at %ld:%ld", if (!plast_err[0])
op->ln, op->cn); snprintf(plast_err, sizeof(plast_err),
"'%s': unfinished expression at %ld:%ld", op->filename, op->ln,
op->cn);
return NULL; return NULL;
} }
@@ -456,8 +490,10 @@ fzl_node_t *parse_and(fzl_parser_t *parser)
right = parse_cond(parser); right = parse_cond(parser);
if (!right) if (!right)
{ {
snprintf(plast_err, sizeof(plast_err), "unfinished expression at %ld:%ld", if (!plast_err[0])
or->ln, or->cn); snprintf(plast_err, sizeof(plast_err),
"'%s': unfinished expression at %ld:%ld", or->filename, or->ln,
or->cn);
return NULL; return NULL;
} }
@@ -488,8 +524,10 @@ fzl_node_t *parse_or(fzl_parser_t *parser)
right = parse_and(parser); right = parse_and(parser);
if (!right) if (!right)
{ {
snprintf(plast_err, sizeof(plast_err), "unfinished expression at %ld:%ld", if (!plast_err[0])
or->ln, or->cn); snprintf(plast_err, sizeof(plast_err),
"'%s': unfinished expression at %ld:%ld", or->filename, or->ln,
or->cn);
return NULL; return NULL;
} }
@@ -508,6 +546,8 @@ fzl_node_t *parse_expression(fzl_parser_t *parser) { return parse_and(parser); }
// Statement parsing // Statement parsing
fzl_node_t *parse_statement(fzl_parser_t *parser) fzl_node_t *parse_statement(fzl_parser_t *parser)
{ {
fzl_node_t *res = NULL;
if (is(parser, FZL_TOKTYPE_TYPE)) if (is(parser, FZL_TOKTYPE_TYPE))
{ {
fzl_token_t *type = peek(parser); 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) if (tok->type != FZL_TOKTYPE_NAME)
{ {
snprintf(plast_err, sizeof(plast_err), snprintf(plast_err, sizeof(plast_err),
"expected name in function definition at %ld:%ld", tok->ln, "'%s': expected name in function definition at %ld:%ld",
tok->cn); tok->filename, tok->ln, tok->cn);
return NULL; return NULL;
} }
@@ -530,7 +570,8 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
if (lparen->type != FZL_TOKTYPE_LPAREN) if (lparen->type != FZL_TOKTYPE_LPAREN)
{ {
snprintf(plast_err, sizeof(plast_err), 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; return NULL;
} }
@@ -540,7 +581,7 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
while (peek(parser) && !is(parser, FZL_TOKTYPE_RPAREN)) while (peek(parser) && !is(parser, FZL_TOKTYPE_RPAREN))
{ {
fzl_node_t *arg = parse_statement(parser); fzl_node_t *arg = parse_expression(parser);
if (!arg) if (!arg)
return NULL; return NULL;
@@ -560,16 +601,16 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
if (rparen->type != FZL_TOKTYPE_RPAREN) if (rparen->type != FZL_TOKTYPE_RPAREN)
{ {
snprintf(plast_err, sizeof(plast_err), snprintf(plast_err, sizeof(plast_err),
"expected ')' after argument list at %ld:%ld", rparen->ln, "'%s': expected ')' after argument list at %ld:%ld",
rparen->cn); rparen->filename, rparen->ln, rparen->cn);
return NULL; return NULL;
} }
if (!is(parser, FZL_TOKTYPE_LBRACE)) if (!is(parser, FZL_TOKTYPE_LBRACE))
{ {
fzl_token_t *tok = peek(parser); fzl_token_t *tok = peek(parser);
snprintf(plast_err, sizeof(plast_err), "expected '{' at %ld:%ld", snprintf(plast_err, sizeof(plast_err), "'%s': expected '{' at %ld:%ld",
tok->ln, tok->cn); tok->filename, tok->ln, tok->cn);
return NULL; return NULL;
} }
@@ -586,14 +627,15 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
return node; return node;
} }
else if (type->type == FZL_TOKTYPE_TYPE ||
if (type->type == FZL_TOKTYPE_TYPE || next(parser)->type == FZL_TOKTYPE_EQ) next(parser)->type == FZL_TOKTYPE_EQ)
{ {
fzl_node_t *identifier = parse_primary(parser); fzl_node_t *identifier = parse_primary(parser);
if (!identifier || identifier->type != FZL_NODETYPE_IDENTIFIER) 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); type->ln, type->cn);
return NULL; return NULL;
} }
@@ -602,9 +644,8 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
left->var.type = type; left->var.type = type;
left->var.identifier = identifier; left->var.identifier = identifier;
if (!is(parser, FZL_TOKTYPE_EQ)) if (is(parser, FZL_TOKTYPE_EQ))
return left; {
fzl_node_t *right; fzl_node_t *right;
while (is(parser, FZL_TOKTYPE_EQ)) while (is(parser, FZL_TOKTYPE_EQ))
{ {
@@ -619,12 +660,12 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
left = node; left = node;
} }
return left;
}
} }
if (is(parser, FZL_TOKTYPE_NAME) && next(parser)->type == FZL_TOKTYPE_EQ) res = left;
}
}
else if (is(parser, FZL_TOKTYPE_NAME) && next(parser)->type == FZL_TOKTYPE_EQ)
{ {
fzl_token_t *name = consume(parser); fzl_token_t *name = consume(parser);
fzl_node_t *left = fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); 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; left = assn;
} }
return left; res = left;
} }
else if (is(parser, FZL_TOKTYPE_RETURN))
if (is(parser, FZL_TOKTYPE_RETURN))
{ {
fzl_token_t *ret = consume(parser); fzl_token_t *ret = consume(parser);
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_RETURN, ret); 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); fzl_node_t *retval = parse_expression(parser);
if (!retval) if (!retval)
return NULL; return NULL;
node->ret.value = retval; node->ret.value = retval;
return node;
} }
if (is(parser, FZL_TOKTYPE_IF)) res = node;
}
else if (is(parser, FZL_TOKTYPE_IF))
{ {
fzl_token_t *if_tok = consume(parser); fzl_token_t *if_tok = consume(parser);
fzl_token_t *lparen = consume(parser); fzl_token_t *lparen = consume(parser);
if (lparen->type != FZL_TOKTYPE_LPAREN) if (lparen->type != FZL_TOKTYPE_LPAREN)
{ {
snprintf(plast_err, sizeof(plast_err), snprintf(plast_err, sizeof(plast_err),
"expected '(' before condition at %ld:%ld", lparen->ln, "'%s': expected '(' before condition at %ld:%ld",
lparen->cn); lparen->filename, lparen->ln, lparen->cn);
return NULL; return NULL;
} }
@@ -686,8 +723,8 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
if (rparen->type != FZL_TOKTYPE_RPAREN) if (rparen->type != FZL_TOKTYPE_RPAREN)
{ {
snprintf(plast_err, sizeof(plast_err), snprintf(plast_err, sizeof(plast_err),
"expected ')' after condition at %ld:%ld", rparen->ln, "'%s': expected ')' after condition at %ld:%ld",
rparen->cn); rparen->filename, rparen->ln, rparen->cn);
return NULL; return NULL;
} }
@@ -711,8 +748,7 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
return stmt_node; return stmt_node;
} }
else if (is(parser, FZL_TOKTYPE_LBRACE))
if (is(parser, FZL_TOKTYPE_LBRACE))
{ {
fzl_token_t *block_tok = consume(parser); fzl_token_t *block_tok = consume(parser);
@@ -735,10 +771,11 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
stmts[count++] = node; stmts[count++] = node;
} }
fzl_token_t *rbrace = consume(parser); 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), 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; return NULL;
} }
@@ -748,7 +785,20 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
return node; 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 // Internal parsing entry point
+86 -37
View File
@@ -1,4 +1,5 @@
#include "compiler/fzl_token.h" #include "compiler/fzl_token.h"
#include "compiler/utils/fzl_linked.h"
#include <compiler/fzl_reader.h> #include <compiler/fzl_reader.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@@ -9,7 +10,7 @@
// Last error from reader // Last error from reader
static char last_err[256] = {0}; 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)); fzl_reader_ll_t *first_node = malloc(sizeof(fzl_reader_ll_t));
first_node->token = NULL; first_node->token = NULL;
@@ -18,11 +19,10 @@ fzl_reader_t *fzl_mkreader(char *source)
fzl_reader_t *reader = malloc(sizeof(fzl_reader_t)); fzl_reader_t *reader = malloc(sizeof(fzl_reader_t));
reader->first = first_node; reader->first = first_node;
reader->last = first_node; reader->last = first_node;
reader->source = source; reader->linked = linked;
reader->size = strlen(source); reader->source = linked->source;
reader->size = linked->total_sz;
reader->position = 0; reader->position = 0;
reader->line_n = 1;
reader->line_start = 0;
return reader; return reader;
} }
@@ -30,21 +30,12 @@ fzl_reader_t *fzl_mkreader(char *source)
// --- Read zone --- // --- Read zone ---
// Move cursor forward // Move cursor forward
// @deprecated
static size_t move(fzl_reader_t *reader, size_t len) static size_t move(fzl_reader_t *reader, size_t len)
{ {
if (!reader) if (!reader)
return 0; 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; return reader->position += len;
} }
@@ -71,17 +62,24 @@ fzl_token_t *parse_name(fzl_reader_t *reader)
move(reader, size); move(reader, size);
fzl_token_t *tok; fzl_token_t *tok;
size_t line = reader->line_n; fzl_file_loc l;
size_t pos = start - reader->line_start; 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) 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) 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) 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) 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 || else if (strcmp(value, "str") == 0 || strcmp(value, "char") == 0 ||
strcmp(value, "bool") == 0 || strcmp(value, "uint") == 0 || strcmp(value, "bool") == 0 || strcmp(value, "uint") == 0 ||
strcmp(value, "int") == 0 || strcmp(value, "i8") == 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, "i64") == 0 || strcmp(value, "u8") == 0 ||
strcmp(value, "u16") == 0 || strcmp(value, "u32") == 0 || strcmp(value, "u16") == 0 || strcmp(value, "u32") == 0 ||
strcmp(value, "u64") == 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 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); free(value);
return tok; 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); } while (reader->source[lpos] != open_symbol && lpos < reader->size);
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) if (close_symbol != open_symbol)
{ {
snprintf(last_err, sizeof(last_err), "unterminated string at %ld:%ld", snprintf(last_err, sizeof(last_err), "'%s': unterminated string at %ld:%ld",
reader->line_n, reader->position - reader->line_start); l.filename, l.line, l.col);
return NULL; return NULL;
} }
if (size == 2) if (size == 2)
{ {
fzl_token_t *tok = fzl_token_t *tok =
fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, reader->line_n, fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, l.line, l.col, "", 0, l.filename);
reader->position - reader->line_start, "", 0);
move(reader, 2); move(reader, 2);
return tok; return tok;
} }
char *value = malloc(size - 2); char *value = malloc(size - 2);
memcpy(value, reader->source + reader->position + 1, size - 2); memcpy(value, reader->source + reader->position + 1, size - 2);
fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, reader->line_n, fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, l.line, l.col, value,
lpos - reader->line_start, value, size - 2); size - 2, l.filename);
free(value); free(value);
move(reader, size); move(reader, size);
@@ -166,8 +171,16 @@ fzl_token_t *parse_number(fzl_reader_t *reader)
memcpy(value, reader->source + reader->position, size); memcpy(value, reader->source + reader->position, size);
value[size] = '\0'; value[size] = '\0';
fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_NUM_LITERAL, reader->line_n, fzl_file_loc l;
lpos - reader->line_start, value, size); 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); free(value);
if (!tok) 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) fzl_token_t *add_single(fzl_reader_t *reader, fzl_toktype_t type)
{ {
size_t p = move(reader, 1); 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 // Add double-char token
fzl_token_t *add_double(fzl_reader_t *reader, fzl_toktype_t type) fzl_token_t *add_double(fzl_reader_t *reader, fzl_toktype_t type)
{ {
size_t p = move(reader, 2); 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 // Skip symbols until '\n' or EOF
void skip_comment(fzl_reader_t *reader) void skip_comment(fzl_reader_t *reader)
@@ -277,16 +307,35 @@ int fzl_read(fzl_reader_t *reader)
token = parse_number(reader); token = parse_number(reader);
else else
{ {
sprintf(last_err, "undefined token '%c' at %ld:%ld", curr, reader->line_n, fzl_file_loc l;
p - reader->line_start); 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; return -1;
} }
if (!token) if (!token)
{ {
if (!last_err[0]) 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; return -1;
} }
+2 -1
View File
@@ -4,7 +4,7 @@
#include <string.h> #include <string.h>
fzl_token_t *fzl_mktoken(const fzl_toktype_t type, size_t line, size_t col, 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); char *valholder = malloc(value_len + 1);
memcpy(valholder, value, value_len); 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->store_value = value_len > 0;
token->value = valholder; token->value = valholder;
token->value_sz = value_len; token->value_sz = value_len;
token->filename = filename;
return token; return token;
} }
+37 -31
View File
@@ -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_OK)
{ {
if (putres == FZL_SYMTABLE_RESULT_EXISTS) if (putres == FZL_SYMTABLE_RESULT_EXISTS)
snprintf(wlast_err, sizeof(wlast_err), snprintf(
"cannot define already declared name '%s' at %ld:%ld", wlast_err, sizeof(wlast_err),
(char *)node->fn.name->value, node->token->ln, "'%s': cannot define already declared name '%s' at %ld:%ld",
node->token->cn); node->token->filename, (char *)node->fn.name->value,
node->token->ln, node->token->cn);
else 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); (char *)node->fn.name->value);
return (fzl_walk_res_t){.error = true}; 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) if (!walker->ctx)
{ {
snprintf(wlast_err, sizeof(wlast_err), snprintf(
"return cannot be used outside of functions"); 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}; 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, if (!is_compatible(retres.type,
tok_to_type(walker->ctx->fn->fn.type))) tok_to_type(walker->ctx->fn->fn.type)))
{ {
snprintf(wlast_err, sizeof(wlast_err), snprintf(
"incompatible types between return and function type at " wlast_err, sizeof(wlast_err),
"'%s': incompatible types between return and function type at "
"%ld:%ld", "%ld:%ld",
node->token->ln, node->token->cn); node->token->filename, node->token->ln, node->token->cn);
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; 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)) if (!is_compatible(left.type, right.type))
{ {
snprintf(wlast_err, sizeof(wlast_err), snprintf(wlast_err, sizeof(wlast_err),
"incompatible types at %ld:%ld", node->token->ln, "'%s': incompatible types at %ld:%ld", node->token->filename,
node->token->cn); node->token->ln, node->token->cn);
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; 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)) if (!is_compatible(left.type, right.type))
{ {
snprintf(wlast_err, sizeof(wlast_err), snprintf(wlast_err, sizeof(wlast_err),
"incompatible types at %ld:%ld", node->token->ln, "'%s': incompatible types at %ld:%ld", node->token->filename,
node->token->cn); node->token->ln, node->token->cn);
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; 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) if (!exists)
{ {
snprintf(wlast_err, sizeof(wlast_err), snprintf(wlast_err, sizeof(wlast_err),
"cannot find symbol '%s' at %ld:%ld", "'%s': cannot find symbol '%s' at %ld:%ld",
(char *)node->token->value, node->token->ln, node->token->filename, (char *)node->token->value,
node->token->cn); node->token->ln, node->token->cn);
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; 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) if (node->call.args_count < 1)
{ {
snprintf(wlast_err, sizeof(wlast_err), snprintf(wlast_err, sizeof(wlast_err),
"'printline' call with zero arguments at %ld:%ld", "'%s': 'printline' call with zero arguments at %ld:%ld",
node->token->ln, node->token->cn); node->token->filename, node->token->ln, node->token->cn);
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
} }
current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false}; 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; fzl_token_t *ltok = node->binary_op.left->token;
snprintf(wlast_err, sizeof(wlast_err), snprintf(wlast_err, sizeof(wlast_err),
"left operand at %ld:%ld is not compatible to integer types", "'%s': left operand at %ld:%ld is not compatible to integer "
ltok->ln, ltok->cn); "types",
ltok->filename, ltok->ln, ltok->cn);
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
} }
if (rres.type < FZL_TYPE_INT8) if (rres.type < FZL_TYPE_INT8)
{ {
fzl_token_t *rtok = node->binary_op.right->token; fzl_token_t *rtok = node->binary_op.right->token;
snprintf( snprintf(wlast_err, sizeof(wlast_err),
wlast_err, sizeof(wlast_err), "'%s': right operand at %ld:%ld is not compatible to "
"right operand at %ld:%ld is not compatible to integer types", "integer types",
rtok->ln, rtok->cn); rtok->filename, rtok->ln, rtok->cn);
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; 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; fzl_token_t *tok = node->unary_op.operand->token;
snprintf(wlast_err, sizeof(wlast_err), snprintf(wlast_err, sizeof(wlast_err),
"incompatible with unary operator type at %ld:%ld", tok->ln, "'%s': incompatible with unary operator type at %ld:%ld",
tok->cn); tok->filename, tok->ln, tok->cn);
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; 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; fzl_token_t *tok = node->binary_op.left->token->value;
snprintf(wlast_err, sizeof(wlast_err), snprintf(wlast_err, sizeof(wlast_err),
"name '%s' is not exists at %ld:%ld", (char *)tok->value, "'%s': name '%s' is not exists at %ld:%ld", tok->filename,
tok->ln, tok->cn); (char *)tok->value, tok->ln, tok->cn);
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; 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; fzl_token_t *tok = node->binary_op.right->token;
snprintf(wlast_err, sizeof(wlast_err), snprintf(wlast_err, sizeof(wlast_err),
"R-Value is not compatible with L-Value at %ld:%ld", "'%s': R-Value is not compatible with L-Value at %ld:%ld",
tok->ln, tok->cn); tok->filename, tok->ln, tok->cn);
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
} }
+56 -134
View File
@@ -1,147 +1,69 @@
#include <common/fzl_colors.h>
#include <compiler/fzl_debug.h> #include <compiler/fzl_debug.h>
#include <compiler/fzl_parser.h> #include <compiler/fzl_parser.h>
#include <compiler/fzl_reader.h> #include <compiler/fzl_reader.h>
#include <compiler/fzl_walker.h> #include <compiler/fzl_walker.h>
#include <compiler/fzl_writer.h> #include <compiler/fzl_writer.h>
#include <compiler/utils/fzl_linked.h>
#include <compiler/utils/fzl_options.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
// 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] <file path>\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) int main(int argc, char **argv)
{ {
build_args_t *args = getargs(argc, argv); fzl_options_t *opts = fzl_mkoptions(argc, argv);
if (args == NULL) if (!opts)
return -1; return -1;
else if (args->help) else if (!opts->should_continue)
return 0; return 0;
if (args->verbose) if (opts->verbose)
printf("> analyze\n-> reading file..."); printf("%s> analyze\n-> reading file...%s", FZL_CDEBUG, FZL_CRST);
char *source; fzl_linked_t *linked = fzl_mklinked();
FILE *fd = fopen(args->filepath, "r"); if (!linked)
if (!fd)
{ {
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; return -1;
} }
fseek(fd, 0L, SEEK_END); bool read_result =
size_t fsz = ftell(fd); fzl_linked_add_files(linked, opts->files, opts->files_count);
rewind(fd); if (!read_result)
source = malloc(fsz + 1);
fread(source, fsz, 1, fd);
fclose(fd);
source[fsz] = '\0';
if (args->verbose)
{ {
printf("ok!\n"); char *lasterr = fzl_linked_geterror();
printf("--> Red %ld bytes\n", fsz); if (lasterr[0])
printf("-> tokenizing..."); printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, lasterr);
return -1;
} }
fzl_reader_t *rd = fzl_mkreader(source); 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); int result = fzl_read(rd);
if (result != 0) if (result != 0)
{ {
printf("error: %s\n", fzl_reader_geterror()); printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_reader_geterror());
return -1; return -1;
} }
if (args->verbose) if (opts->verbose)
printf("ok!\n"); printf("%sok%s!\n", FZL_COK, FZL_CRST);
fzl_reader_ll_t *entry = rd->first; 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) while (entry)
{ {
if (entry->token) if (entry->token)
@@ -157,42 +79,42 @@ int main(int argc, char **argv)
} }
printf("\n"); printf("\n");
printf("-> parsing..."); printf("%s-> parsing...%s", FZL_CDEBUG, FZL_CRST);
} }
fzl_parser_t *parser = fzl_mkparser(rd->first); fzl_parser_t *parser = fzl_mkparser(rd->first);
result = fzl_parse(parser); result = fzl_parse(parser);
if (result != 0) if (result != 0)
{ {
printf("Error: %s\n", fzl_parser_geterror()); printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_parser_geterror());
return -1; 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); fzl_debug_print_ast(parser->root);
printf("> building\n"); printf("%s> building%s\n", FZL_CDEBUG, FZL_CRST);
printf("-> walking AST...\n"); printf("%s-> walking AST...%s\n", FZL_CDEBUG, FZL_CRST);
} }
fzl_walker_t *walker = fzl_mkwalker(parser->root); fzl_walker_t *walker = fzl_mkwalker(parser->root);
result = fzl_walk(walker); result = fzl_walk(walker);
if (result != 0) if (result != 0)
{ {
printf("Error: %s\n", fzl_walker_geterror()); printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_walker_geterror());
return -1; 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++) for (size_t i = 0; i < walker->consts->size; i++)
printf("---> %s\n", walker->consts->array[i].as.string.chars); printf("---> %s\n", walker->consts->array[i].as.string.chars);
printf("--> Ops:\n"); printf("%s--> Ops%s:\n", FZL_CDEBUG, FZL_CRST);
printf("---> "); printf("---> ");
for (size_t i = 0; i < walker->op_count; i++) for (size_t i = 0; i < walker->op_count; i++)
{ {
@@ -202,40 +124,40 @@ int main(int argc, char **argv)
} }
printf("\n"); printf("\n");
printf("-> preparing final write\n"); printf("%s-> preparing final write%s\n", FZL_CDEBUG, FZL_CRST);
} }
char outpath[256]; char outpath[256];
if (args->outpath) if (opts->outname)
strcpy(outpath, args->outpath); strcpy(outpath, opts->outname);
else else
strcpy(outpath, "a.fzb"); strcpy(outpath, "a.fzb");
if (args->verbose) if (opts->verbose)
{ {
printf("-> output file path is: %s\n", outpath); printf("%s-> output file path is%s: %s\n", FZL_CDEBUG, FZL_CRST, outpath);
printf("-> writing file..."); printf("%s-> writing file...%s", FZL_CDEBUG, FZL_CRST);
} }
fzl_writer_t *writer = fzl_mkwriter(outpath); fzl_writer_t *writer = fzl_mkwriter(outpath);
result = fzl_write(writer, walker); result = fzl_write(writer, walker);
if (result != 0) if (result != 0)
{ {
printf("Error: %s\n", fzl_writer_geterror()); printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_writer_geterror());
return -1; return -1;
} }
if (args->verbose) if (opts->verbose)
printf("ok!\n"); printf("%sok%s!\n", FZL_COK, FZL_CRST);
free(source); fzl_freeoptions(opts);
free(args); fzl_freelinked(linked);
fzl_freereader(rd); fzl_freereader(rd);
fzl_freeast(parser->root); fzl_freeast(parser->root);
fzl_freeparser(parser); fzl_freeparser(parser);
fzl_freewalker(walker); fzl_freewalker(walker);
fzl_freewriter(writer); fzl_freewriter(writer);
printf("done.\n"); printf("%sCompiled successfully%s.\n", FZL_COK, FZL_CRST);
return 0; return 0;
} }
+159
View File
@@ -0,0 +1,159 @@
#include <compiler/utils/fzl_linked.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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);
}
+131
View File
@@ -0,0 +1,131 @@
#include <common/fzl_colors.h>
#include <compiler/utils/fzl_options.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char version[] = "FZL Compiler 1.0";
void print_help()
{
printf("Usage: fzc [flags] <sources...>\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);
}
-2
View File
@@ -11,8 +11,6 @@
#include <string.h> #include <string.h>
#include <vm/fzl_vm.h> #include <vm/fzl_vm.h>
// NOTE: need to add optimized arithmetics in near future
char last_err[256]; char last_err[256];
static char *expect_hdr = "FZL\0\1"; static char *expect_hdr = "FZL\0\1";