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/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
View File
@@ -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
View File
@@ -1,3 +1,3 @@
// 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)
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
View File
@@ -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
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
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);
+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
#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);
+2 -1
View File
@@ -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);
+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
+129 -79
View File
@@ -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
View File
@@ -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;
}
+2 -1
View File
@@ -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
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_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
View File
@@ -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;
}
+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 <vm/fzl_vm.h>
// NOTE: need to add optimized arithmetics in near future
char last_err[256];
static char *expect_hdr = "FZL\0\1";