aboutsummaryrefslogtreecommitdiff
path: root/src/interpreter.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interpreter.c')
-rw-r--r--src/interpreter.c235
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;
}