feat: implement math in compiler
This commit is contained in:
@@ -4,9 +4,18 @@
|
||||
// Available opcodes
|
||||
typedef enum
|
||||
{
|
||||
FZL_OPCODE_LOADCONST, // Load const into T (temp) reg
|
||||
FZL_OPCODE_PUSHARG, // Push argument from T into args stack
|
||||
FZL_OPCODE_CALL_BUILTIN // Call builtin function
|
||||
FZL_OPCODE_LOADCONST, // Load const into T (temp) reg
|
||||
FZL_OPCODE_PUSHARG, // Push argument from T into args stack
|
||||
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;
|
||||
|
||||
#endif // FZL_OPCODES_H
|
||||
|
||||
@@ -11,6 +11,17 @@ typedef enum
|
||||
FZL_NODETYPE_BLOCK,
|
||||
FZL_NODETYPE_CALL,
|
||||
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;
|
||||
|
||||
// AST node descriptor
|
||||
@@ -23,11 +34,34 @@ typedef struct fzl_node
|
||||
|
||||
union
|
||||
{
|
||||
// Array of nested nodes (for blocks, etc)
|
||||
struct
|
||||
{
|
||||
struct fzl_node **entries;
|
||||
size_t entry_count;
|
||||
} 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;
|
||||
|
||||
|
||||
@@ -8,11 +8,22 @@
|
||||
// Token type
|
||||
typedef enum
|
||||
{
|
||||
FZL_TOKTYPE_NAME,
|
||||
FZL_TOKTYPE_LPAIR,
|
||||
FZL_TOKTYPE_RPAIR,
|
||||
FZL_TOKTYPE_COMMA,
|
||||
FZL_TOKTYPE_STR_LITERAL
|
||||
FZL_TOKTYPE_NAME, // abc
|
||||
|
||||
FZL_TOKTYPE_LPAREN, // (
|
||||
FZL_TOKTYPE_RPAREN, // )
|
||||
|
||||
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;
|
||||
|
||||
// Token descriptor
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "compiler/fzl_parser.h"
|
||||
#include <compiler/fzl_debug.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@@ -32,12 +33,12 @@ void print_node(fzl_node_t *node, int level)
|
||||
switch (node->type)
|
||||
{
|
||||
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,
|
||||
(char *)node->token->value);
|
||||
for (size_t i = 0; i < node->list.entry_count; i++)
|
||||
print_node(node->list.entries[i], level + 1);
|
||||
for (size_t i = 0; i < node->call.args_count; i++)
|
||||
print_node(node->call.args[i], level + 1);
|
||||
}
|
||||
else
|
||||
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);
|
||||
|
||||
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:
|
||||
printf("%s Secure node\n", levelbuf);
|
||||
|
||||
+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;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "compiler/fzl_token.h"
|
||||
#include <compiler/fzl_reader.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -97,6 +99,44 @@ fzl_token_t *parse_string_literal(fzl_reader_t *reader)
|
||||
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)
|
||||
{
|
||||
if (reader->position >= reader->size)
|
||||
@@ -117,17 +157,27 @@ int fzl_read(fzl_reader_t *reader)
|
||||
if (curr == '\'' || curr == '"')
|
||||
token = parse_string_literal(reader);
|
||||
else if (curr == '(')
|
||||
{
|
||||
token = fzl_mktoken(FZL_TOKTYPE_LPAIR, p, p, NULL, 0);
|
||||
reader->position++;
|
||||
}
|
||||
token = add_single(reader, FZL_TOKTYPE_LPAREN);
|
||||
else if (curr == ')')
|
||||
{
|
||||
token = fzl_mktoken(FZL_TOKTYPE_RPAIR, p, p, NULL, 0);
|
||||
reader->position++;
|
||||
}
|
||||
token = add_single(reader, FZL_TOKTYPE_RPAREN);
|
||||
else if (curr == ',')
|
||||
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')
|
||||
token = parse_name(reader);
|
||||
else if (curr >= '0' && curr <= '9')
|
||||
token = parse_number(reader);
|
||||
else
|
||||
{
|
||||
sprintf(last_err, "undefined token '%c'", curr);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <common/fzl_builtins.h>
|
||||
#include <common/fzl_opcodes.h>
|
||||
#include <compiler/fzl_parser.h>
|
||||
#include <compiler/fzl_token.h>
|
||||
#include <compiler/fzl_walker.h>
|
||||
#include <compiler/utils/fzl_const_pool.h>
|
||||
#include <stdbool.h>
|
||||
@@ -108,9 +109,9 @@ bool walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
case FZL_NODETYPE_CALL:
|
||||
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;
|
||||
push_op(walker, FZL_OPCODE_PUSHARG);
|
||||
}
|
||||
@@ -129,13 +130,70 @@ bool walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
break;
|
||||
|
||||
case FZL_NODETYPE_LITERAL:
|
||||
size_t n = add_const(
|
||||
walker, (fzl_const_t){.type = FZL_CONSTTYPE_STRING,
|
||||
.as.string.chars = node->token->value,
|
||||
.as.string.length = node->token->value_sz});
|
||||
if (node->token->type == FZL_TOKTYPE_STR_LITERAL)
|
||||
{
|
||||
size_t n = add_const(
|
||||
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_word(walker, n);
|
||||
push_op(walker, FZL_OPCODE_LOADCONST);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+8
-2
@@ -193,8 +193,14 @@ int main(int argc, char **argv)
|
||||
printf("---> %s\n", walker->consts->array[i].as.string.chars);
|
||||
|
||||
printf("--> Ops:\n");
|
||||
printf("---> ");
|
||||
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");
|
||||
}
|
||||
@@ -207,7 +213,7 @@ int main(int argc, char **argv)
|
||||
|
||||
if (args->verbose)
|
||||
{
|
||||
printf("-> output file path is: %s", outpath);
|
||||
printf("-> output file path is: %s\n", outpath);
|
||||
printf("-> writing file...");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user