feat: implement math in compiler
This commit is contained in:
+292
-54
@@ -1,5 +1,7 @@
|
||||
#include "compiler/fzl_token.h"
|
||||
#include <compiler/fzl_parser.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -45,7 +47,7 @@ fzl_node_t *fzl_mknode(fzl_nodetype_t type, fzl_token_t *token)
|
||||
// Get token at cursor
|
||||
static fzl_token_t *peek(fzl_parser_t *parser)
|
||||
{
|
||||
if (!parser->cursor)
|
||||
if (!parser || !parser->cursor)
|
||||
return NULL;
|
||||
return parser->cursor->token;
|
||||
}
|
||||
@@ -53,7 +55,7 @@ static fzl_token_t *peek(fzl_parser_t *parser)
|
||||
// Get token at (cursor + 1)
|
||||
static fzl_token_t *next(fzl_parser_t *parser)
|
||||
{
|
||||
if (!parser->cursor)
|
||||
if (!parser || !parser->cursor)
|
||||
return NULL;
|
||||
|
||||
fzl_reader_ll_t *next = parser->cursor->next;
|
||||
@@ -66,105 +68,315 @@ static fzl_token_t *next(fzl_parser_t *parser)
|
||||
// Consume token at cursor and move to the next
|
||||
static fzl_token_t *consume(fzl_parser_t *parser)
|
||||
{
|
||||
if (!parser->cursor)
|
||||
if (!parser || !parser->cursor)
|
||||
return NULL;
|
||||
fzl_token_t *tok = parser->cursor->token;
|
||||
parser->cursor = parser->cursor->next;
|
||||
return tok;
|
||||
}
|
||||
|
||||
// Check if current token have the same type as specified
|
||||
static bool is(fzl_parser_t *parser, fzl_toktype_t type)
|
||||
{
|
||||
if (!parser)
|
||||
return false;
|
||||
|
||||
fzl_token_t *tok = peek(parser);
|
||||
if (!tok)
|
||||
return false;
|
||||
|
||||
return tok->type == type;
|
||||
}
|
||||
|
||||
// Convert arithmetic operator token type to node type
|
||||
static fzl_nodetype_t math_op_to_type(fzl_toktype_t type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case FZL_TOKTYPE_PLUS:
|
||||
return FZL_NODETYPE_ADD;
|
||||
case FZL_TOKTYPE_MINUS:
|
||||
return FZL_NODETYPE_SUB;
|
||||
case FZL_TOKTYPE_STAR:
|
||||
return FZL_NODETYPE_MUL;
|
||||
case FZL_TOKTYPE_SLASH:
|
||||
return FZL_NODETYPE_DIV;
|
||||
case FZL_TOKTYPE_CARET:
|
||||
return FZL_NODETYPE_POW;
|
||||
case FZL_TOKTYPE_PERCENT:
|
||||
return FZL_NODETYPE_MOD;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static fzl_nodetype_t unary_op_to_type(fzl_toktype_t type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case FZL_TOKTYPE_PLUS:
|
||||
return FZL_NODETYPE_UNARY_PLUS;
|
||||
case FZL_TOKTYPE_MINUS:
|
||||
return FZL_NODETYPE_UNARY_MINUS;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
fzl_node_t *parse_expression(fzl_parser_t *parser);
|
||||
|
||||
// Parse primary
|
||||
fzl_node_t *parse_primary(fzl_parser_t *parser)
|
||||
{
|
||||
if (peek(parser) && peek(parser)->type == FZL_TOKTYPE_STR_LITERAL)
|
||||
if (!parser || !peek(parser))
|
||||
return NULL;
|
||||
|
||||
if (is(parser, FZL_TOKTYPE_STR_LITERAL))
|
||||
{
|
||||
fzl_token_t *tok = consume(parser);
|
||||
return fzl_mknode(FZL_NODETYPE_LITERAL, tok);
|
||||
}
|
||||
else if (is(parser, FZL_TOKTYPE_NUM_LITERAL))
|
||||
{
|
||||
fzl_token_t *tok = consume(parser);
|
||||
return fzl_mknode(FZL_NODETYPE_LITERAL, tok);
|
||||
}
|
||||
else if (is(parser, FZL_TOKTYPE_LPAREN))
|
||||
{
|
||||
consume(parser);
|
||||
fzl_node_t *node = parse_expression(parser);
|
||||
if (!is(parser, FZL_TOKTYPE_RPAREN))
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "expected rparen at %d",
|
||||
parser->cursor->token->i0);
|
||||
return NULL;
|
||||
}
|
||||
consume(parser);
|
||||
return node;
|
||||
}
|
||||
else if (is(parser, FZL_TOKTYPE_NAME))
|
||||
{
|
||||
fzl_token_t *name = consume(parser);
|
||||
return fzl_mknode(FZL_NODETYPE_IDENTIFIER, name);
|
||||
}
|
||||
|
||||
snprintf(plast_err, sizeof(plast_err), "failed to parse primary at %d",
|
||||
peek(parser)->i0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *parse_expression(fzl_parser_t *parser, int precedence);
|
||||
|
||||
// Parse call expression
|
||||
fzl_node_t *parse_call(fzl_parser_t *parser)
|
||||
// Parse postfix expressions (parens, index access, dots)
|
||||
fzl_node_t *parse_postfix(fzl_parser_t *parser)
|
||||
{
|
||||
fzl_token_t *tok = consume(parser); // <NAME>
|
||||
if (tok->type != FZL_TOKTYPE_NAME)
|
||||
if (!parser)
|
||||
return NULL;
|
||||
|
||||
fzl_token_t *lpair = consume(parser); // (
|
||||
if (lpair->type != FZL_TOKTYPE_LPAIR)
|
||||
fzl_node_t *left = parse_primary(parser);
|
||||
fzl_node_t *right = NULL;
|
||||
|
||||
if (!left)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "failed to parse postfix at %d",
|
||||
peek(parser)->i0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CALL, tok);
|
||||
node->list.entry_count = 0;
|
||||
|
||||
size_t capacity = 4;
|
||||
node->list.entries = malloc(capacity * sizeof(fzl_node_t *));
|
||||
node->list.entry_count = 0;
|
||||
|
||||
if (peek(parser) && peek(parser)->type == FZL_TOKTYPE_RPAIR)
|
||||
while (is(parser, FZL_TOKTYPE_LPAREN))
|
||||
{
|
||||
consume(parser);
|
||||
return node;
|
||||
}
|
||||
|
||||
while (peek(parser) && peek(parser)->type != FZL_TOKTYPE_RPAIR)
|
||||
{
|
||||
fzl_node_t *arg = parse_expression(parser, 0);
|
||||
if (!arg)
|
||||
return NULL;
|
||||
size_t args_capacity = 2;
|
||||
size_t args_count = 0;
|
||||
fzl_node_t **args = malloc(args_capacity * sizeof(fzl_node_t *));
|
||||
|
||||
if (node->list.entry_count == capacity)
|
||||
while (!is(parser, FZL_TOKTYPE_RPAREN))
|
||||
{
|
||||
capacity *= 2;
|
||||
node->list.entries =
|
||||
realloc(node->list.entries, capacity * sizeof(fzl_node_t *));
|
||||
fzl_node_t *arg = parse_expression(parser);
|
||||
if (!arg)
|
||||
{
|
||||
free(args);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (args_capacity <= args_count)
|
||||
{
|
||||
args_capacity *= 2;
|
||||
args = realloc(args, args_capacity * sizeof(fzl_node_t));
|
||||
}
|
||||
|
||||
args[args_count] = arg;
|
||||
args_count++;
|
||||
|
||||
if (is(parser, FZL_TOKTYPE_COMMA))
|
||||
consume(parser);
|
||||
}
|
||||
|
||||
node->list.entries[node->list.entry_count++] = arg;
|
||||
|
||||
if (peek(parser) && peek(parser)->type == FZL_TOKTYPE_COMMA)
|
||||
consume(parser);
|
||||
else if (peek(parser) && peek(parser)->type != FZL_TOKTYPE_RPAIR)
|
||||
fzl_token_t *rparen = consume(parser);
|
||||
if (!rparen || rparen->type != FZL_TOKTYPE_RPAREN)
|
||||
{
|
||||
free(args);
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"expected ',' or ')' after arg list");
|
||||
"expected ')' after argument list at %d", peek(parser)->i0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CALL, left->token);
|
||||
node->call.callee = left;
|
||||
node->call.args = args;
|
||||
node->call.args_count = args_count;
|
||||
|
||||
left = node;
|
||||
}
|
||||
|
||||
fzl_token_t *rpair = consume(parser);
|
||||
if (rpair->type != FZL_TOKTYPE_RPAIR)
|
||||
return left;
|
||||
}
|
||||
|
||||
// Parse unary operations
|
||||
fzl_node_t *parse_unary(fzl_parser_t *parser)
|
||||
{
|
||||
if (!parser)
|
||||
return NULL;
|
||||
|
||||
return node;
|
||||
if (!is(parser, FZL_TOKTYPE_MINUS) && !is(parser, FZL_TOKTYPE_PLUS))
|
||||
return parse_postfix(parser);
|
||||
|
||||
fzl_token_t *op = consume(parser);
|
||||
fzl_node_t *operand = parse_unary(parser);
|
||||
|
||||
if (!operand)
|
||||
return NULL;
|
||||
|
||||
fzl_node_t *result = fzl_mknode(unary_op_to_type(op->type), op);
|
||||
result->unary_op.operand = operand;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fzl_node_t *parse_power(fzl_parser_t *parser)
|
||||
{
|
||||
if (!parser)
|
||||
return NULL;
|
||||
|
||||
fzl_node_t *left = parse_unary(parser);
|
||||
fzl_node_t *right = NULL;
|
||||
|
||||
if (!left)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "failed to parse power at %d",
|
||||
peek(parser)->i0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (is(parser, FZL_TOKTYPE_CARET))
|
||||
{
|
||||
fzl_token_t *caret = consume(parser);
|
||||
|
||||
right = parse_unary(parser);
|
||||
if (!right)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"failed to parse right side of power at %d", peek(parser)->i0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_POW, caret);
|
||||
node->binary_op.left = left;
|
||||
node->binary_op.right = right;
|
||||
|
||||
left = node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
// Parse FACTOR: multiplication and division
|
||||
fzl_node_t *parse_factor(fzl_parser_t *parser)
|
||||
{
|
||||
if (!parser)
|
||||
return NULL;
|
||||
|
||||
fzl_node_t *left = parse_power(parser);
|
||||
fzl_node_t *right = NULL;
|
||||
|
||||
if (!left)
|
||||
{
|
||||
if (!plast_err[0])
|
||||
snprintf(plast_err, sizeof(plast_err), "invalid expression at %u",
|
||||
parser->cursor->token->i0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (is(parser, FZL_TOKTYPE_STAR) || is(parser, FZL_TOKTYPE_SLASH) ||
|
||||
is(parser, FZL_TOKTYPE_PERCENT))
|
||||
{
|
||||
fzl_token_t *op = consume(parser);
|
||||
|
||||
right = parse_factor(parser);
|
||||
if (!right)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"unfinished factor (mul/div) expression at %u", left->token->i0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *node = fzl_mknode(math_op_to_type(op->type), op);
|
||||
node->binary_op.left = left;
|
||||
node->binary_op.right = right;
|
||||
left = node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
// Parse TERM: addition and subtraction
|
||||
fzl_node_t *parse_term(fzl_parser_t *parser)
|
||||
{
|
||||
if (!parser)
|
||||
return NULL;
|
||||
|
||||
fzl_node_t *left = parse_factor(parser);
|
||||
fzl_node_t *right = NULL;
|
||||
|
||||
if (!left)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "invalid expression at %u",
|
||||
parser->cursor->token->i0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (is(parser, FZL_TOKTYPE_PLUS) || is(parser, FZL_TOKTYPE_MINUS))
|
||||
{
|
||||
fzl_token_t *op = consume(parser);
|
||||
|
||||
right = parse_factor(parser);
|
||||
if (!right)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"unfinished term (add/sub) expression at %u", left->token->i0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *node = fzl_mknode(math_op_to_type(op->type), op);
|
||||
node->binary_op.left = left;
|
||||
node->binary_op.right = right;
|
||||
left = node;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
// Expression parsing
|
||||
fzl_node_t *parse_expression(fzl_parser_t *parser, int precedence)
|
||||
fzl_node_t *parse_expression(fzl_parser_t *parser)
|
||||
{
|
||||
if (peek(parser) && peek(parser)->type == FZL_TOKTYPE_NAME)
|
||||
{
|
||||
if (next(parser) && next(parser)->type == FZL_TOKTYPE_LPAIR)
|
||||
return parse_call(parser);
|
||||
}
|
||||
else if (peek(parser) && peek(parser)->type == FZL_TOKTYPE_STR_LITERAL)
|
||||
return parse_primary(parser);
|
||||
|
||||
snprintf(plast_err, sizeof(plast_err), "failed to parse expression at %d",
|
||||
peek(parser)->i0);
|
||||
return NULL;
|
||||
return parse_term(parser);
|
||||
}
|
||||
|
||||
// Statement parsing
|
||||
fzl_node_t *parse_statement(fzl_parser_t *parser)
|
||||
{
|
||||
return parse_expression(parser, 0);
|
||||
return parse_expression(parser);
|
||||
}
|
||||
|
||||
// Internal parsing entry point
|
||||
@@ -229,7 +441,7 @@ void fzl_freeast(fzl_node_t *root)
|
||||
|
||||
while (root)
|
||||
{
|
||||
if (root->type == FZL_NODETYPE_BLOCK || root->type == FZL_NODETYPE_CALL)
|
||||
if (root->type == FZL_NODETYPE_BLOCK)
|
||||
{
|
||||
if (root->list.entries)
|
||||
{
|
||||
@@ -240,6 +452,32 @@ void fzl_freeast(fzl_node_t *root)
|
||||
free(root->list.entries);
|
||||
}
|
||||
}
|
||||
else if (root->type == FZL_NODETYPE_CALL)
|
||||
{
|
||||
if (root->call.args_count)
|
||||
{
|
||||
for (size_t i = 0; i < root->call.args_count; i++)
|
||||
if (root->call.args[i])
|
||||
fzl_freeast(root->call.args[i]);
|
||||
|
||||
free(root->call.args);
|
||||
}
|
||||
}
|
||||
else if (root->type == FZL_NODETYPE_ADD || root->type == FZL_NODETYPE_SUB ||
|
||||
root->type == FZL_NODETYPE_MUL || root->type == FZL_NODETYPE_DIV ||
|
||||
root->type == FZL_NODETYPE_POW || root->type == FZL_NODETYPE_MOD)
|
||||
{
|
||||
if (root->binary_op.left)
|
||||
fzl_freeast(root->binary_op.left);
|
||||
if (root->binary_op.right)
|
||||
fzl_freeast(root->binary_op.right);
|
||||
}
|
||||
else if (root->type == FZL_NODETYPE_UNARY_PLUS ||
|
||||
root->type == FZL_NODETYPE_UNARY_MINUS)
|
||||
{
|
||||
if (root->unary_op.operand)
|
||||
fzl_freeast(root->unary_op.operand);
|
||||
}
|
||||
|
||||
fzl_freenode(root);
|
||||
root = root->next;
|
||||
|
||||
Reference in New Issue
Block a user