feat: implement functions
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
||||
int fib(int n)
|
||||
{
|
||||
if (n <= 1)
|
||||
return n
|
||||
|
||||
return fib(n - 1) + fib(n - 2)
|
||||
}
|
||||
|
||||
uint sum(uint a, uint b)
|
||||
{
|
||||
return a + b
|
||||
}
|
||||
|
||||
printline("Test #1: fibonacci")
|
||||
int result = fib(7)
|
||||
if (result == 13)
|
||||
printline("Recurse test passed")
|
||||
else printline("Recurse test failed")
|
||||
|
||||
printline("Test #2: sum")
|
||||
if (sum(2, 2) == 4)
|
||||
printline("Sum test passed")
|
||||
else printline("Sum test failed")
|
||||
|
||||
@@ -18,6 +18,9 @@ typedef enum
|
||||
FZL_OPCODE_JMP = 0xF20001, // Jump to specified IP address
|
||||
FZL_OPCODE_JZ = 0xF20002, // Jump if top value in dstack is zero
|
||||
|
||||
FZL_OPCODE_CALL = 0xF30001, // Call function
|
||||
FZL_OPCODE_RET = 0xF30002, // Return from function
|
||||
|
||||
FZL_OPCODE_ADD = 0xA00001, // Sum two numbers in dstack
|
||||
FZL_OPCODE_SUB = 0xA00002, // Subract two numbers in dstack
|
||||
FZL_OPCODE_MUL = 0xA00003, // Multiply two numbers in dstack
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef FZL_PARSER_H
|
||||
#define FZL_PARSER_H
|
||||
|
||||
#include "common/fzl_types.h"
|
||||
#include <compiler/fzl_reader.h>
|
||||
#include <compiler/fzl_token.h>
|
||||
#include <stddef.h>
|
||||
@@ -13,6 +14,8 @@ typedef enum
|
||||
FZL_NODETYPE_LITERAL,
|
||||
FZL_NODETYPE_IDENTIFIER,
|
||||
FZL_NODETYPE_CONDITIONAL,
|
||||
FZL_NODETYPE_FUNCTION,
|
||||
FZL_NODETYPE_RETURN,
|
||||
|
||||
FZL_NODETYPE_ADD,
|
||||
FZL_NODETYPE_SUB,
|
||||
@@ -93,6 +96,23 @@ typedef struct fzl_node
|
||||
struct fzl_node *true_block;
|
||||
struct fzl_node *else_block;
|
||||
} cond;
|
||||
|
||||
// Function declaration
|
||||
struct
|
||||
{
|
||||
struct fzl_node **args;
|
||||
size_t args_count;
|
||||
|
||||
struct fzl_node *body;
|
||||
fzl_token_t *name;
|
||||
fzl_token_t *type;
|
||||
} fn;
|
||||
|
||||
// Return value
|
||||
struct
|
||||
{
|
||||
struct fzl_node *value;
|
||||
} ret;
|
||||
};
|
||||
} fzl_node_t;
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
// Token type
|
||||
typedef enum
|
||||
{
|
||||
FZL_TOKTYPE_RETURN, // return
|
||||
|
||||
FZL_TOKTYPE_IF, // if
|
||||
FZL_TOKTYPE_ELSE, // else
|
||||
|
||||
|
||||
@@ -18,6 +18,13 @@ typedef struct
|
||||
bool error;
|
||||
} fzl_walk_res_t;
|
||||
|
||||
// Function context descriptor
|
||||
typedef struct
|
||||
{
|
||||
fzl_node_t *fn;
|
||||
size_t initial_env_lvl;
|
||||
} fzl_walk_ctx_t;
|
||||
|
||||
// Walker descriptor
|
||||
typedef struct
|
||||
{
|
||||
@@ -30,6 +37,8 @@ typedef struct
|
||||
|
||||
fzl_symtable_t *syms[64];
|
||||
size_t sym_top;
|
||||
|
||||
fzl_walk_ctx_t *ctx;
|
||||
} fzl_walker_t;
|
||||
|
||||
// Allocate new walker
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <common/fzl_types.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -17,6 +18,7 @@ typedef struct
|
||||
{
|
||||
char *name;
|
||||
fzl_type_t type;
|
||||
size_t ip;
|
||||
} fzl_sym_t;
|
||||
|
||||
// Symbols table descriptor
|
||||
@@ -33,7 +35,7 @@ fzl_symtable_t *fzl_mksymt();
|
||||
|
||||
// Put new entry into symtable
|
||||
fzl_symtable_res_t fzl_symt_put(fzl_symtable_t *symt, char *name,
|
||||
fzl_type_t type);
|
||||
fzl_type_t type, uint64_t ip);
|
||||
|
||||
// Get entry from specified symtable
|
||||
bool fzl_symt_get(fzl_symtable_t *symt, char *name, fzl_sym_t *res);
|
||||
|
||||
@@ -33,7 +33,7 @@ typedef struct
|
||||
fzl_vm_env_t *fzl_mkenv();
|
||||
|
||||
// Try get value by name
|
||||
fzl_value_t fzl_env_lookup(fzl_vm_env_t *env, char *name);
|
||||
bool fzl_env_lookup(fzl_vm_env_t *env, char *name, fzl_value_t *res);
|
||||
|
||||
// Check name in env table
|
||||
bool fzl_env_contains(fzl_vm_env_t *env, char *name);
|
||||
|
||||
@@ -96,6 +96,22 @@ void print_node(fzl_node_t *node, int level)
|
||||
print_node(node->unary_op.operand, level + 1);
|
||||
break;
|
||||
|
||||
case FZL_NODETYPE_FUNCTION:
|
||||
printf("%s Function named '%s' with ret type '%s':\n", levelbuf,
|
||||
(char *)node->fn.name->value, (char *)node->fn.type->value);
|
||||
printf("-%s Args:\n", levelbuf);
|
||||
for (size_t i = 0; i < node->fn.args_count; i++)
|
||||
print_node(node->fn.args[i], level + 2);
|
||||
printf("-%s Body:\n", levelbuf);
|
||||
print_node(node->fn.body, level + 2);
|
||||
break;
|
||||
|
||||
case FZL_NODETYPE_RETURN:
|
||||
printf("%s Return:\n", levelbuf);
|
||||
if (node->ret.value)
|
||||
print_node(node->ret.value, level + 1);
|
||||
break;
|
||||
|
||||
case FZL_NODETYPE_EQUAL:
|
||||
case FZL_NODETYPE_NEQUAL:
|
||||
case FZL_NODETYPE_LESS:
|
||||
|
||||
+101
-1
@@ -514,6 +514,79 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
|
||||
if (type->type == FZL_TOKTYPE_TYPE)
|
||||
consume(parser);
|
||||
|
||||
if (type->type == FZL_TOKTYPE_TYPE &&
|
||||
next(parser)->type == FZL_TOKTYPE_LPAREN)
|
||||
{
|
||||
fzl_token_t *tok = consume(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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_token_t *lparen = consume(parser);
|
||||
if (lparen->type != FZL_TOKTYPE_LPAREN)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"expected '(' after name at %ld:%ld", lparen->ln, lparen->cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t remainder = 1;
|
||||
size_t count = 0;
|
||||
fzl_node_t **args = malloc(remainder * sizeof(fzl_node_t *));
|
||||
|
||||
while (peek(parser) && !is(parser, FZL_TOKTYPE_RPAREN))
|
||||
{
|
||||
fzl_node_t *arg = parse_statement(parser);
|
||||
if (!arg)
|
||||
return NULL;
|
||||
|
||||
if (remainder <= count)
|
||||
{
|
||||
remainder *= 2;
|
||||
args = realloc(args, remainder * sizeof(fzl_node_t *));
|
||||
}
|
||||
|
||||
args[count++] = arg;
|
||||
|
||||
if (is(parser, FZL_TOKTYPE_COMMA))
|
||||
consume(parser);
|
||||
}
|
||||
|
||||
fzl_token_t *rparen = consume(parser);
|
||||
if (rparen->type != FZL_TOKTYPE_RPAREN)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"expected ')' after argument list at %ld:%ld", 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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *body = parse_statement(parser);
|
||||
if (!body)
|
||||
return NULL;
|
||||
|
||||
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FUNCTION, tok);
|
||||
node->fn.args = args;
|
||||
node->fn.args_count = count;
|
||||
node->fn.body = body;
|
||||
node->fn.name = tok;
|
||||
node->fn.type = type;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
if (type->type == FZL_TOKTYPE_TYPE || next(parser)->type == FZL_TOKTYPE_EQ)
|
||||
{
|
||||
|
||||
@@ -574,6 +647,25 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
|
||||
return left;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
consume(parser);
|
||||
return node;
|
||||
}
|
||||
|
||||
fzl_node_t *retval = parse_expression(parser);
|
||||
if (!retval)
|
||||
return NULL;
|
||||
|
||||
node->ret.value = retval;
|
||||
return node;
|
||||
}
|
||||
|
||||
if (is(parser, FZL_TOKTYPE_IF))
|
||||
{
|
||||
fzl_token_t *if_tok = consume(parser);
|
||||
@@ -637,7 +729,7 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
|
||||
if (remainder <= count)
|
||||
{
|
||||
remainder *= 2;
|
||||
stmts = realloc(stmts, remainder);
|
||||
stmts = realloc(stmts, remainder * sizeof(fzl_node_t *));
|
||||
}
|
||||
|
||||
stmts[count++] = node;
|
||||
@@ -758,6 +850,14 @@ void fzl_freeast(fzl_node_t *root)
|
||||
if (root->unary_op.operand)
|
||||
fzl_freeast(root->unary_op.operand);
|
||||
}
|
||||
else if (root->type == FZL_NODETYPE_FUNCTION)
|
||||
{
|
||||
if (root->fn.args_count)
|
||||
for (size_t i = 0; i < root->fn.args_count; i++)
|
||||
fzl_freenode(root->fn.args[i]);
|
||||
free(root->fn.args);
|
||||
fzl_freenode(root->fn.body);
|
||||
}
|
||||
|
||||
fzl_freenode(root);
|
||||
root = root->next;
|
||||
|
||||
@@ -74,7 +74,9 @@ fzl_token_t *parse_name(fzl_reader_t *reader)
|
||||
size_t line = reader->line_n;
|
||||
size_t pos = start - reader->line_start;
|
||||
|
||||
if (strcmp(value, "if") == 0)
|
||||
if (strcmp(value, "return") == 0)
|
||||
tok = fzl_mktoken(FZL_TOKTYPE_RETURN, line, pos, value, size);
|
||||
else if (strcmp(value, "if") == 0)
|
||||
tok = fzl_mktoken(FZL_TOKTYPE_IF, line, pos, value, size);
|
||||
else if (strcmp(value, "else") == 0)
|
||||
tok = fzl_mktoken(FZL_TOKTYPE_ELSE, line, pos, value, size);
|
||||
|
||||
+142
-12
@@ -52,6 +52,8 @@ fzl_walker_t *fzl_mkwalker(fzl_node_t *root)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
walker->ctx = NULL;
|
||||
|
||||
return walker;
|
||||
}
|
||||
|
||||
@@ -152,6 +154,101 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
{
|
||||
switch (node->type)
|
||||
{
|
||||
case FZL_NODETYPE_FUNCTION:
|
||||
{
|
||||
push_op(walker, FZL_OPCODE_JMP);
|
||||
size_t skip_ip = walker->op_count;
|
||||
push_word(walker, (uint64_t)0);
|
||||
|
||||
fzl_type_t fntype = tok_to_type(node->fn.type);
|
||||
fzl_symtable_res_t putres =
|
||||
fzl_symt_put(walker->syms[walker->sym_top - 1],
|
||||
node->fn.name->value, fntype, walker->op_count);
|
||||
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);
|
||||
else
|
||||
snprintf(wlast_err, sizeof(wlast_err), "failed to store name '%s'",
|
||||
(char *)node->fn.name->value);
|
||||
|
||||
return (fzl_walk_res_t){.error = true};
|
||||
}
|
||||
|
||||
// NOTE: add sym_top limit check
|
||||
size_t lvl = walker->sym_top;
|
||||
walker->syms[walker->sym_top++] = fzl_mksymt();
|
||||
walker->ctx = malloc(sizeof(fzl_walk_ctx_t));
|
||||
walker->ctx->fn = node;
|
||||
walker->ctx->initial_env_lvl = lvl;
|
||||
|
||||
push_op(walker, FZL_OPCODE_MK_ENVTABLE);
|
||||
|
||||
for (ssize_t i = node->fn.args_count - 1; i >= 0; i--)
|
||||
{
|
||||
fzl_walk_res_t res = walk(walker, node->fn.args[i]);
|
||||
if (res.error)
|
||||
return res;
|
||||
push_op(walker, FZL_OPCODE_WRITE);
|
||||
}
|
||||
|
||||
fzl_walk_res_t bodyres = walk(walker, node->fn.body);
|
||||
if (bodyres.error)
|
||||
return bodyres;
|
||||
|
||||
// NOTE: ghost walk (w/o opcodes write) for arg check should be there in
|
||||
// near future
|
||||
|
||||
push_op(walker, FZL_OPCODE_RM_ENVTABLE);
|
||||
walker->ops[skip_ip] = walker->op_count;
|
||||
|
||||
walker->ctx = NULL; // NOTE: think about nested function defs (not now)
|
||||
for (ssize_t i = walker->sym_top - 1; i >= lvl; i--)
|
||||
fzl_freesymt(walker->syms[--walker->sym_top]);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case FZL_NODETYPE_RETURN:
|
||||
{
|
||||
if (!walker->ctx)
|
||||
{
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
"return cannot be used outside of functions");
|
||||
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
|
||||
}
|
||||
|
||||
if (node->ret.value)
|
||||
{
|
||||
fzl_walk_res_t retres = walk(walker, node->ret.value);
|
||||
if (retres.error)
|
||||
return retres;
|
||||
|
||||
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);
|
||||
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
|
||||
}
|
||||
|
||||
current_res = (fzl_walk_res_t){.type = retres.type, .error = false};
|
||||
}
|
||||
else
|
||||
current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false};
|
||||
|
||||
for (size_t i = 0; i < (walker->sym_top - walker->ctx->initial_env_lvl);
|
||||
i++)
|
||||
push_op(walker, FZL_OPCODE_RM_ENVTABLE);
|
||||
push_op(walker, FZL_OPCODE_RET);
|
||||
break;
|
||||
}
|
||||
|
||||
case FZL_NODETYPE_NOT:
|
||||
{
|
||||
fzl_walk_res_t res = walk(walker, node->unary_op.operand);
|
||||
@@ -294,8 +391,12 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
.as.string.length = node->token->value_sz});
|
||||
|
||||
fzl_sym_t sym;
|
||||
bool exists = fzl_symt_get(walker->syms[walker->sym_top - 1],
|
||||
node->token->value, &sym);
|
||||
bool exists = false;
|
||||
for (ssize_t i = walker->sym_top - 1; i >= 0; i--)
|
||||
if ((exists =
|
||||
fzl_symt_get(walker->syms[i], node->token->value, &sym)))
|
||||
break;
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
@@ -314,6 +415,7 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
}
|
||||
|
||||
case FZL_NODETYPE_BLOCK:
|
||||
walker->syms[walker->sym_top++] = fzl_mksymt();
|
||||
push_op(walker, FZL_OPCODE_MK_ENVTABLE);
|
||||
if (node->list.entry_count > 0)
|
||||
for (size_t i = 0; i < node->list.entry_count; i++)
|
||||
@@ -322,6 +424,7 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
if (res.error)
|
||||
return res;
|
||||
}
|
||||
fzl_freesymt(walker->syms[--walker->sym_top]);
|
||||
push_op(walker, FZL_OPCODE_RM_ENVTABLE);
|
||||
break;
|
||||
|
||||
@@ -335,11 +438,10 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
// NOTE: you need to implement dynamic names call too
|
||||
push_op(walker, FZL_OPCODE_CALL_BUILTIN);
|
||||
|
||||
if (strcmp(node->token->value, "printline") == 0)
|
||||
{
|
||||
push_op(walker, FZL_OPCODE_CALL_BUILTIN);
|
||||
push_word(walker, FZL_BUILTIN_PRINTLINE);
|
||||
if (node->call.args_count < 1)
|
||||
{
|
||||
@@ -348,14 +450,37 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
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};
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
"call to unknown function '%s'", (char *)node->token->value);
|
||||
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
|
||||
fzl_sym_t res;
|
||||
bool found = false;
|
||||
for (ssize_t i = walker->sym_top - 1; i >= 0; i--)
|
||||
if ((found =
|
||||
fzl_symt_get(walker->syms[i], node->token->value, &res)))
|
||||
break;
|
||||
|
||||
if (!found)
|
||||
{
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
"call to unknown function '%s'",
|
||||
(char *)node->token->value);
|
||||
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
|
||||
}
|
||||
|
||||
if (!res.ip)
|
||||
{
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
"cannot jump to address 0x0");
|
||||
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
|
||||
}
|
||||
|
||||
push_op(walker, FZL_OPCODE_CALL);
|
||||
push_word(walker, res.ip);
|
||||
|
||||
current_res = (fzl_walk_res_t){.type = res.type, .error = false};
|
||||
}
|
||||
current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false};
|
||||
break;
|
||||
|
||||
case FZL_NODETYPE_LITERAL:
|
||||
@@ -475,7 +600,7 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
{
|
||||
fzl_symtable_res_t res = fzl_symt_put(
|
||||
walker->syms[walker->sym_top - 1],
|
||||
node->var.identifier->token->value, tok_to_type(node->var.type));
|
||||
node->var.identifier->token->value, tok_to_type(node->var.type), 0);
|
||||
|
||||
fzl_token_t *id_tok = node->var.identifier->token;
|
||||
size_t const_n = add_const(
|
||||
@@ -509,9 +634,14 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
else if (node->binary_op.left->type == FZL_NODETYPE_IDENTIFIER)
|
||||
{
|
||||
fzl_sym_t sym;
|
||||
bool res = fzl_symt_get(walker->syms[walker->sym_top - 1],
|
||||
node->binary_op.left->token->value, &sym);
|
||||
if (!res) // NOTE: refactor this before implement blocks, fns, etc
|
||||
bool found = false;
|
||||
for (ssize_t i = walker->sym_top - 1; i >= 0; i--)
|
||||
if ((found =
|
||||
fzl_symt_get(walker->syms[i],
|
||||
node->binary_op.left->token->value, &sym)))
|
||||
break;
|
||||
|
||||
if (!found)
|
||||
{
|
||||
fzl_token_t *tok = node->binary_op.left->token->value;
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <compiler/utils/fzl_symtable.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -20,7 +21,7 @@ fzl_symtable_t *fzl_mksymt()
|
||||
}
|
||||
|
||||
fzl_symtable_res_t fzl_symt_put(fzl_symtable_t *symt, char *name,
|
||||
fzl_type_t type)
|
||||
fzl_type_t type, uint64_t ip)
|
||||
{
|
||||
if (!symt)
|
||||
return FZL_SYMTABLE_RESULT_ERR;
|
||||
@@ -35,7 +36,8 @@ fzl_symtable_res_t fzl_symt_put(fzl_symtable_t *symt, char *name,
|
||||
symt->symbols = realloc(symt->symbols, symt->remainder * sizeof(fzl_sym_t));
|
||||
}
|
||||
|
||||
symt->symbols[symt->size++] = (fzl_sym_t){.name = name, .type = type};
|
||||
symt->symbols[symt->size++] =
|
||||
(fzl_sym_t){.name = name, .type = type, .ip = ip};
|
||||
return FZL_SYMTABLE_RESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
+43
-13
@@ -4,6 +4,7 @@
|
||||
#include <common/fzl_types.h>
|
||||
#include <common/fzl_value.h>
|
||||
#include <compiler/utils/fzl_const_pool.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -123,6 +124,27 @@ int fzl_vm_run(fzl_vm_t *vm)
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case FZL_OPCODE_CALL:
|
||||
{
|
||||
uint64_t ip = vm->ops[++vm->ip];
|
||||
vm->cstack[vm->ctop++] = vm->ip;
|
||||
vm->ip = ip - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case FZL_OPCODE_RET:
|
||||
{
|
||||
if (vm->ctop < 1)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err),
|
||||
"runtime error - no place to jump");
|
||||
return -1;
|
||||
}
|
||||
|
||||
vm->ip = vm->cstack[--vm->ctop];
|
||||
break;
|
||||
}
|
||||
|
||||
case FZL_OPCODE_CMP_EQ:
|
||||
if (vm->dtop < 2)
|
||||
{
|
||||
@@ -131,10 +153,10 @@ int fzl_vm_run(fzl_vm_t *vm)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fzl_value_t leq = vm->dstack[--vm->dtop];
|
||||
fzl_value_t req = vm->dstack[--vm->dtop];
|
||||
fzl_value_t leq = vm->dstack[--vm->dtop];
|
||||
vm->dstack[vm->dtop++] =
|
||||
(fzl_value_t){.type = FZL_TYPE_BOOL, .as.b = leq.as.b == req.as.b};
|
||||
(fzl_value_t){.type = FZL_TYPE_BOOL, .as.b = leq.as.u == req.as.u};
|
||||
break;
|
||||
|
||||
case FZL_OPCODE_CMP_NEQ:
|
||||
@@ -145,8 +167,8 @@ int fzl_vm_run(fzl_vm_t *vm)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fzl_value_t lneq = vm->dstack[--vm->dtop];
|
||||
fzl_value_t rneq = vm->dstack[--vm->dtop];
|
||||
fzl_value_t lneq = vm->dstack[--vm->dtop];
|
||||
vm->dstack[vm->dtop++] = (fzl_value_t){.type = FZL_TYPE_BOOL,
|
||||
.as.b = lneq.as.u != rneq.as.u};
|
||||
break;
|
||||
@@ -159,8 +181,8 @@ int fzl_vm_run(fzl_vm_t *vm)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fzl_value_t llt = vm->dstack[--vm->dtop];
|
||||
fzl_value_t rlt = vm->dstack[--vm->dtop];
|
||||
fzl_value_t llt = vm->dstack[--vm->dtop];
|
||||
vm->dstack[vm->dtop++] =
|
||||
(fzl_value_t){.type = FZL_TYPE_BOOL, .as.b = llt.as.u < rlt.as.u};
|
||||
break;
|
||||
@@ -173,8 +195,8 @@ int fzl_vm_run(fzl_vm_t *vm)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fzl_value_t llteq = vm->dstack[--vm->dtop];
|
||||
fzl_value_t rlteq = vm->dstack[--vm->dtop];
|
||||
fzl_value_t llteq = vm->dstack[--vm->dtop];
|
||||
vm->dstack[vm->dtop++] = (fzl_value_t){
|
||||
.type = FZL_TYPE_BOOL, .as.b = llteq.as.u <= rlteq.as.u};
|
||||
break;
|
||||
@@ -187,8 +209,8 @@ int fzl_vm_run(fzl_vm_t *vm)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fzl_value_t lgt = vm->dstack[--vm->dtop];
|
||||
fzl_value_t rgt = vm->dstack[--vm->dtop];
|
||||
fzl_value_t lgt = vm->dstack[--vm->dtop];
|
||||
vm->dstack[vm->dtop++] =
|
||||
(fzl_value_t){.type = FZL_TYPE_BOOL, .as.b = lgt.as.u > rgt.as.u};
|
||||
break;
|
||||
@@ -201,8 +223,8 @@ int fzl_vm_run(fzl_vm_t *vm)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fzl_value_t lgteq = vm->dstack[--vm->dtop];
|
||||
fzl_value_t rgteq = vm->dstack[--vm->dtop];
|
||||
fzl_value_t lgteq = vm->dstack[--vm->dtop];
|
||||
vm->dstack[vm->dtop++] = (fzl_value_t){
|
||||
.type = FZL_TYPE_BOOL, .as.b = lgteq.as.u >= rgteq.as.u};
|
||||
break;
|
||||
@@ -319,7 +341,9 @@ int fzl_vm_run(fzl_vm_t *vm)
|
||||
}
|
||||
}
|
||||
|
||||
vm->dstack[vm->dtop++] = value;
|
||||
// vm->dstack[vm->dtop++] = value;
|
||||
// NOTE: add POP opcode to prevent
|
||||
// stack overflow!
|
||||
break;
|
||||
|
||||
case FZL_OPCODE_MK_ENVTABLE:
|
||||
@@ -340,8 +364,14 @@ int fzl_vm_run(fzl_vm_t *vm)
|
||||
}
|
||||
|
||||
fzl_value_t val = vm->dstack[--vm->dtop];
|
||||
fzl_value_t env_val =
|
||||
fzl_env_lookup(vm->estack[vm->etop - 1], (char *)val.as.s.value);
|
||||
fzl_value_t env_val;
|
||||
bool result;
|
||||
for (ssize_t i = vm->etop - 1; i >= 0; i--)
|
||||
{
|
||||
if ((result = fzl_env_lookup(vm->estack[i], (char *)val.as.s.value,
|
||||
&env_val)))
|
||||
break;
|
||||
}
|
||||
vm->dstack[vm->dtop++] = env_val;
|
||||
|
||||
break;
|
||||
@@ -411,10 +441,10 @@ int fzl_vm_run(fzl_vm_t *vm)
|
||||
"runtime error - expected 2 values in stack");
|
||||
return -1;
|
||||
}
|
||||
fzl_value_t sub1 = vm->dstack[--vm->dtop];
|
||||
fzl_value_t sub2 = vm->dstack[--vm->dtop];
|
||||
fzl_value_t sub1 = vm->dstack[--vm->dtop];
|
||||
vm->dstack[vm->dtop++] =
|
||||
(fzl_value_t){.type = add1.type, .as.u = sub1.as.u - sub2.as.u};
|
||||
(fzl_value_t){.type = sub1.type, .as.u = sub1.as.u - sub2.as.u};
|
||||
break;
|
||||
|
||||
case FZL_OPCODE_MUL:
|
||||
@@ -450,8 +480,8 @@ int fzl_vm_run(fzl_vm_t *vm)
|
||||
"runtime error - expected 2 values in stack");
|
||||
return -1;
|
||||
}
|
||||
fzl_value_t pow1 = vm->dstack[--vm->dtop];
|
||||
fzl_value_t pow2 = vm->dstack[--vm->dtop];
|
||||
fzl_value_t pow1 = vm->dstack[--vm->dtop];
|
||||
|
||||
uint64_t pow_n = pow1.as.u;
|
||||
uint64_t pow_res = pow_n;
|
||||
|
||||
+13
-1
@@ -20,6 +20,17 @@ void fzl_vm_print_ops(fzl_vm_t *vm)
|
||||
|
||||
switch (vm->ops[i])
|
||||
{
|
||||
case FZL_OPCODE_CALL:
|
||||
{
|
||||
size_t ip = vm->ops[++i];
|
||||
printf("Call IP: %lu\n", ip);
|
||||
break;
|
||||
}
|
||||
|
||||
case FZL_OPCODE_RET:
|
||||
printf("Return\n");
|
||||
break;
|
||||
|
||||
case FZL_OPCODE_LOADCONST:
|
||||
{
|
||||
size_t const_n = vm->ops[++i];
|
||||
@@ -79,6 +90,7 @@ void fzl_vm_print_ops(fzl_vm_t *vm)
|
||||
|
||||
case FZL_OPCODE_CMP_EQ:
|
||||
printf("CMP_EQ\n");
|
||||
break;
|
||||
|
||||
case FZL_OPCODE_CMP_NEQ:
|
||||
printf("CMP_NEQ\n");
|
||||
@@ -113,7 +125,7 @@ void fzl_vm_print_ops(fzl_vm_t *vm)
|
||||
break;
|
||||
|
||||
case FZL_OPCODE_JMP:
|
||||
printf("JMP IP %ld\n", vm->ops[++i]);
|
||||
printf("JMP IP: %ld\n", vm->ops[++i]);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
+7
-4
@@ -28,16 +28,19 @@ static void resize_env_if_needed(fzl_vm_env_t *env)
|
||||
env->table = realloc(env->table, env->remainder * sizeof(fzl_vm_env_entry_t));
|
||||
}
|
||||
|
||||
fzl_value_t fzl_env_lookup(fzl_vm_env_t *env, char *name)
|
||||
bool fzl_env_lookup(fzl_vm_env_t *env, char *name, fzl_value_t *res)
|
||||
{
|
||||
if (!env)
|
||||
return null;
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < env->size; i++)
|
||||
if (strcmp(env->table[i].name, name) == 0)
|
||||
return env->table[i].value;
|
||||
{
|
||||
*res = env->table[i].value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return (fzl_value_t){.type = FZL_TYPE_NULL};
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fzl_env_contains(fzl_vm_env_t *env, char *name)
|
||||
|
||||
Reference in New Issue
Block a user