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
+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