diff --git a/bshell/compile.h b/bshell/compile.h new file mode 100644 index 0000000..28205ce --- /dev/null +++ b/bshell/compile.h @@ -0,0 +1,12 @@ +#ifndef COMPILE_H_ +#define COMPILE_H_ + +#include "script-block.h" + +struct ast_node; + +extern enum bshell_status bshell_compile( + struct ast_node *src, + bshell_scriptblock *dest); + +#endif diff --git a/bshell/compile/array.c b/bshell/compile/array.c new file mode 100644 index 0000000..82d61bd --- /dev/null +++ b/bshell/compile/array.c @@ -0,0 +1,13 @@ +#include "compile-node.h" + +struct compile_result compile_array( + struct compile_ctx *ctx, + struct ast_node *src) +{ + struct array_ast_node *array = (struct array_ast_node *)src; + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_MK_ARRAY, + fx_queue_length(&array->n_items)); + return COMPILE_OK(0); +} diff --git a/bshell/compile/block.c b/bshell/compile/block.c new file mode 100644 index 0000000..c284fad --- /dev/null +++ b/bshell/compile/block.c @@ -0,0 +1,61 @@ +#include "../compile.h" +#include "compile-node.h" + +#include + +static enum bshell_status block_load( + struct compile_ctx *ctx, + struct compile_value *value) +{ + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_LDBLOCK, + value->v_pool); + return BSHELL_SUCCESS; +} + +static const struct compile_value_type block_type = { + .v_load = block_load, +}; + +struct compile_result compile_block( + struct compile_ctx *ctx, + struct ast_node *src) +{ + bshell_scriptblock *sub_block = bshell_scriptblock_create(); + if (!sub_block) { + return COMPILE_ERR(BSHELL_ERR_NO_MEMORY); + } + + enum bshell_status status = bshell_compile(src, sub_block); + if (status != BSHELL_SUCCESS) { + bshell_scriptblock_unref(sub_block); + return COMPILE_ERR(status); + } + + fx_value sub_block_value = FX_VALUE_OBJECT(sub_block); + unsigned long slot = bshell_scriptblock_add_pool_value( + ctx->c_block, + &sub_block_value); + fx_value_unset(&sub_block_value); + compile_push_pool_value(ctx, &block_type, slot); + + return COMPILE_OK(0); +} + +enum bshell_status compile_block_immediate( + struct compile_ctx *ctx, + struct ast_node *src) +{ + enum bshell_status status = BSHELL_SUCCESS; + struct block_ast_node *block = (struct block_ast_node *)src; + + fx_queue_entry *cur = fx_queue_first(&block->n_statements); + while (cur && status == BSHELL_SUCCESS) { + struct ast_node *node = fx_unbox(struct ast_node, cur, n_entry); + status = compile_node(ctx, node); + cur = fx_queue_next(cur); + } + + return status; +} diff --git a/bshell/compile/command.c b/bshell/compile/command.c new file mode 100644 index 0000000..ee0fab8 --- /dev/null +++ b/bshell/compile/command.c @@ -0,0 +1,72 @@ +#include "compile-node.h" + +enum bshell_status cmdcall_load( + struct compile_ctx *ctx, + struct compile_value *value) +{ + struct cmdcall_ast_node *cmdcall = (struct cmdcall_ast_node *) + value->v_node; + bshell_scriptblock_push_instruction(ctx->c_block, OPCODE_PEXEC, 1); + return BSHELL_SUCCESS; +} + +enum bshell_status pipeline_load( + struct compile_ctx *ctx, + struct compile_value *value) +{ + struct pipeline_ast_node *pipeline = (struct pipeline_ast_node *) + value->v_node; + size_t nr_items = fx_queue_length(&pipeline->n_stages); + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_PEXEC, + nr_items); + return BSHELL_SUCCESS; +} + +static const struct compile_value_type cmdcall_type = { + .v_load = cmdcall_load, +}; + +static const struct compile_value_type pipeline_type = { + .v_load = pipeline_load, +}; + +struct compile_result compile_cmdcall( + struct compile_ctx *ctx, + struct ast_node *src) +{ + struct cmdcall_ast_node *cmdcall = (struct cmdcall_ast_node *)src; + size_t nr_args = fx_queue_length(&cmdcall->n_args); + for (size_t i = 0; i < nr_args; i++) { + struct compile_value *arg = compile_pop_value(ctx); + compile_value_load(ctx, arg); + compile_value_destroy(arg); + } + + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_LDCMD, + nr_args); + + compile_push_value(ctx, &cmdcall_type, src); + return COMPILE_OK(0); +} + +struct compile_result compile_pipeline( + struct compile_ctx *ctx, + struct ast_node *src) +{ + struct pipeline_ast_node *pipeline = (struct pipeline_ast_node *)src; + size_t nr_items = fx_queue_length(&pipeline->n_stages); + for (size_t i = 0; i < nr_items; i++) { + struct compile_value *item = compile_pop_value(ctx); + if (item->v_node->n_type != AST_CMDCALL) { + compile_value_load(ctx, item); + } + compile_value_destroy(item); + } + + compile_push_value(ctx, &pipeline_type, src); + return COMPILE_OK(0); +} diff --git a/bshell/compile/compile-node.h b/bshell/compile/compile-node.h new file mode 100644 index 0000000..6fb89a7 --- /dev/null +++ b/bshell/compile/compile-node.h @@ -0,0 +1,175 @@ +#ifndef COMPILE_COMPILE_NODE_H_ +#define COMPILE_COMPILE_NODE_H_ + +#include "../ast/ast.h" +#include "../operator.h" +#include "../parse/token.h" +#include "../script-block.h" + +#include +#include + +#define COMPILE_OK(flags) \ + ((struct compile_result) {.r_status = BSHELL_SUCCESS, \ + .r_flags = (flags)}) +#define COMPILE_ERR(status) ((struct compile_result) {.r_status = (status)}) + +struct compile_ctx; +struct compile_value; + +struct compile_result { + enum bshell_status r_status; + enum { + COMPILE_REPEAT_NODE = 0x00u, + } r_flags; +}; + +typedef struct compile_result (*compile_begin_impl)(struct compile_ctx *); +typedef struct compile_result (*compile_end_impl)(struct compile_ctx *); +typedef struct compile_result ( + *compile_node_impl)(struct compile_ctx *, struct ast_node *); + +enum compile_state_type_id { + COMPILE_NORMAL = 0, + COMPILE_FSTRING, +}; + +struct compile_value_type { + enum bshell_status ( + *v_load)(struct compile_ctx *, struct compile_value *); + enum bshell_status ( + *v_store)(struct compile_ctx *, struct compile_value *); +}; + +struct compile_value { + const struct compile_value_type *v_type; + enum operator_id v_op; + struct compile_value *v_left, *v_right; + struct ast_node *v_node; + unsigned long v_pool; + fx_queue_entry v_entry; +}; + +struct compile_label { + size_t l_ip; +}; + +struct compile_label_ref { + fx_queue_entry ref_entry; + size_t ref_offset; + size_t ref_label_id; +}; + +struct compile_ctx { + fx_queue c_state, c_stack; + bshell_scriptblock *c_block; + FX_VECTOR_DECLARE(struct compile_label, c_labels); + fx_queue c_label_refs; + size_t c_depth; +}; + +struct compile_state_type { + size_t s_size; + compile_begin_impl s_compile_begin; + compile_end_impl s_compile_end; + const compile_node_impl *s_compile_node; + compile_node_impl s_compile_node_generic; + size_t s_nr_compile_node; +}; + +struct compile_state { + const struct compile_state_type *s_type; + fx_queue_entry s_entry; + size_t s_depth; +}; + +extern struct compile_state *compile_push_state( + struct compile_ctx *ctx, + enum compile_state_type_id state_type); +extern void compile_pop_state(struct compile_ctx *ctx); +extern struct compile_state *compile_get_state(const struct compile_ctx *ctx); + +extern enum bshell_status compile_push_value( + struct compile_ctx *ctx, + const struct compile_value_type *type, + struct ast_node *node); +extern enum bshell_status compile_push_pool_value( + struct compile_ctx *ctx, + const struct compile_value_type *type, + unsigned long pool_slot); +extern enum bshell_status compile_push_op( + struct compile_ctx *ctx, + const struct compile_value_type *type, + enum operator_id op, + struct compile_value *left, + struct compile_value *right); +extern struct compile_value *compile_pop_value(struct compile_ctx *ctx); +extern void compile_value_load( + struct compile_ctx *ctx, + struct compile_value *item); +extern void compile_value_store( + struct compile_ctx *ctx, + struct compile_value *item); +extern void compile_value_destroy(struct compile_value *item); + +extern size_t compile_declare_label(struct compile_ctx *ctx); +extern void compile_define_label(struct compile_ctx *ctx, size_t label_id); +extern void compile_ref_label(struct compile_ctx *ctx, size_t label_id); +extern enum bshell_status compile_resolve_labels(struct compile_ctx *ctx); + +extern struct compile_result compile_int( + struct compile_ctx *ctx, + struct ast_node *src); +extern struct compile_result compile_string( + struct compile_ctx *ctx, + struct ast_node *src); +extern struct compile_result compile_word( + struct compile_ctx *ctx, + struct ast_node *src); +extern struct compile_result compile_op( + struct compile_ctx *ctx, + struct ast_node *src); +extern struct compile_result compile_var( + struct compile_ctx *ctx, + struct ast_node *src); + +extern struct compile_result compile_fstring( + struct compile_ctx *ctx, + struct ast_node *src); +extern struct compile_result compile_array( + struct compile_ctx *ctx, + struct ast_node *src); +extern struct compile_result compile_hashtable_item( + struct compile_ctx *ctx, + struct ast_node *src); +extern struct compile_result compile_hashtable( + struct compile_ctx *ctx, + struct ast_node *src); + +extern struct compile_result compile_block( + struct compile_ctx *ctx, + struct ast_node *src); + +extern struct compile_result compile_cmdcall( + struct compile_ctx *ctx, + struct ast_node *src); +extern struct compile_result compile_pipeline( + struct compile_ctx *ctx, + struct ast_node *src); + +extern enum bshell_status compile_if( + struct compile_ctx *ctx, + struct ast_node *src); + +extern enum bshell_status compile_block_immediate( + struct compile_ctx *ctx, + struct ast_node *src); + +extern enum bshell_status compile_expression( + struct compile_ctx *ctx, + struct ast_node *src); +extern enum bshell_status compile_node( + struct compile_ctx *ctx, + struct ast_node *src); + +#endif diff --git a/bshell/compile/compile.c b/bshell/compile/compile.c new file mode 100644 index 0000000..3fe9429 --- /dev/null +++ b/bshell/compile/compile.c @@ -0,0 +1,43 @@ +#include "../compile.h" + +#include "../ast/ast.h" +#include "../debug.h" +#include "../status.h" +#include "compile-node.h" + +#include + +extern enum bshell_status compile_node( + struct compile_ctx *ctx, + struct ast_node *src) +{ + switch (src->n_type) { + case AST_IF: + return compile_if(ctx, src); + case AST_BLOCK: + return compile_block_immediate(ctx, src); + default: + return compile_expression(ctx, src); + } + + return BSHELL_SUCCESS; +} + +enum bshell_status bshell_compile( + struct ast_node *src, + bshell_scriptblock *dest) +{ + struct compile_ctx ctx = {.c_block = dest}; + + enum bshell_status status = compile_node(&ctx, src); + if (status != BSHELL_SUCCESS) { + return status; + } + + status = compile_resolve_labels(&ctx); + if (status != BSHELL_SUCCESS) { + return status; + } + + return BSHELL_SUCCESS; +} diff --git a/bshell/compile/const.c b/bshell/compile/const.c new file mode 100644 index 0000000..7ac74bf --- /dev/null +++ b/bshell/compile/const.c @@ -0,0 +1,85 @@ +#include "compile-node.h" + +enum bshell_status int_load( + struct compile_ctx *ctx, + struct compile_value *value) +{ + struct int_ast_node *i = (struct int_ast_node *)value->v_node; + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_LDC_INT, + i->n_value->tok_int); + return BSHELL_SUCCESS; +} + +enum bshell_status string_load( + struct compile_ctx *ctx, + struct compile_value *value) +{ + struct string_ast_node *s = (struct string_ast_node *)value->v_node; + unsigned long index = bshell_scriptblock_get_string( + ctx->c_block, + s->n_value->tok_str); + if (index == POOL_INDEX_INVALID) { + return BSHELL_ERR_NO_MEMORY; + } + + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_LDC_STR, + index); + return BSHELL_SUCCESS; +} + +enum bshell_status word_load( + struct compile_ctx *ctx, + struct compile_value *value) +{ + struct word_ast_node *s = (struct word_ast_node *)value->v_node; + unsigned long index = bshell_scriptblock_get_string( + ctx->c_block, + s->n_value->tok_str); + if (index == POOL_INDEX_INVALID) { + return BSHELL_ERR_NO_MEMORY; + } + + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_LDC_STR, + index); + return BSHELL_SUCCESS; +} + +static const struct compile_value_type int_type = { + .v_load = int_load, +}; + +static const struct compile_value_type string_type = { + .v_load = string_load, +}; + +static const struct compile_value_type word_type = { + .v_load = word_load, +}; + +struct compile_result compile_int(struct compile_ctx *ctx, struct ast_node *src) +{ + compile_push_value(ctx, &int_type, src); + return COMPILE_OK(0); +} + +struct compile_result compile_string( + struct compile_ctx *ctx, + struct ast_node *src) +{ + compile_push_value(ctx, &string_type, src); + return COMPILE_OK(0); +} + +struct compile_result compile_word( + struct compile_ctx *ctx, + struct ast_node *src) +{ + compile_push_value(ctx, &word_type, src); + return COMPILE_OK(0); +} diff --git a/bshell/compile/expression.c b/bshell/compile/expression.c new file mode 100644 index 0000000..9d8994e --- /dev/null +++ b/bshell/compile/expression.c @@ -0,0 +1,72 @@ +#include "compile-node.h" + +static struct ast_iterate_result do_compile_node( + struct ast_node *node, + enum ast_iteration_type it_type, + struct ast_iterator *it, + struct compile_ctx *ctx) +{ + if (it_type != AST_ITERATION_POST) { + int flags = 0; + switch (node->n_type) { + case AST_BLOCK: + break; + default: + flags |= AST_ITERATE_ADD_CHILDREN; + break; + } + + return AST_ITERATE_OK(flags); + } + + ctx->c_depth = node->n_it.e_depth; + struct compile_state *state = compile_get_state(ctx); + while (state->s_depth >= ctx->c_depth && state->s_depth > 0) { + compile_pop_state(ctx); + state = compile_get_state(ctx); + } + + compile_node_impl impl = NULL; + + if (node->n_type < state->s_type->s_nr_compile_node) { + impl = state->s_type->s_compile_node[node->n_type]; + } + + if (!impl) { + impl = state->s_type->s_compile_node_generic; + } + + if (!impl) { + return AST_ITERATE_OK(0); + } + + struct compile_result result = impl(ctx, node); + unsigned int flags = 0; + if (result.r_flags & COMPILE_REPEAT_NODE) { + flags |= AST_ITERATE_REPEAT; + } + + if (result.r_status == BSHELL_SUCCESS) { + return AST_ITERATE_OK(flags); + } + + return AST_ITERATE_ERR(result.r_status); +} + +enum bshell_status compile_expression( + struct compile_ctx *ctx, + struct ast_node *src) +{ + compile_push_state(ctx, COMPILE_NORMAL); + + struct ast_iterator it = {0}; + ast_node_iterate(src, &it, (ast_iterator_callback)do_compile_node, ctx); + + struct compile_value *result = compile_pop_value(ctx); + if (result) { + compile_value_load(ctx, result); + compile_value_destroy(result); + } + + return BSHELL_SUCCESS; +} diff --git a/bshell/compile/fstring.c b/bshell/compile/fstring.c new file mode 100644 index 0000000..0c233a3 --- /dev/null +++ b/bshell/compile/fstring.c @@ -0,0 +1,35 @@ +#include "compile-node.h" + +enum bshell_status fstring_load( + struct compile_ctx *ctx, + struct compile_value *value) +{ + struct fstring_ast_node *fstring = (struct fstring_ast_node *) + value->v_node; + + return BSHELL_SUCCESS; +} + +static const struct compile_value_type fstring_type = { + .v_load = fstring_load, +}; + +struct compile_result compile_fstring( + struct compile_ctx *ctx, + struct ast_node *src) +{ + struct fstring_ast_node *fstring = (struct fstring_ast_node *)src; + size_t nr_items = fx_queue_length(&fstring->n_elements); + for (size_t i = 0; i < nr_items; i++) { + struct compile_value *item = compile_pop_value(ctx); + compile_value_load(ctx, item); + compile_value_destroy(item); + } + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_MK_STR, + fx_queue_length(&fstring->n_elements)); + + compile_push_value(ctx, &fstring_type, src); + return COMPILE_OK(0); +} diff --git a/bshell/compile/hashtable.c b/bshell/compile/hashtable.c new file mode 100644 index 0000000..c64340c --- /dev/null +++ b/bshell/compile/hashtable.c @@ -0,0 +1,39 @@ +#include "compile-node.h" + +static const struct compile_value_type hashtable_type = {}; +static const struct compile_value_type hashtable_item_type = {}; + +struct compile_result compile_hashtable( + struct compile_ctx *ctx, + struct ast_node *src) +{ + struct hashtable_ast_node *hashtable = (struct hashtable_ast_node *)src; + size_t nr_items = fx_queue_length(&hashtable->n_items); + for (size_t i = 0; i < nr_items; i++) { + struct compile_value *item = compile_pop_value(ctx); + compile_value_load(ctx, item); + compile_value_destroy(item); + } + + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_MK_HTAB, + nr_items); + compile_push_value(ctx, &hashtable_type, src); + return COMPILE_OK(0); +} + +struct compile_result compile_hashtable_item( + struct compile_ctx *ctx, + struct ast_node *src) +{ + struct compile_value *value = compile_pop_value(ctx); + struct compile_value *key = compile_pop_value(ctx); + compile_value_load(ctx, key); + compile_value_load(ctx, value); + compile_value_destroy(key); + compile_value_destroy(value); + + compile_push_value(ctx, &hashtable_item_type, src); + return COMPILE_OK(0); +} diff --git a/bshell/compile/if.c b/bshell/compile/if.c new file mode 100644 index 0000000..c34b616 --- /dev/null +++ b/bshell/compile/if.c @@ -0,0 +1,75 @@ +#include "compile-node.h" + +enum bshell_status compile_if(struct compile_ctx *ctx, struct ast_node *src) +{ + struct if_ast_node *if_group = (struct if_ast_node *)src; + size_t nr_labels = fx_queue_length(&if_group->n_branches); + // add one extra label for the end of the if group + nr_labels++; + + size_t *label_ids = calloc(nr_labels, sizeof *label_ids); + if (!label_ids) { + return BSHELL_ERR_NO_MEMORY; + } + + size_t i; + for (i = 0; i < nr_labels; i++) { + label_ids[i] = compile_declare_label(ctx); + } + + i = 0; + fx_queue_entry *cur = fx_queue_first(&if_group->n_branches); + while (cur) { + struct if_branch_ast_node *branch = fx_unbox( + struct if_branch_ast_node, + cur, + n_base.n_entry); + if (!branch->n_cond) { + compile_block_immediate(ctx, branch->n_body); + compile_ref_label(ctx, label_ids[nr_labels - 1]); + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_BR, + 0); + break; + } + + compile_expression(ctx, branch->n_cond); + compile_ref_label(ctx, label_ids[i++]); + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_BR_TRUE, + 0); + + cur = fx_queue_next(cur); + } + + i = 0; + cur = fx_queue_first(&if_group->n_branches); + while (cur) { + struct if_branch_ast_node *branch = fx_unbox( + struct if_branch_ast_node, + cur, + n_base.n_entry); + if (!branch->n_cond) { + break; + } + + compile_define_label(ctx, label_ids[i++]); + compile_block_immediate(ctx, branch->n_body); + cur = fx_queue_next(cur); + + if (i < nr_labels - 2) { + compile_ref_label(ctx, label_ids[nr_labels - 1]); + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_BR, + 0); + } + } + + compile_define_label(ctx, label_ids[nr_labels - 1]); + free(label_ids); + + return BSHELL_SUCCESS; +} diff --git a/bshell/compile/label.c b/bshell/compile/label.c new file mode 100644 index 0000000..031403c --- /dev/null +++ b/bshell/compile/label.c @@ -0,0 +1,67 @@ +#include "compile-node.h" + +size_t compile_declare_label(struct compile_ctx *ctx) +{ + size_t id = ctx->c_labels.count; + struct compile_label *label = fx_vector_emplace_back( + ctx->c_labels, + NULL); + return id; +} + +void compile_define_label(struct compile_ctx *ctx, size_t label_id) +{ + size_t offset = 0; + bshell_scriptblock_get_text(ctx->c_block, NULL, &offset); + offset *= sizeof(bshell_instruction); + ctx->c_labels.items[label_id].l_ip = offset; +} + +void compile_ref_label(struct compile_ctx *ctx, size_t label_id) +{ + struct compile_label_ref *ref = malloc(sizeof *ref); + if (!ref) { + return; + } + + memset(ref, 0x0, sizeof *ref); + ref->ref_label_id = label_id; + bshell_scriptblock_get_text(ctx->c_block, NULL, &ref->ref_offset); + ref->ref_offset *= sizeof(bshell_instruction); + fx_queue_push_back(&ctx->c_label_refs, &ref->ref_entry); +} + +enum bshell_status compile_resolve_labels(struct compile_ctx *ctx) +{ + fx_queue_entry *cur = fx_queue_pop_front(&ctx->c_label_refs); + while (cur) { + struct compile_label_ref *ref = fx_unbox( + struct compile_label_ref, + cur, + ref_entry); + struct compile_label *label = &ctx->c_labels.items + [ref->ref_label_id]; + + long long rel_value = (long long)label->l_ip + - (long long)ref->ref_offset; + + enum bshell_opcode op; + uint32_t arg; + bshell_scriptblock_read_instruction( + ctx->c_block, + ref->ref_offset, + &op, + &arg); + arg = (uint32_t)rel_value; + bshell_scriptblock_patch_instruction( + ctx->c_block, + ref->ref_offset, + op, + arg); + + free(ref); + cur = fx_queue_pop_front(&ctx->c_label_refs); + } + + return BSHELL_SUCCESS; +} diff --git a/bshell/compile/normal.c b/bshell/compile/normal.c new file mode 100644 index 0000000..fe21bc9 --- /dev/null +++ b/bshell/compile/normal.c @@ -0,0 +1,24 @@ +#include "compile-node.h" + +static const compile_node_impl node_compilers[] = { + [AST_INT] = compile_int, + [AST_STRING] = compile_string, + [AST_WORD] = compile_word, + [AST_OP] = compile_op, + [AST_VAR] = compile_var, + [AST_FSTRING] = compile_fstring, + [AST_ARRAY] = compile_array, + [AST_HASHTABLE] = compile_hashtable, + [AST_HASHTABLE_ITEM] = compile_hashtable_item, + [AST_CMDCALL] = compile_cmdcall, + [AST_PIPELINE] = compile_pipeline, + [AST_BLOCK] = compile_block, +}; +static const size_t nr_node_compilers = sizeof node_compilers + / sizeof node_compilers[0]; + +const struct compile_state_type normal_state = { + .s_size = sizeof(struct compile_state), + .s_compile_node = node_compilers, + .s_nr_compile_node = nr_node_compilers, +}; diff --git a/bshell/compile/op.c b/bshell/compile/op.c new file mode 100644 index 0000000..0f87eeb --- /dev/null +++ b/bshell/compile/op.c @@ -0,0 +1,121 @@ +#include "../operator.h" +#include "compile-node.h" + +static enum bshell_opcode opcode_for_op(enum operator_id op) +{ + switch (op) { + case OP_ADD: + return OPCODE_ADD; + case OP_SUBTRACT: + return OPCODE_SUB; + case OP_MULTIPLY: + return OPCODE_MUL; + case OP_DIVIDE: + return OPCODE_DIV; + case OP_MODULO: + return OPCODE_MOD; + case OP_INCREMENT: + return OPCODE_INC; + case OP_DECREMENT: + return OPCODE_DEC; + case OP_LEFT_SHIFT: + return OPCODE_SHL; + case OP_RIGHT_SHIFT: + return OPCODE_SHR; + case OP_BINARY_AND: + return OPCODE_BAND; + case OP_BINARY_OR: + return OPCODE_BOR; + case OP_BINARY_XOR: + return OPCODE_BXOR; + case OP_BINARY_NOT: + return OPCODE_BNOT; + case OP_LESS_THAN: + return OPCODE_CMP_LT; + case OP_GREATER_THAN: + return OPCODE_CMP_GT; + case OP_EQUAL: + return OPCODE_CMP_EQ; + case OP_NOT_EQUAL: + return OPCODE_CMP_NE; + case OP_LESS_EQUAL: + return OPCODE_CMP_LE; + case OP_GREATER_EQUAL: + return OPCODE_CMP_GE; + case OP_LOGICAL_AND: + return OPCODE_LAND; + case OP_LOGICAL_OR: + return OPCODE_LOR; + case OP_LOGICAL_XOR: + return OPCODE_LXOR; + case OP_LOGICAL_NOT: + return OPCODE_LNOT; + case OP_RANGE: + return OPCODE_RANGE; + case OP_MATCH: + return OPCODE_MATCH; + case OP_REPLACE: + return OPCODE_REPLACE; + case OP_LIKE: + return OPCODE_LIKE; + case OP_IN: + return OPCODE_IN; + case OP_FORMAT: + return OPCODE_FMT; + case OP_CONTAINS: + return OPCODE_CONTAINS; + case OP_USPLIT: + return OPCODE_SPLIT; + case OP_BSPLIT: + return OPCODE_SPLIT; + case OP_UJOIN: + return OPCODE_JOIN; + case OP_BJOIN: + return OPCODE_JOIN; + case OP_IS: + return OPCODE_IS; + case OP_AS: + return OPCODE_AS; + default: + return OPCODE_NOP; + } +} + +enum bshell_status op_load(struct compile_ctx *ctx, struct compile_value *value) +{ + enum bshell_opcode opcode = opcode_for_op(value->v_op); + if (opcode != OPCODE_NOP) { + compile_value_load(ctx, value->v_right); + compile_value_load(ctx, value->v_left); + bshell_scriptblock_push_instruction( + ctx->c_block, + opcode_for_op(value->v_op), + 0); + return BSHELL_SUCCESS; + } + + switch (value->v_op) { + case OP_ASSIGN: + compile_value_load(ctx, value->v_right); + compile_value_store(ctx, value->v_left); + break; + default: + return BSHELL_ERR_NOT_SUPPORTED; + } + + return BSHELL_SUCCESS; +} + +static const struct compile_value_type op_type = { + .v_load = op_load, +}; + +struct compile_result compile_op(struct compile_ctx *ctx, struct ast_node *src) +{ + struct op_ast_node *op = (struct op_ast_node *)src; + struct compile_value *left = NULL, *right = NULL; + right = compile_pop_value(ctx); + left = compile_pop_value(ctx); + compile_push_op(ctx, &op_type, op->n_op->op_id, left, right); + return COMPILE_OK(0); +} diff --git a/bshell/compile/stack.c b/bshell/compile/stack.c new file mode 100644 index 0000000..9028217 --- /dev/null +++ b/bshell/compile/stack.c @@ -0,0 +1,91 @@ +#include "compile-node.h" + +enum bshell_status compile_push_value( + struct compile_ctx *ctx, + const struct compile_value_type *type, + struct ast_node *node) +{ + struct compile_value *item = malloc(sizeof *item); + if (!item) { + return BSHELL_ERR_NO_MEMORY; + } + + memset(item, 0x0, sizeof *item); + + item->v_type = type; + item->v_node = node; + fx_queue_push_back(&ctx->c_stack, &item->v_entry); + + return BSHELL_SUCCESS; +} + +enum bshell_status compile_push_pool_value( + struct compile_ctx *ctx, + const struct compile_value_type *type, + unsigned long pool_slot) +{ + struct compile_value *item = malloc(sizeof *item); + if (!item) { + return BSHELL_ERR_NO_MEMORY; + } + + memset(item, 0x0, sizeof *item); + + item->v_type = type; + item->v_pool = pool_slot; + fx_queue_push_back(&ctx->c_stack, &item->v_entry); + + return BSHELL_SUCCESS; +} + +enum bshell_status compile_push_op( + struct compile_ctx *ctx, + const struct compile_value_type *type, + enum operator_id op, + struct compile_value *left, + struct compile_value *right) +{ + struct compile_value *item = malloc(sizeof *item); + if (!item) { + return BSHELL_ERR_NO_MEMORY; + } + + memset(item, 0x0, sizeof *item); + + item->v_type = type; + item->v_op = op; + item->v_left = left; + item->v_right = right; + fx_queue_push_back(&ctx->c_stack, &item->v_entry); + + return BSHELL_SUCCESS; +} + +struct compile_value *compile_pop_value(struct compile_ctx *ctx) +{ + fx_queue_entry *entry = fx_queue_pop_back(&ctx->c_stack); + if (!entry) { + return NULL; + } + + return fx_unbox(struct compile_value, entry, v_entry); +} + +void compile_value_load(struct compile_ctx *ctx, struct compile_value *item) +{ + if (item->v_type->v_load) { + item->v_type->v_load(ctx, item); + } +} + +void compile_value_store(struct compile_ctx *ctx, struct compile_value *item) +{ + if (item->v_type->v_store) { + item->v_type->v_store(ctx, item); + } +} + +void compile_value_destroy(struct compile_value *value) +{ + free(value); +} diff --git a/bshell/compile/state.c b/bshell/compile/state.c new file mode 100644 index 0000000..f40d07a --- /dev/null +++ b/bshell/compile/state.c @@ -0,0 +1,66 @@ +#include "compile-node.h" + +extern const struct compile_state_type normal_state; +static const struct compile_state_type *state_types[] = { + [COMPILE_NORMAL] = &normal_state, +}; +static const size_t nr_state_types = sizeof state_types / sizeof state_types[0]; + +struct compile_state *compile_push_state( + struct compile_ctx *ctx, + enum compile_state_type_id state_type_id) +{ + if (state_type_id >= nr_state_types) { + return NULL; + } + + const struct compile_state_type *state_type = state_types + [state_type_id]; + if (!state_type) { + return NULL; + } + + struct compile_state *state = malloc(state_type->s_size); + if (!state) { + return NULL; + } + + state->s_type = state_type; + state->s_depth = ctx->c_depth; + fx_queue_push_back(&ctx->c_state, &state->s_entry); + + if (state_type->s_compile_begin) { + state_type->s_compile_begin(ctx); + } + + return state; +} + +void compile_pop_state(struct compile_ctx *ctx) +{ + struct compile_state *state = compile_get_state(ctx); + if (!state) { + return; + } + + if (!fx_queue_prev(&state->s_entry)) { + return; + } + + if (state->s_type->s_compile_end) { + state->s_type->s_compile_end(ctx); + } + + fx_queue_pop_back(&ctx->c_state); + free(state); +} + +struct compile_state *compile_get_state(const struct compile_ctx *ctx) +{ + fx_queue_entry *entry = fx_queue_last(&ctx->c_state); + if (!entry) { + return NULL; + } + + return fx_unbox(struct compile_state, entry, s_entry); +} diff --git a/bshell/compile/var.c b/bshell/compile/var.c new file mode 100644 index 0000000..97acd66 --- /dev/null +++ b/bshell/compile/var.c @@ -0,0 +1,50 @@ +#include "compile-node.h" + +enum bshell_status var_load( + struct compile_ctx *ctx, + struct compile_value *value) +{ + struct var_ast_node *var = (struct var_ast_node *)value->v_node; + unsigned long index = bshell_scriptblock_get_string( + ctx->c_block, + var->n_ident->tok_str); + if (index == POOL_INDEX_INVALID) { + return BSHELL_ERR_NO_MEMORY; + } + + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_LDLOCAL, + index); + return BSHELL_SUCCESS; +} + +enum bshell_status var_store( + struct compile_ctx *ctx, + struct compile_value *value) +{ + struct var_ast_node *var = (struct var_ast_node *)value->v_node; + unsigned long index = bshell_scriptblock_get_string( + ctx->c_block, + var->n_ident->tok_str); + if (index == POOL_INDEX_INVALID) { + return BSHELL_ERR_NO_MEMORY; + } + + bshell_scriptblock_push_instruction( + ctx->c_block, + OPCODE_STLOCAL, + index); + return BSHELL_SUCCESS; +} + +static const struct compile_value_type var_type = { + .v_load = var_load, + .v_store = var_store, +}; + +struct compile_result compile_var(struct compile_ctx *ctx, struct ast_node *src) +{ + compile_push_value(ctx, &var_type, src); + return COMPILE_OK(0); +}