#include "interpreter.h" #include #include #include 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 yy_delete_buffer(YY_BUFFER_STATE); void context_set(hashmap_t context, const char *name, int val) { hashmap_insert(context, name, val); } int context_get(hashmap_t context, const char *name) { int *val = hashmap_get(context, name); if (val) return *val; return 0; } static void print_var(const char *name, int val) { printf("%s = %d\n", name, val); } void context_print(hashmap_t context) { hashmap_iterate(context, print_var); } static int eval_aexpr(hashmap_t 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_AOP: { int aexp1 = eval_aexpr(context, node->u.d_aop.aexp1); int aexp2 = 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; } } default: fprintf(stderr, "Bad aexpr node %d\n", node->type); exit(EXIT_FAILURE); } } static int eval_bexpr(hashmap_t 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); switch (node->u.d_bop.bop) { case BOP_AND: return bexp1 && bexp2; case BOP_OR: return bexp1 || bexp2; } } 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); 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; } } default: fprintf(stderr, "Bad bexpr node %d\n", node->type); exit(EXIT_FAILURE); } } 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; } 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; } default: fprintf(stderr, "Bad stmt node %d\n", node->type); exit(EXIT_FAILURE); } } } int exec_file (hashmap_t context, const char *path) { yyin = fopen(path, "r"); if (!yyin) { perror(path); return -1; } yyrestart(yyin); if (!yyparse()) { exec_stmt(context, ast_root); ast_free(ast_root); } else { fprintf(stderr, "Parse error in %s\n", path); fclose(yyin); return -1; } fclose(yyin); return 0; } int exec_str (hashmap_t context, const char *str) { YY_BUFFER_STATE buf = yy_scan_string(str); if (!yyparse()) { exec_stmt(context, ast_root); ast_free(ast_root); } else { fprintf(stderr, "Parse error\n"); yy_delete_buffer(buf); return -1; } yy_delete_buffer(buf); return 0; }