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:
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
+6
-6
@@ -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);
|
||||
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
// I'm a comment
|
||||
printline("Comment is skipped")
|
||||
printline("Comment is skipped");;;;;
|
||||
|
||||
|
||||
+5
-5
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -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");
|
||||
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
printline('hello, world')
|
||||
printline('hello, world');
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
printline("")
|
||||
printline("");
|
||||
|
||||
@@ -1 +1 @@
|
||||
printline("hello)
|
||||
printline("hello);
|
||||
|
||||
+9
-9
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -2,6 +2,7 @@
|
||||
#define FZL_READER_H
|
||||
|
||||
#include <compiler/fzl_token.h>
|
||||
#include <compiler/utils/fzl_linked.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
+129
-79
@@ -7,6 +7,7 @@
|
||||
#include <string.h>
|
||||
|
||||
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
|
||||
|
||||
+86
-37
@@ -1,4 +1,5 @@
|
||||
#include "compiler/fzl_token.h"
|
||||
#include "compiler/utils/fzl_linked.h"
|
||||
#include <compiler/fzl_reader.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
+38
-32
@@ -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};
|
||||
}
|
||||
|
||||
|
||||
+60
-138
@@ -1,147 +1,69 @@
|
||||
#include <common/fzl_colors.h>
|
||||
#include <compiler/fzl_debug.h>
|
||||
#include <compiler/fzl_parser.h>
|
||||
#include <compiler/fzl_reader.h>
|
||||
#include <compiler/fzl_walker.h>
|
||||
#include <compiler/fzl_writer.h>
|
||||
#include <compiler/utils/fzl_linked.h>
|
||||
#include <compiler/utils/fzl_options.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -11,8 +11,6 @@
|
||||
#include <string.h>
|
||||
#include <vm/fzl_vm.h>
|
||||
|
||||
// NOTE: need to add optimized arithmetics in near future
|
||||
|
||||
char last_err[256];
|
||||
|
||||
static char *expect_hdr = "FZL\0\1";
|
||||
|
||||
Reference in New Issue
Block a user