diff options
Diffstat (limited to 'src/interpreter.c')
-rw-r--r-- | src/interpreter.c | 235 |
1 files changed, 150 insertions, 85 deletions
diff --git a/src/interpreter.c b/src/interpreter.c index 27626a8..af487c6 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -1,138 +1,204 @@ #include "interpreter.h" + #include <stdlib.h> #include <stdio.h> -#include <string.h> +#include <assert.h> + +#include "hashmap.h" + typedef void *YY_BUFFER_STATE; extern FILE *yyin; extern ASTNode *ast_root; extern int yyparse(void); -extern void yyrestart (FILE *); -extern YY_BUFFER_STATE yy_scan_string(const char *); +extern void yyrestart (FILE*); +extern YY_BUFFER_STATE yy_scan_string(const char*); extern void yy_delete_buffer(YY_BUFFER_STATE); +typedef struct Context{ + hashmap_t var_table; + hashmap_t proc_table; +} Context; + + +Context *context_create(void) { + Context *context = malloc(sizeof(Context)); + assert(context); + context->var_table = hashmap_create(); + context->proc_table = hashmap_create(); + return context; +} -void context_set(hashmap_t context, const char *name, int val) { - hashmap_insert(context, name, val); +static void free_procdecl(const char *name, void *procdecl) { + ast_free((ASTNode*)procdecl); } -int context_get(hashmap_t context, const char *name) { - int *val = hashmap_get(context, name); +void context_free(Context *context) { + hashmap_free(context->var_table); + hashmap_iterate(context->proc_table, free_procdecl); + hashmap_free(context->proc_table); + free(context); +} + +int context_get_var(Context *context, const char *name) { + int *val = (int*)hashmap_get(context->var_table, name); if (val) return *val; return 0; } -static void print_var(const char *name, int val) { - printf("%s = %d\n", name, val); +void context_set_var(Context *context, const char *name, int val) { + hashmap_insert(context->var_table, name, (void*)val); } -void context_print(hashmap_t context) { - hashmap_iterate(context, print_var); +static void print_var(const char *name, void *val) { + printf("%s = %d\n", name, (int)val); } -static int eval_aexpr(hashmap_t context, ASTNode *node) { +void context_print_var_table(Context *context) { + hashmap_iterate(context->var_table, print_var); +} + +static ASTNode *context_get_proc(Context *context, const char *name) { + ASTNode **procdecl = (ASTNode**)hashmap_get(context->proc_table, name); + if (procdecl) return *procdecl; + return NULL; +} + +static void context_set_proc(Context *context, const char *name, ASTNode *procdecl) { + hashmap_insert(context->proc_table, name, (void*)procdecl); +} + +static int eval_aexpr(Context *context, ASTNode *node) { switch (node->type) { case NT_INT: return node->u.d_int.val; - case NT_VAR: return context_get(context, node->u.d_var.name); + case NT_VAR: return context_get_var(context, node->u.d_var.name); case NT_AOP: { - int aexp1 = eval_aexpr(context, node->u.d_aop.aexp1); - int aexp2 = eval_aexpr(context, node->u.d_aop.aexp2); + int aexp1_val = eval_aexpr(context, node->u.d_aop.aexp1); + int aexp2_val = eval_aexpr(context, node->u.d_aop.aexp2); switch (node->u.d_aop.aop) { - case AOP_ADD: return aexp1 + aexp2; - case AOP_SUB: return aexp1 - aexp2; - case AOP_MUL: return aexp1 * aexp2; + case AOP_ADD: return aexp1_val + aexp2_val; + case AOP_SUB: return aexp1_val - aexp2_val; + case AOP_MUL: return aexp1_val * aexp2_val; + default: assert(0); } } - default: - fprintf(stderr, "Bad aexpr node %d\n", node->type); - exit(EXIT_FAILURE); + default: assert(0); } } -static int eval_bexpr(hashmap_t context, ASTNode *node) { +static int eval_bexpr(Context *context, ASTNode *node) { switch (node->type) { case NT_BOP: { - int bexp1 = eval_bexpr(context, node->u.d_bop.bexp1); - int bexp2 = eval_bexpr(context, node->u.d_bop.bexp2); + int bexp1_val = eval_bexpr(context, node->u.d_bop.bexp1); + int bexp2_val = eval_bexpr(context, node->u.d_bop.bexp2); switch (node->u.d_bop.bop) { - case BOP_AND: return bexp1 && bexp2; - case BOP_OR: return bexp1 || bexp2; + case BOP_AND: return bexp1_val && bexp2_val; + case BOP_OR: return bexp1_val || bexp2_val; + default: assert(0); } } - case NT_NOT: - return !eval_bexpr(context, node->u.d_not.bexp); + case NT_NOT: return !eval_bexpr(context, node->u.d_not.bexp); case NT_ROP: { - int aexp1 = eval_aexpr(context, node->u.d_rop.aexp1); - int aexp2 = eval_aexpr(context, node->u.d_rop.aexp2); + int aexp1_val = eval_aexpr(context, node->u.d_rop.aexp1); + int aexp2_val = eval_aexpr(context, node->u.d_rop.aexp2); switch (node->u.d_rop.rop) { - case ROP_EQ: return aexp1 == aexp2; - case ROP_NE: return aexp1 != aexp2; - case ROP_LT: return aexp1 < aexp2; - case ROP_LE: return aexp1 <= aexp2; - case ROP_GT: return aexp1 > aexp2; - case ROP_GE: return aexp1 >= aexp2; + case ROP_EQ: return aexp1_val == aexp2_val; + case ROP_NE: return aexp1_val != aexp2_val; + case ROP_LT: return aexp1_val < aexp2_val; + case ROP_LE: return aexp1_val <= aexp2_val; + case ROP_GT: return aexp1_val > aexp2_val; + case ROP_GE: return aexp1_val >= aexp2_val; + default: assert(0); } } - default: - fprintf(stderr, "Bad bexpr node %d\n", node->type); - exit(EXIT_FAILURE); + default: assert(0); } } -void exec_stmt(hashmap_t context, ASTNode *node) { - while (node) { - switch (node->type) { - case NT_SKIP: - return; - case NT_ASSIGN: { - char *name = node->u.d_assign.var->u.d_var.name; - int val = eval_aexpr(context, node->u.d_assign.aexp); - context_set(context, name, val); - return; +void interp_ast(Context *context, ASTNode *node) { + switch (node->type) { + case NT_SKIP: return; + case NT_ASSIGN: { + char *name = node->u.d_assign.var->u.d_var.name; + int val = eval_aexpr(context, node->u.d_assign.aexp); + context_set_var(context, name, val); + return; + } + case NT_SEQ: + interp_ast(context, node->u.d_seq.stm1); + interp_ast(context, node->u.d_seq.stm2); + return; + case NT_IF: + if (eval_bexpr(context, node->u.d_if.bexp)) interp_ast(context, node->u.d_if.stm1); + else interp_ast(context, node->u.d_if.stm2); + return; + case NT_WHILE: + while (eval_bexpr(context, node->u.d_while.bexp)) interp_ast(context, node->u.d_while.stm); + return; + case NT_LET: { + char *name = node->u.d_let.var->u.d_var.name; + int old_val = context_get_var(context, name); + int new_val = eval_aexpr(context, node->u.d_let.aexp); + context_set_var(context, name, new_val); + interp_ast(context, node->u.d_let.stm); + context_set_var(context, name, old_val); + return; + } + case NT_PROCDECL: { + char *name = node->u.d_procdecl.name; + ASTNode *procdecl = ast_clone(node); + ASTNode *procdecl_old = context_get_proc(context, name); + if (procdecl_old) ast_free(procdecl_old); + context_set_proc(context, name, procdecl); + return; + } + case NT_PROCCALL: { + char *name = node->u.d_proccall.name; + ASTNode *procdecl = context_get_proc(context, name); + if (!procdecl) return; + ASTNodeList *caller_args = node->u.d_proccall.args; + ASTNodeList *callee_args = procdecl->u.d_procdecl.args; + Context *proc_context = context_create(); + hashmap_keys_t keys = hashmap_keys_create(context->proc_table); + const char *key; + while ((key = hashmap_keys_next(keys)) != NULL) { + ASTNode *proc = context_get_proc(context, key); + assert(proc); + context_set_proc(proc_context, key, ast_clone(proc)); + } + hashmap_keys_free(keys); + while (caller_args && callee_args) { + char *caller_arg_name = caller_args->node->u.d_var.name; + char *callee_arg_name = callee_args->node->u.d_var.name; + context_set_var(proc_context, callee_arg_name, context_get_var(context, caller_arg_name)); + caller_args = caller_args->next; + callee_args = callee_args->next; } - case NT_SEQ: - exec_stmt(context, node->u.d_seq.stm1); - exec_stmt(context, node->u.d_seq.stm2); - return; - case NT_IF: - if (eval_bexpr(context, node->u.d_if.bexp)) - exec_stmt(context, node->u.d_if.stm1); - else - exec_stmt(context, node->u.d_if.stm2); - return; - case NT_WHILE: - while (eval_bexpr(context, node->u.d_while.bexp)) { - exec_stmt(context, node->u.d_while.stm); - } - return; - case NT_LET: { - char *name = node->u.d_let.var->u.d_var.name; - int old_val = context_get(context, name); - int new_val = eval_aexpr(context, node->u.d_let.aexp); - context_set(context, name, new_val); - exec_stmt(context, node->u.d_let.stm); - context_set(context, name, old_val); - return; + interp_ast(proc_context, procdecl->u.d_procdecl.stm); + ASTNodeList *caller_vargs = node->u.d_proccall.vargs; + ASTNodeList *callee_vargs = procdecl->u.d_procdecl.vargs; + while (caller_vargs && callee_vargs) { + char *caller_varg_name = caller_vargs->node->u.d_var.name; + char *callee_varg_name = callee_vargs->node->u.d_var.name; + context_set_var(context, caller_varg_name, context_get_var(proc_context, callee_varg_name)); + caller_vargs = caller_vargs->next; + callee_vargs = callee_vargs->next; } - default: - fprintf(stderr, "Bad stmt node %d\n", node->type); - exit(EXIT_FAILURE); + context_free(proc_context); + return; } + default: assert(0); } } -int exec_file (hashmap_t context, const char *path) { +int interp_file (Context *context, const char *path) { yyin = fopen(path, "r"); - if (!yyin) { - perror(path); - return -1; - } + if (!yyin) return -1; yyrestart(yyin); if (!yyparse()) { - exec_stmt(context, ast_root); + interp_ast(context, ast_root); ast_free(ast_root); } else { - fprintf(stderr, "Parse error in %s\n", path); fclose(yyin); return -1; } @@ -140,13 +206,12 @@ int exec_file (hashmap_t context, const char *path) { return 0; } -int exec_str (hashmap_t context, const char *str) { +int interp_str (Context *context, const char *str) { YY_BUFFER_STATE buf = yy_scan_string(str); if (!yyparse()) { - exec_stmt(context, ast_root); + interp_ast(context, ast_root); ast_free(ast_root); } else { - fprintf(stderr, "Parse error\n"); yy_delete_buffer(buf); return -1; } |