lang: codegen: redesign codegen to use a stack-based state machine
This commit is contained in:
@@ -3,9 +3,98 @@
|
||||
#include <ivy/lang/codegen.h>
|
||||
#include <mie/builder.h>
|
||||
#include <mie/module.h>
|
||||
#include <mie/value.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
enum ivy_status codegen_push_generator(
|
||||
struct ivy_codegen *gen, enum code_generator_type gen_type, void *arg)
|
||||
{
|
||||
const struct code_generator *generator = get_code_generator(gen_type);
|
||||
if (!generator) {
|
||||
return IVY_ERR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (generator->g_state_size < sizeof(struct code_generator_state)) {
|
||||
return IVY_ERR_INTERNAL_FAILURE;
|
||||
}
|
||||
|
||||
struct code_generator_state *state = malloc(generator->g_state_size);
|
||||
if (!state) {
|
||||
return IVY_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memset(state, 0x0, generator->g_state_size);
|
||||
|
||||
state->s_gen = generator;
|
||||
state->s_arg = arg;
|
||||
|
||||
enum ivy_status status = IVY_OK;
|
||||
|
||||
if (generator->g_state_init) {
|
||||
status = generator->g_state_init(gen, state);
|
||||
}
|
||||
|
||||
if (status != IVY_OK) {
|
||||
free(state);
|
||||
return status;
|
||||
}
|
||||
|
||||
b_queue_push_back(&gen->c_state, &state->s_entry);
|
||||
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
enum ivy_status codegen_pop_generator(struct ivy_codegen *gen)
|
||||
{
|
||||
b_queue_entry *entry = b_queue_pop_back(&gen->c_state);
|
||||
if (!entry) {
|
||||
return IVY_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
struct code_generator_state *state
|
||||
= b_unbox(struct code_generator_state, entry, s_entry);
|
||||
|
||||
enum ivy_status status = IVY_OK;
|
||||
|
||||
if (state->s_gen->g_state_fini) {
|
||||
status = state->s_gen->g_state_fini(gen, state);
|
||||
}
|
||||
|
||||
if (status != IVY_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
free(state);
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
void codegen_push_value(struct ivy_codegen *gen, struct mie_value *value)
|
||||
{
|
||||
b_queue_push_back(&gen->c_ir_values, &value->v_entry);
|
||||
}
|
||||
|
||||
struct mie_value *codegen_pop_value(struct ivy_codegen *gen)
|
||||
{
|
||||
b_queue_entry *entry = b_queue_pop_back(&gen->c_ir_values);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return b_unbox(struct mie_value, entry, v_entry);
|
||||
}
|
||||
|
||||
static struct code_generator_state *get_current_generator_state(
|
||||
struct ivy_codegen *gen)
|
||||
{
|
||||
b_queue_entry *entry = b_queue_last(&gen->c_state);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return b_unbox(struct code_generator_state, entry, s_entry);
|
||||
}
|
||||
|
||||
enum ivy_status ivy_codegen_create(struct ivy_codegen **out)
|
||||
{
|
||||
struct ivy_codegen *gen = malloc(sizeof *gen);
|
||||
@@ -17,6 +106,8 @@ enum ivy_status ivy_codegen_create(struct ivy_codegen **out)
|
||||
|
||||
gen->c_ctx = mie_ctx_create();
|
||||
|
||||
codegen_push_generator(gen, CODE_GENERATOR_UNIT, NULL);
|
||||
|
||||
*out = gen;
|
||||
return IVY_OK;
|
||||
}
|
||||
@@ -67,3 +158,53 @@ enum ivy_status ivy_codegen_end_module(
|
||||
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
struct mie_module *ivy_codegen_get_current_module(struct ivy_codegen *gen)
|
||||
{
|
||||
return gen->c_module;
|
||||
}
|
||||
|
||||
enum ivy_status ivy_codegen_push_node(
|
||||
struct ivy_codegen *gen, struct ivy_ast_node *node,
|
||||
enum ivy_ast_iteration_type node_type)
|
||||
{
|
||||
if (!gen->c_builder) {
|
||||
return IVY_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
struct code_generator_state *state
|
||||
= get_current_generator_state(gen);
|
||||
|
||||
if (!state) {
|
||||
return IVY_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
const struct code_generator *generator = state->s_gen;
|
||||
|
||||
code_generator_node_callback func;
|
||||
switch (node_type) {
|
||||
case IVY_AST_ITERATION_PRE:
|
||||
func = generator->g_node_generators_pre[node->n_type];
|
||||
break;
|
||||
case IVY_AST_ITERATION_POST:
|
||||
func = generator->g_node_generators_post[node->n_type];
|
||||
break;
|
||||
default:
|
||||
return IVY_ERR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (!func) {
|
||||
return IVY_ERR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
struct code_generator_result result = func(gen, state, node);
|
||||
if (result.r_flags & CODEGEN_REPEAT_NODE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return result.r_status;
|
||||
}
|
||||
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
@@ -2,17 +2,84 @@
|
||||
#define _LANG_CODEGEN_H_
|
||||
|
||||
#include <blue/core/queue.h>
|
||||
#include <ivy/lang/ast.h>
|
||||
#include <ivy/lang/lex.h>
|
||||
#include <mie/builder.h>
|
||||
|
||||
struct mie_builder;
|
||||
struct mie_ctx;
|
||||
#define CODEGEN_RESULT_OK(flags) \
|
||||
(struct code_generator_result) \
|
||||
{ \
|
||||
.r_status = (IVY_OK), .r_flags = (flags) \
|
||||
}
|
||||
#define CODEGEN_RESULT_ERR(status) \
|
||||
(struct code_generator_result) \
|
||||
{ \
|
||||
.r_status = (status), .r_flags = (0) \
|
||||
}
|
||||
|
||||
struct ivy_codegen;
|
||||
struct ivy_ast_node;
|
||||
|
||||
struct mie_value;
|
||||
struct mie_func;
|
||||
|
||||
enum code_generator_type {
|
||||
CODE_GENERATOR_NONE = 0,
|
||||
CODE_GENERATOR_UNIT,
|
||||
CODE_GENERATOR_EXPR,
|
||||
};
|
||||
|
||||
struct code_generator_result {
|
||||
enum ivy_status r_status;
|
||||
|
||||
enum code_generator_result_flags {
|
||||
CODEGEN_REPEAT_NODE = 0x01u,
|
||||
} r_flags;
|
||||
};
|
||||
|
||||
struct code_generator_state;
|
||||
|
||||
typedef enum ivy_status (*code_generator_state_init_callback)(
|
||||
struct ivy_codegen *, struct code_generator_state *);
|
||||
typedef enum ivy_status (*code_generator_state_fini_callback)(
|
||||
struct ivy_codegen *, struct code_generator_state *);
|
||||
typedef struct code_generator_result (*code_generator_callback)(
|
||||
struct ivy_codegen *);
|
||||
typedef struct code_generator_result (*code_generator_node_callback)(
|
||||
struct ivy_codegen *, struct code_generator_state *, struct ivy_ast_node *);
|
||||
|
||||
struct code_generator {
|
||||
enum code_generator_type g_type;
|
||||
size_t g_state_size;
|
||||
|
||||
code_generator_state_init_callback g_state_init;
|
||||
code_generator_state_fini_callback g_state_fini;
|
||||
code_generator_node_callback g_node_generators_pre[IVY_AST_TYPE_COUNT];
|
||||
code_generator_node_callback g_node_generators_post[IVY_AST_TYPE_COUNT];
|
||||
};
|
||||
|
||||
struct code_generator_state {
|
||||
b_queue_entry s_entry;
|
||||
void *s_arg;
|
||||
const struct code_generator *s_gen;
|
||||
};
|
||||
|
||||
struct ivy_codegen {
|
||||
b_queue c_ir_values;
|
||||
b_queue c_state;
|
||||
struct mie_builder *c_builder;
|
||||
struct mie_ctx *c_ctx;
|
||||
struct mie_module *c_module;
|
||||
struct mie_func *c_immediate;
|
||||
};
|
||||
|
||||
extern const struct code_generator *get_code_generator(
|
||||
enum code_generator_type type);
|
||||
|
||||
extern enum ivy_status codegen_push_generator(
|
||||
struct ivy_codegen *gen, enum code_generator_type gen_type, void *arg);
|
||||
extern enum ivy_status codegen_pop_generator(struct ivy_codegen *gen);
|
||||
|
||||
extern void codegen_push_value(struct ivy_codegen *gen, struct mie_value *value);
|
||||
extern struct mie_value *codegen_pop_value(struct ivy_codegen *gen);
|
||||
|
||||
#endif
|
||||
|
||||
127
lang/codegen/expr.c
Normal file
127
lang/codegen/expr.c
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "codegen.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct expr_codegen_state {
|
||||
struct code_generator_state s_base;
|
||||
struct ivy_ast_node *s_expr_root;
|
||||
};
|
||||
|
||||
static struct code_generator_result check_expr_root(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
||||
struct ivy_ast_node *node)
|
||||
{
|
||||
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
||||
if (!expr->s_expr_root) {
|
||||
expr->s_expr_root = node;
|
||||
}
|
||||
|
||||
return CODEGEN_RESULT_OK(0);
|
||||
}
|
||||
|
||||
static struct code_generator_result gen_int(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
||||
struct ivy_ast_node *node)
|
||||
{
|
||||
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
||||
|
||||
printf("codegen: got int\n");
|
||||
|
||||
struct ivy_ast_int_node *int_node = (struct ivy_ast_int_node *)node;
|
||||
struct mie_value *value
|
||||
= mie_ctx_get_int(gen->c_ctx, int_node->n_value->t_int, 32);
|
||||
|
||||
codegen_push_value(gen, value);
|
||||
|
||||
if (node == expr->s_expr_root) {
|
||||
codegen_pop_generator(gen);
|
||||
}
|
||||
|
||||
return CODEGEN_RESULT_OK(0);
|
||||
}
|
||||
|
||||
static struct code_generator_result gen_op(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
||||
struct ivy_ast_node *node)
|
||||
{
|
||||
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
||||
|
||||
printf("codegen: got operator\n");
|
||||
|
||||
struct mie_value *left = codegen_pop_value(gen);
|
||||
struct mie_value *right = codegen_pop_value(gen);
|
||||
|
||||
if (!left || !right) {
|
||||
return CODEGEN_RESULT_ERR(IVY_ERR_INVALID_VALUE);
|
||||
}
|
||||
|
||||
struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)node;
|
||||
const struct ivy_operator *op = op_node->n_op;
|
||||
struct mie_value *op_instr = NULL;
|
||||
|
||||
switch (op->op_id) {
|
||||
case IVY_OP_ADD:
|
||||
op_instr
|
||||
= mie_builder_add(gen->c_builder, left, right, "addtmp");
|
||||
break;
|
||||
case IVY_OP_SUBTRACT:
|
||||
op_instr
|
||||
= mie_builder_sub(gen->c_builder, left, right, "subtmp");
|
||||
break;
|
||||
case IVY_OP_MULTIPLY:
|
||||
op_instr
|
||||
= mie_builder_mul(gen->c_builder, left, right, "multmp");
|
||||
break;
|
||||
case IVY_OP_DIVIDE:
|
||||
op_instr
|
||||
= mie_builder_div(gen->c_builder, left, right, "divtmp");
|
||||
break;
|
||||
default:
|
||||
mie_value_destroy(left);
|
||||
mie_value_destroy(right);
|
||||
return CODEGEN_RESULT_ERR(IVY_ERR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
if (!op_instr) {
|
||||
mie_value_destroy(left);
|
||||
mie_value_destroy(right);
|
||||
return CODEGEN_RESULT_ERR(IVY_ERR_NO_MEMORY);
|
||||
}
|
||||
|
||||
codegen_push_value(gen, op_instr);
|
||||
|
||||
if (node == expr->s_expr_root) {
|
||||
codegen_pop_generator(gen);
|
||||
}
|
||||
|
||||
return CODEGEN_RESULT_OK(0);
|
||||
}
|
||||
|
||||
static enum ivy_status state_init(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state)
|
||||
{
|
||||
printf("codegen: start of expression\n");
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
static enum ivy_status state_fini(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state)
|
||||
{
|
||||
printf("codegen: end of expression\n");
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
struct code_generator expr_generator = {
|
||||
.g_type = CODE_GENERATOR_UNIT,
|
||||
.g_state_size = sizeof(struct expr_codegen_state),
|
||||
.g_state_init = state_init,
|
||||
.g_state_fini = state_fini,
|
||||
.g_node_generators_pre = {
|
||||
[IVY_AST_INT] = check_expr_root,
|
||||
[IVY_AST_OP] = check_expr_root,
|
||||
},
|
||||
.g_node_generators_post = {
|
||||
[IVY_AST_INT] = gen_int,
|
||||
[IVY_AST_OP] = gen_op,
|
||||
},
|
||||
};
|
||||
20
lang/codegen/generator.c
Normal file
20
lang/codegen/generator.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "codegen.h"
|
||||
|
||||
extern const struct code_generator unit_generator;
|
||||
extern const struct code_generator expr_generator;
|
||||
|
||||
static const struct code_generator *code_generators[] = {
|
||||
[CODE_GENERATOR_UNIT] = &unit_generator,
|
||||
[CODE_GENERATOR_EXPR] = &expr_generator,
|
||||
};
|
||||
static const size_t nr_code_generators
|
||||
= sizeof code_generators / sizeof code_generators[0];
|
||||
|
||||
const struct code_generator *get_code_generator(enum code_generator_type type)
|
||||
{
|
||||
if (type >= nr_code_generators) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return code_generators[type];
|
||||
}
|
||||
12
lang/codegen/try.c
Normal file
12
lang/codegen/try.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "codegen.h"
|
||||
|
||||
enum ivy_status try_code_generator(struct ivy_codegen *gen, struct ivy_ast_node *node)
|
||||
{
|
||||
return IVY_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
enum ivy_status try_catch_code_generator(
|
||||
struct ivy_codegen *gen, struct ivy_ast_node *node)
|
||||
{
|
||||
return IVY_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
68
lang/codegen/unit.c
Normal file
68
lang/codegen/unit.c
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "codegen.h"
|
||||
|
||||
#include <mie/block.h>
|
||||
#include <mie/func.h>
|
||||
#include <mie/module.h>
|
||||
|
||||
struct unit_codegen_state {
|
||||
struct code_generator_state s_base;
|
||||
/* function for top-level statements */
|
||||
struct mie_func *s_immediate;
|
||||
};
|
||||
|
||||
static enum ivy_status switch_to_immediate_func(
|
||||
struct ivy_codegen *gen, struct unit_codegen_state *unit)
|
||||
{
|
||||
if (!unit->s_immediate) {
|
||||
struct mie_type *ret_type
|
||||
= mie_ctx_get_type(gen->c_ctx, MIE_TYPE_VOID);
|
||||
unit->s_immediate = mie_func_create(
|
||||
"init", MIE_FUNC_STATIC, ret_type, NULL, 0);
|
||||
|
||||
if (!unit->s_immediate) {
|
||||
return IVY_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
mie_module_add_function(gen->c_module, unit->s_immediate);
|
||||
}
|
||||
|
||||
struct mie_block *block = mie_func_get_last_block(unit->s_immediate);
|
||||
if (!block || mie_block_is_terminated(block)) {
|
||||
block = mie_func_create_block(unit->s_immediate, NULL);
|
||||
mie_func_insert_block(unit->s_immediate, block, NULL);
|
||||
}
|
||||
|
||||
mie_builder_set_insert_point(gen->c_builder, block);
|
||||
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
static struct code_generator_result gen_expr(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
||||
struct ivy_ast_node *node)
|
||||
{
|
||||
struct unit_codegen_state *unit = (struct unit_codegen_state *)state;
|
||||
struct mie_builder *builder = gen->c_builder;
|
||||
struct mie_func *current = mie_builder_get_current_func(builder);
|
||||
|
||||
enum ivy_status status = IVY_OK;
|
||||
if (!current || current != unit->s_immediate) {
|
||||
status = switch_to_immediate_func(gen, unit);
|
||||
}
|
||||
|
||||
if (status != IVY_OK) {
|
||||
return CODEGEN_RESULT_ERR(status);
|
||||
}
|
||||
|
||||
codegen_push_generator(gen, CODE_GENERATOR_EXPR, NULL);
|
||||
return CODEGEN_RESULT_OK(CODEGEN_REPEAT_NODE);
|
||||
}
|
||||
|
||||
struct code_generator unit_generator = {
|
||||
.g_type = CODE_GENERATOR_UNIT,
|
||||
.g_state_size = sizeof(struct unit_codegen_state),
|
||||
.g_node_generators_pre = {
|
||||
[IVY_AST_INT] = gen_expr,
|
||||
[IVY_AST_OP] = gen_expr,
|
||||
},
|
||||
};
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
struct ivy_codegen;
|
||||
struct ivy_ast_node;
|
||||
enum ivy_ast_iteration_type;
|
||||
|
||||
struct mie_module;
|
||||
|
||||
@@ -15,8 +16,10 @@ IVY_API void ivy_codegen_destroy(struct ivy_codegen *gen);
|
||||
IVY_API enum ivy_status ivy_codegen_start_module(struct ivy_codegen *gen);
|
||||
IVY_API enum ivy_status ivy_codegen_end_module(
|
||||
struct ivy_codegen *gen, struct mie_module **out);
|
||||
IVY_API struct mie_module *ivy_codegen_get_current_module(struct ivy_codegen *gen);
|
||||
|
||||
IVY_API enum ivy_status ivy_codegen_push_node(
|
||||
struct ivy_codegen *gen, struct ivy_ast_node *node);
|
||||
struct ivy_codegen *gen, struct ivy_ast_node *node,
|
||||
enum ivy_ast_iteration_type node_type);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user