feat: implement math in compiler
This commit is contained in:
@@ -4,9 +4,18 @@
|
|||||||
// Available opcodes
|
// Available opcodes
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
FZL_OPCODE_LOADCONST, // Load const into T (temp) reg
|
FZL_OPCODE_LOADCONST, // Load const into T (temp) reg
|
||||||
FZL_OPCODE_PUSHARG, // Push argument from T into args stack
|
FZL_OPCODE_PUSHARG, // Push argument from T into args stack
|
||||||
FZL_OPCODE_CALL_BUILTIN // Call builtin function
|
FZL_OPCODE_CALL_BUILTIN, // Call builtin function
|
||||||
|
FZL_OPCODE_PUSHNUM, // Push number into stack
|
||||||
|
|
||||||
|
FZL_OPCODE_ADD, // Sum two numbers in arg strack
|
||||||
|
FZL_OPCODE_SUB, // Subract two numbers in arg stack
|
||||||
|
FZL_OPCODE_MUL, // Multiply two numbers in arg stack
|
||||||
|
FZL_OPCODE_DIV, // Divide two numbers in arg stack
|
||||||
|
FZL_OPCODE_POW, // Power first number in arg stack by second
|
||||||
|
FZL_OPCODE_MOD, // Get module of two numbers in arg stack
|
||||||
|
FZL_OPCODE_NEG, // Negotiate number in arg stack
|
||||||
} fzl_opcode_t;
|
} fzl_opcode_t;
|
||||||
|
|
||||||
#endif // FZL_OPCODES_H
|
#endif // FZL_OPCODES_H
|
||||||
|
|||||||
@@ -11,6 +11,17 @@ typedef enum
|
|||||||
FZL_NODETYPE_BLOCK,
|
FZL_NODETYPE_BLOCK,
|
||||||
FZL_NODETYPE_CALL,
|
FZL_NODETYPE_CALL,
|
||||||
FZL_NODETYPE_LITERAL,
|
FZL_NODETYPE_LITERAL,
|
||||||
|
FZL_NODETYPE_IDENTIFIER,
|
||||||
|
|
||||||
|
FZL_NODETYPE_ADD,
|
||||||
|
FZL_NODETYPE_SUB,
|
||||||
|
FZL_NODETYPE_MUL,
|
||||||
|
FZL_NODETYPE_DIV,
|
||||||
|
FZL_NODETYPE_POW,
|
||||||
|
FZL_NODETYPE_MOD,
|
||||||
|
|
||||||
|
FZL_NODETYPE_UNARY_PLUS,
|
||||||
|
FZL_NODETYPE_UNARY_MINUS
|
||||||
} fzl_nodetype_t;
|
} fzl_nodetype_t;
|
||||||
|
|
||||||
// AST node descriptor
|
// AST node descriptor
|
||||||
@@ -23,11 +34,34 @@ typedef struct fzl_node
|
|||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
// Array of nested nodes (for blocks, etc)
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
struct fzl_node **entries;
|
struct fzl_node **entries;
|
||||||
size_t entry_count;
|
size_t entry_count;
|
||||||
} list;
|
} list;
|
||||||
|
|
||||||
|
// Call data
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
struct fzl_node *callee;
|
||||||
|
|
||||||
|
struct fzl_node **args;
|
||||||
|
size_t args_count;
|
||||||
|
} call;
|
||||||
|
|
||||||
|
// Binary operations
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
struct fzl_node *left;
|
||||||
|
struct fzl_node *right;
|
||||||
|
} binary_op;
|
||||||
|
|
||||||
|
// Unary operations
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
struct fzl_node *operand;
|
||||||
|
} unary_op;
|
||||||
};
|
};
|
||||||
} fzl_node_t;
|
} fzl_node_t;
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,22 @@
|
|||||||
// Token type
|
// Token type
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
FZL_TOKTYPE_NAME,
|
FZL_TOKTYPE_NAME, // abc
|
||||||
FZL_TOKTYPE_LPAIR,
|
|
||||||
FZL_TOKTYPE_RPAIR,
|
FZL_TOKTYPE_LPAREN, // (
|
||||||
FZL_TOKTYPE_COMMA,
|
FZL_TOKTYPE_RPAREN, // )
|
||||||
FZL_TOKTYPE_STR_LITERAL
|
|
||||||
|
FZL_TOKTYPE_COMMA, // ,
|
||||||
|
|
||||||
|
FZL_TOKTYPE_STR_LITERAL, // ""
|
||||||
|
FZL_TOKTYPE_NUM_LITERAL, // 123
|
||||||
|
|
||||||
|
FZL_TOKTYPE_STAR, // *
|
||||||
|
FZL_TOKTYPE_SLASH, // /
|
||||||
|
FZL_TOKTYPE_PLUS, // +
|
||||||
|
FZL_TOKTYPE_MINUS, // -
|
||||||
|
FZL_TOKTYPE_CARET, // ^
|
||||||
|
FZL_TOKTYPE_PERCENT, // %
|
||||||
} fzl_toktype_t;
|
} fzl_toktype_t;
|
||||||
|
|
||||||
// Token descriptor
|
// Token descriptor
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "compiler/fzl_parser.h"
|
||||||
#include <compiler/fzl_debug.h>
|
#include <compiler/fzl_debug.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -32,12 +33,12 @@ void print_node(fzl_node_t *node, int level)
|
|||||||
switch (node->type)
|
switch (node->type)
|
||||||
{
|
{
|
||||||
case FZL_NODETYPE_CALL:
|
case FZL_NODETYPE_CALL:
|
||||||
if (node->list.entry_count > 0)
|
if (node->call.args_count > 0)
|
||||||
{
|
{
|
||||||
printf("%s Call fn '%s' with args:\n", levelbuf,
|
printf("%s Call fn '%s' with args:\n", levelbuf,
|
||||||
(char *)node->token->value);
|
(char *)node->token->value);
|
||||||
for (size_t i = 0; i < node->list.entry_count; i++)
|
for (size_t i = 0; i < node->call.args_count; i++)
|
||||||
print_node(node->list.entries[i], level + 1);
|
print_node(node->call.args[i], level + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printf("%s Call fn '%s' w/o args\n", levelbuf,
|
printf("%s Call fn '%s' w/o args\n", levelbuf,
|
||||||
@@ -62,6 +63,22 @@ void print_node(fzl_node_t *node, int level)
|
|||||||
print_node(node->list.entries[i], level + 1);
|
print_node(node->list.entries[i], level + 1);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case FZL_NODETYPE_ADD:
|
||||||
|
case FZL_NODETYPE_SUB:
|
||||||
|
case FZL_NODETYPE_MUL:
|
||||||
|
case FZL_NODETYPE_DIV:
|
||||||
|
case FZL_NODETYPE_POW:
|
||||||
|
case FZL_NODETYPE_MOD:
|
||||||
|
printf("%s Binary op (%d)\n", levelbuf, node->type);
|
||||||
|
printf("-%s LEFT:\n", levelbuf);
|
||||||
|
print_node(node->binary_op.left, level + 2);
|
||||||
|
printf("-%s RIGHT:\n", levelbuf);
|
||||||
|
print_node(node->binary_op.right, level + 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_NODETYPE_IDENTIFIER:
|
||||||
|
printf("%s Identifier ('%s')\n", levelbuf, (char *)node->token->value);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("%s Secure node\n", levelbuf);
|
printf("%s Secure node\n", levelbuf);
|
||||||
|
|||||||
+292
-54
@@ -1,5 +1,7 @@
|
|||||||
#include "compiler/fzl_token.h"
|
#include "compiler/fzl_token.h"
|
||||||
#include <compiler/fzl_parser.h>
|
#include <compiler/fzl_parser.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.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
|
// Get token at cursor
|
||||||
static fzl_token_t *peek(fzl_parser_t *parser)
|
static fzl_token_t *peek(fzl_parser_t *parser)
|
||||||
{
|
{
|
||||||
if (!parser->cursor)
|
if (!parser || !parser->cursor)
|
||||||
return NULL;
|
return NULL;
|
||||||
return parser->cursor->token;
|
return parser->cursor->token;
|
||||||
}
|
}
|
||||||
@@ -53,7 +55,7 @@ static fzl_token_t *peek(fzl_parser_t *parser)
|
|||||||
// Get token at (cursor + 1)
|
// Get token at (cursor + 1)
|
||||||
static fzl_token_t *next(fzl_parser_t *parser)
|
static fzl_token_t *next(fzl_parser_t *parser)
|
||||||
{
|
{
|
||||||
if (!parser->cursor)
|
if (!parser || !parser->cursor)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
fzl_reader_ll_t *next = parser->cursor->next;
|
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
|
// Consume token at cursor and move to the next
|
||||||
static fzl_token_t *consume(fzl_parser_t *parser)
|
static fzl_token_t *consume(fzl_parser_t *parser)
|
||||||
{
|
{
|
||||||
if (!parser->cursor)
|
if (!parser || !parser->cursor)
|
||||||
return NULL;
|
return NULL;
|
||||||
fzl_token_t *tok = parser->cursor->token;
|
fzl_token_t *tok = parser->cursor->token;
|
||||||
parser->cursor = parser->cursor->next;
|
parser->cursor = parser->cursor->next;
|
||||||
return tok;
|
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
|
// Parse primary
|
||||||
fzl_node_t *parse_primary(fzl_parser_t *parser)
|
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);
|
fzl_token_t *tok = consume(parser);
|
||||||
return fzl_mknode(FZL_NODETYPE_LITERAL, tok);
|
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",
|
snprintf(plast_err, sizeof(plast_err), "failed to parse primary at %d",
|
||||||
peek(parser)->i0);
|
peek(parser)->i0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
fzl_node_t *parse_expression(fzl_parser_t *parser, int precedence);
|
// Parse postfix expressions (parens, index access, dots)
|
||||||
|
fzl_node_t *parse_postfix(fzl_parser_t *parser)
|
||||||
// Parse call expression
|
|
||||||
fzl_node_t *parse_call(fzl_parser_t *parser)
|
|
||||||
{
|
{
|
||||||
fzl_token_t *tok = consume(parser); // <NAME>
|
if (!parser)
|
||||||
if (tok->type != FZL_TOKTYPE_NAME)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
fzl_token_t *lpair = consume(parser); // (
|
fzl_node_t *left = parse_primary(parser);
|
||||||
if (lpair->type != FZL_TOKTYPE_LPAIR)
|
fzl_node_t *right = NULL;
|
||||||
|
|
||||||
|
if (!left)
|
||||||
|
{
|
||||||
|
snprintf(plast_err, sizeof(plast_err), "failed to parse postfix at %d",
|
||||||
|
peek(parser)->i0);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CALL, tok);
|
while (is(parser, FZL_TOKTYPE_LPAREN))
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
consume(parser);
|
consume(parser);
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (peek(parser) && peek(parser)->type != FZL_TOKTYPE_RPAIR)
|
size_t args_capacity = 2;
|
||||||
{
|
size_t args_count = 0;
|
||||||
fzl_node_t *arg = parse_expression(parser, 0);
|
fzl_node_t **args = malloc(args_capacity * sizeof(fzl_node_t *));
|
||||||
if (!arg)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (node->list.entry_count == capacity)
|
while (!is(parser, FZL_TOKTYPE_RPAREN))
|
||||||
{
|
{
|
||||||
capacity *= 2;
|
fzl_node_t *arg = parse_expression(parser);
|
||||||
node->list.entries =
|
if (!arg)
|
||||||
realloc(node->list.entries, capacity * sizeof(fzl_node_t *));
|
{
|
||||||
|
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;
|
fzl_token_t *rparen = consume(parser);
|
||||||
|
if (!rparen || rparen->type != FZL_TOKTYPE_RPAREN)
|
||||||
if (peek(parser) && peek(parser)->type == FZL_TOKTYPE_COMMA)
|
|
||||||
consume(parser);
|
|
||||||
else if (peek(parser) && peek(parser)->type != FZL_TOKTYPE_RPAIR)
|
|
||||||
{
|
{
|
||||||
|
free(args);
|
||||||
snprintf(plast_err, sizeof(plast_err),
|
snprintf(plast_err, sizeof(plast_err),
|
||||||
"expected ',' or ')' after arg list");
|
"expected ')' after argument list at %d", peek(parser)->i0);
|
||||||
return NULL;
|
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);
|
return left;
|
||||||
if (rpair->type != FZL_TOKTYPE_RPAIR)
|
}
|
||||||
|
|
||||||
|
// Parse unary operations
|
||||||
|
fzl_node_t *parse_unary(fzl_parser_t *parser)
|
||||||
|
{
|
||||||
|
if (!parser)
|
||||||
return NULL;
|
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
|
// 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)
|
return parse_term(parser);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statement parsing
|
// Statement parsing
|
||||||
fzl_node_t *parse_statement(fzl_parser_t *parser)
|
fzl_node_t *parse_statement(fzl_parser_t *parser)
|
||||||
{
|
{
|
||||||
return parse_expression(parser, 0);
|
return parse_expression(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal parsing entry point
|
// Internal parsing entry point
|
||||||
@@ -229,7 +441,7 @@ void fzl_freeast(fzl_node_t *root)
|
|||||||
|
|
||||||
while (root)
|
while (root)
|
||||||
{
|
{
|
||||||
if (root->type == FZL_NODETYPE_BLOCK || root->type == FZL_NODETYPE_CALL)
|
if (root->type == FZL_NODETYPE_BLOCK)
|
||||||
{
|
{
|
||||||
if (root->list.entries)
|
if (root->list.entries)
|
||||||
{
|
{
|
||||||
@@ -240,6 +452,32 @@ void fzl_freeast(fzl_node_t *root)
|
|||||||
free(root->list.entries);
|
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);
|
fzl_freenode(root);
|
||||||
root = root->next;
|
root = root->next;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
#include "compiler/fzl_token.h"
|
||||||
#include <compiler/fzl_reader.h>
|
#include <compiler/fzl_reader.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -97,6 +99,44 @@ fzl_token_t *parse_string_literal(fzl_reader_t *reader)
|
|||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse numeric literal
|
||||||
|
fzl_token_t *parse_number(fzl_reader_t *reader)
|
||||||
|
{
|
||||||
|
if (!reader)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size_t size = 0;
|
||||||
|
size_t lpos = reader->position;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
size++;
|
||||||
|
lpos++;
|
||||||
|
} while ((reader->source[lpos] >= '0' && reader->source[lpos] <= '9') &&
|
||||||
|
lpos < reader->size);
|
||||||
|
|
||||||
|
char *value = malloc(size * sizeof(char) + 1);
|
||||||
|
memcpy(value, reader->source + reader->position, size);
|
||||||
|
value[size] = '\0';
|
||||||
|
|
||||||
|
fzl_token_t *tok =
|
||||||
|
fzl_mktoken(FZL_TOKTYPE_NUM_LITERAL, reader->position, lpos, value, size);
|
||||||
|
free(value);
|
||||||
|
|
||||||
|
if (!tok)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
reader->position += size;
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add single-char token
|
||||||
|
fzl_token_t *add_single(fzl_reader_t *reader, fzl_toktype_t type)
|
||||||
|
{
|
||||||
|
size_t p = reader->position++;
|
||||||
|
return fzl_mktoken(type, p, p, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int fzl_read(fzl_reader_t *reader)
|
int fzl_read(fzl_reader_t *reader)
|
||||||
{
|
{
|
||||||
if (reader->position >= reader->size)
|
if (reader->position >= reader->size)
|
||||||
@@ -117,17 +157,27 @@ int fzl_read(fzl_reader_t *reader)
|
|||||||
if (curr == '\'' || curr == '"')
|
if (curr == '\'' || curr == '"')
|
||||||
token = parse_string_literal(reader);
|
token = parse_string_literal(reader);
|
||||||
else if (curr == '(')
|
else if (curr == '(')
|
||||||
{
|
token = add_single(reader, FZL_TOKTYPE_LPAREN);
|
||||||
token = fzl_mktoken(FZL_TOKTYPE_LPAIR, p, p, NULL, 0);
|
|
||||||
reader->position++;
|
|
||||||
}
|
|
||||||
else if (curr == ')')
|
else if (curr == ')')
|
||||||
{
|
token = add_single(reader, FZL_TOKTYPE_RPAREN);
|
||||||
token = fzl_mktoken(FZL_TOKTYPE_RPAIR, p, p, NULL, 0);
|
else if (curr == ',')
|
||||||
reader->position++;
|
token = add_single(reader, FZL_TOKTYPE_COMMA);
|
||||||
}
|
else if (curr == '*')
|
||||||
|
token = add_single(reader, FZL_TOKTYPE_STAR);
|
||||||
|
else if (curr == '/')
|
||||||
|
token = add_single(reader, FZL_TOKTYPE_SLASH);
|
||||||
|
else if (curr == '+')
|
||||||
|
token = add_single(reader, FZL_TOKTYPE_PLUS);
|
||||||
|
else if (curr == '-')
|
||||||
|
token = add_single(reader, FZL_TOKTYPE_MINUS);
|
||||||
|
else if (curr == '^')
|
||||||
|
token = add_single(reader, FZL_TOKTYPE_CARET);
|
||||||
|
else if (curr == '%')
|
||||||
|
token = add_single(reader, FZL_TOKTYPE_PERCENT);
|
||||||
else if (curr >= 'A' && curr <= 'Z' || curr >= 'a' && curr <= 'z')
|
else if (curr >= 'A' && curr <= 'Z' || curr >= 'a' && curr <= 'z')
|
||||||
token = parse_name(reader);
|
token = parse_name(reader);
|
||||||
|
else if (curr >= '0' && curr <= '9')
|
||||||
|
token = parse_number(reader);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf(last_err, "undefined token '%c'", curr);
|
sprintf(last_err, "undefined token '%c'", curr);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <common/fzl_builtins.h>
|
#include <common/fzl_builtins.h>
|
||||||
#include <common/fzl_opcodes.h>
|
#include <common/fzl_opcodes.h>
|
||||||
#include <compiler/fzl_parser.h>
|
#include <compiler/fzl_parser.h>
|
||||||
|
#include <compiler/fzl_token.h>
|
||||||
#include <compiler/fzl_walker.h>
|
#include <compiler/fzl_walker.h>
|
||||||
#include <compiler/utils/fzl_const_pool.h>
|
#include <compiler/utils/fzl_const_pool.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -108,9 +109,9 @@ bool walk(fzl_walker_t *walker, fzl_node_t *node)
|
|||||||
case FZL_NODETYPE_CALL:
|
case FZL_NODETYPE_CALL:
|
||||||
if (node->list.entry_count > 0)
|
if (node->list.entry_count > 0)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < node->list.entry_count; i++)
|
for (size_t i = 0; i < node->call.args_count; i++)
|
||||||
{
|
{
|
||||||
if (!walk(walker, node->list.entries[i]))
|
if (!walk(walker, node->call.args[i]))
|
||||||
return false;
|
return false;
|
||||||
push_op(walker, FZL_OPCODE_PUSHARG);
|
push_op(walker, FZL_OPCODE_PUSHARG);
|
||||||
}
|
}
|
||||||
@@ -129,13 +130,70 @@ bool walk(fzl_walker_t *walker, fzl_node_t *node)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FZL_NODETYPE_LITERAL:
|
case FZL_NODETYPE_LITERAL:
|
||||||
size_t n = add_const(
|
if (node->token->type == FZL_TOKTYPE_STR_LITERAL)
|
||||||
walker, (fzl_const_t){.type = FZL_CONSTTYPE_STRING,
|
{
|
||||||
.as.string.chars = node->token->value,
|
size_t n = add_const(
|
||||||
.as.string.length = node->token->value_sz});
|
walker, (fzl_const_t){.type = FZL_CONSTTYPE_STRING,
|
||||||
|
.as.string.chars = node->token->value,
|
||||||
|
.as.string.length = node->token->value_sz});
|
||||||
|
|
||||||
push_op(walker, FZL_OPCODE_LOADCONST);
|
push_op(walker, FZL_OPCODE_LOADCONST);
|
||||||
push_word(walker, n);
|
push_word(walker, n);
|
||||||
|
}
|
||||||
|
else if (node->token->type == FZL_TOKTYPE_NUM_LITERAL)
|
||||||
|
{
|
||||||
|
push_op(walker, FZL_OPCODE_PUSHNUM);
|
||||||
|
|
||||||
|
uint64_t num = strtol(node->token->value, NULL, 10);
|
||||||
|
push_word(walker, num);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_NODETYPE_ADD:
|
||||||
|
case FZL_NODETYPE_SUB:
|
||||||
|
case FZL_NODETYPE_MUL:
|
||||||
|
case FZL_NODETYPE_DIV:
|
||||||
|
case FZL_NODETYPE_POW:
|
||||||
|
case FZL_NODETYPE_MOD:
|
||||||
|
if (!walk(walker, node->binary_op.left))
|
||||||
|
return false;
|
||||||
|
push_op(walker, FZL_OPCODE_PUSHARG);
|
||||||
|
|
||||||
|
if (!walk(walker, node->binary_op.right))
|
||||||
|
return false;
|
||||||
|
push_op(walker, FZL_OPCODE_PUSHARG);
|
||||||
|
|
||||||
|
switch (node->type)
|
||||||
|
{
|
||||||
|
case FZL_NODETYPE_ADD:
|
||||||
|
push_op(walker, FZL_OPCODE_ADD);
|
||||||
|
break;
|
||||||
|
case FZL_NODETYPE_SUB:
|
||||||
|
push_op(walker, FZL_OPCODE_SUB);
|
||||||
|
break;
|
||||||
|
case FZL_NODETYPE_MUL:
|
||||||
|
push_op(walker, FZL_OPCODE_MUL);
|
||||||
|
break;
|
||||||
|
case FZL_NODETYPE_DIV:
|
||||||
|
push_op(walker, FZL_OPCODE_DIV);
|
||||||
|
break;
|
||||||
|
case FZL_NODETYPE_POW:
|
||||||
|
push_op(walker, FZL_OPCODE_POW);
|
||||||
|
break;
|
||||||
|
case FZL_NODETYPE_MOD:
|
||||||
|
push_op(walker, FZL_OPCODE_MOD);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FZL_NODETYPE_UNARY_MINUS:
|
||||||
|
if (!walk(walker, node->unary_op.operand))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
push_op(walker, FZL_OPCODE_NEG);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -193,8 +193,14 @@ int main(int argc, char **argv)
|
|||||||
printf("---> %s\n", walker->consts->array[i].as.string.chars);
|
printf("---> %s\n", walker->consts->array[i].as.string.chars);
|
||||||
|
|
||||||
printf("--> Ops:\n");
|
printf("--> Ops:\n");
|
||||||
|
printf("---> ");
|
||||||
for (size_t i = 0; i < walker->op_count; i++)
|
for (size_t i = 0; i < walker->op_count; i++)
|
||||||
printf("---> %lu\n", walker->ops[i]);
|
{
|
||||||
|
if (i > 0 && i < walker->op_count)
|
||||||
|
printf("->");
|
||||||
|
printf("%lu", walker->ops[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
printf("-> preparing final write\n");
|
printf("-> preparing final write\n");
|
||||||
}
|
}
|
||||||
@@ -207,7 +213,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
if (args->verbose)
|
if (args->verbose)
|
||||||
{
|
{
|
||||||
printf("-> output file path is: %s", outpath);
|
printf("-> output file path is: %s\n", outpath);
|
||||||
printf("-> writing file...");
|
printf("-> writing file...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user