From 8b6acc85633520f109d348c5e46c8a89521b3932 Mon Sep 17 00:00:00 2001 From: Flavian Kaufmann Date: Wed, 21 May 2025 14:05:27 +0200 Subject: procedures --- example/example.imp | 19 ++-- include/ast.h | 18 +++- include/hash_map.h | 13 --- include/hashmap.h | 23 +++++ include/interpreter.h | 19 ++-- include/repl.h | 2 + src/ast.c | 97 ++++++++++++++++++++- src/driver.c | 13 +-- src/hash_map.c | 126 --------------------------- src/hashmap.c | 169 ++++++++++++++++++++++++++++++++++++ src/interpreter.c | 235 ++++++++++++++++++++++++++++++++------------------ src/lexer.l | 3 + src/parser.y | 33 +++++-- src/repl.c | 28 +++--- 14 files changed, 528 insertions(+), 270 deletions(-) delete mode 100644 include/hash_map.h create mode 100644 include/hashmap.h delete mode 100644 src/hash_map.c create mode 100644 src/hashmap.c diff --git a/example/example.imp b/example/example.imp index b52d2da..a5bc5dd 100644 --- a/example/example.imp +++ b/example/example.imp @@ -1,13 +1,12 @@ -y := 0; - -var x := 5 in - - while x < 10 and true do - x := (x + 1); +procedure factorial(n;r) begin + if n <= 0 then + r := 1; + else + m := n - 1; + factorial(m;r); + r := r * n; end; - - y := x; - end; -z := 5; \ No newline at end of file +n := 5; +factorial(n;r); \ No newline at end of file diff --git a/include/ast.h b/include/ast.h index 8482aab..2d25057 100644 --- a/include/ast.h +++ b/include/ast.h @@ -4,7 +4,8 @@ typedef enum { NT_SKIP, NT_ASSIGN, NT_SEQ, NT_IF, NT_WHILE, - NT_INT, NT_VAR, NT_AOP, NT_BOP, NT_NOT, NT_ROP, NT_LET + NT_INT, NT_VAR, NT_AOP, NT_BOP, NT_NOT, NT_ROP, NT_LET, + NT_PROCDECL, NT_PROCCALL } NodeType; typedef enum { AOP_ADD, AOP_SUB, AOP_MUL } AOp; @@ -25,9 +26,16 @@ typedef struct ASTNode { struct { struct ASTNode *bexp; } d_not; struct { ROp rop; struct ASTNode *aexp1, *aexp2; } d_rop; struct { struct ASTNode *var, *aexp, *stm; } d_let; + struct { char *name; struct ASTNodeList *args, *vargs; struct ASTNode *stm; } d_procdecl; + struct { char *name; struct ASTNodeList *args, *vargs; } d_proccall; } u; } ASTNode; +typedef struct ASTNodeList { + ASTNode *node; + struct ASTNodeList *next; +} ASTNodeList; + ASTNode *ast_skip(void); ASTNode *ast_assign(ASTNode *var, ASTNode *aexp); @@ -41,8 +49,14 @@ ASTNode *ast_bop(BOp bop, ASTNode *bexp1, ASTNode *bexp2); ASTNode *ast_not(ASTNode *bexp); ASTNode *ast_rop(ROp rop, ASTNode *aexp1, ASTNode *aexp2); ASTNode *ast_let(ASTNode *var, ASTNode *aexp, ASTNode *stm); +ASTNode *ast_procdecl(const char *name, ASTNodeList *args, ASTNodeList *vargs, ASTNode *stm); +ASTNode *ast_proccall(const char *name, ASTNodeList *args, ASTNodeList *vargs); + + +ASTNodeList *ast_node_list(ASTNode *node, ASTNodeList *list); +ASTNode *ast_clone(ASTNode *node); void ast_free(ASTNode *node); -#endif +#endif \ No newline at end of file diff --git a/include/hash_map.h b/include/hash_map.h deleted file mode 100644 index 6bc733f..0000000 --- a/include/hash_map.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef HASH_MAP_H -#define HASH_MAP_H - -typedef struct HashMap *hashmap_t; - -hashmap_t hashmap_create(void); -void hashmap_insert(hashmap_t map, const char *key, int value); -int *hashmap_get(hashmap_t map, const char *key); -void hashmap_delete(hashmap_t map, const char *key); -void hashmap_free(hashmap_t map); -void hashmap_iterate(hashmap_t map, void (*callback)(const char *key, int value)); - -#endif \ No newline at end of file diff --git a/include/hashmap.h b/include/hashmap.h new file mode 100644 index 0000000..c62a319 --- /dev/null +++ b/include/hashmap.h @@ -0,0 +1,23 @@ +#ifndef HASHMAP_H +#define HASHMAP_H + + +typedef struct HashMap *hashmap_t; +typedef struct HashMapKeys *hashmap_keys_t; + + +hashmap_t hashmap_create(void); +void hashmap_free(hashmap_t map); + +void **hashmap_get(hashmap_t map, const char *key); +void hashmap_insert(hashmap_t map, const char *key, void *value); +int hashmap_delete(hashmap_t map, const char *key); + +void hashmap_iterate(hashmap_t map, void (*callback)(const char *key, void *value)); +hashmap_keys_t hashmap_keys_create(hashmap_t map); +const char *hashmap_keys_next(hashmap_keys_t iter); +void hashmap_keys_free(hashmap_keys_t iter); + + + +#endif \ No newline at end of file diff --git a/include/interpreter.h b/include/interpreter.h index 6e60113..cb3ba75 100644 --- a/include/interpreter.h +++ b/include/interpreter.h @@ -3,17 +3,22 @@ #include "ast.h" -#include "hash_map.h" -void exec_stmt(hashmap_t context, ASTNode *node); -void context_print(hashmap_t context); +typedef struct Context *context_t; -void context_set(hashmap_t context, const char *name, int value); -int context_get(hashmap_t context, const char *name); -int exec_file (hashmap_t context, const char *path); -int exec_str (hashmap_t context, const char *str); +context_t context_create(void); +void context_free(context_t context); + +int context_get_var(context_t context, const char *name); +void context_set_var(context_t context, const char *name, int value); +void context_print_var_table(context_t context); +void context_print_proc_table(context_t context); + +void interp_ast(context_t context, ASTNode *node); +int interp_file (context_t context, const char *path); +int interp_str (context_t context, const char *str); #endif \ No newline at end of file diff --git a/include/repl.h b/include/repl.h index 804b702..4b833ad 100644 --- a/include/repl.h +++ b/include/repl.h @@ -1,6 +1,8 @@ #ifndef REPL_H #define REPL_H + void repl(void); + #endif \ No newline at end of file diff --git a/src/ast.c b/src/ast.c index 66e76ea..ba8dc9f 100644 --- a/src/ast.c +++ b/src/ast.c @@ -1,5 +1,5 @@ #include "ast.h" -#include + #include #include #include @@ -96,6 +96,39 @@ ASTNode *ast_let(ASTNode *var, ASTNode *aexp, ASTNode *stm) { return node; } +ASTNode *ast_procdecl(const char *name, ASTNodeList *args, ASTNodeList *vargs, ASTNode *stm) { + ASTNode *node = new_node(NT_PROCDECL); + node->u.d_procdecl.name = strdup(name); + assert(node->u.d_procdecl.name); + node->u.d_procdecl.args = args; + node->u.d_procdecl.vargs = vargs; + node->u.d_procdecl.stm = stm; + return node; +} + +ASTNode *ast_proccall(const char *name, ASTNodeList *args, ASTNodeList *vargs) { + ASTNode *node = new_node(NT_PROCCALL); + node->u.d_proccall.name = strdup(name); + assert(node->u.d_proccall.name); + node->u.d_proccall.args = args; + node->u.d_proccall.vargs = vargs; + return node; +} + +ASTNodeList *ast_node_list(ASTNode *node, ASTNodeList *list) { + ASTNodeList *new_list = malloc(sizeof(ASTNodeList)); + assert(new_list); + new_list->node = node; + new_list->next = list; + return new_list; +} + +static void ast_free_node_list(ASTNodeList *list) { + if (!list) return; + ast_free(list->node); + ast_free_node_list(list->next); + free(list); +} void ast_free(ASTNode *node) { if (!node) return; @@ -144,6 +177,68 @@ void ast_free(ASTNode *node) { ast_free(node->u.d_let.aexp); ast_free(node->u.d_let.stm); break; + case NT_PROCDECL: + free(node->u.d_procdecl.name); + ast_free_node_list(node->u.d_procdecl.args); + ast_free_node_list(node->u.d_procdecl.vargs); + ast_free(node->u.d_procdecl.stm); + break; + case NT_PROCCALL: + free(node->u.d_proccall.name); + ast_free_node_list(node->u.d_proccall.args); + ast_free_node_list(node->u.d_proccall.vargs); + break; + default: assert(0); } free(node); +} + +static ASTNodeList *ast_node_list_clone(ASTNodeList *list) { + if (!list) return NULL; + return ast_node_list(ast_clone(list->node), ast_node_list_clone(list->next)); +} + +ASTNode *ast_clone(ASTNode *node) { + if (!node) return NULL; + switch (node->type) { + case NT_SKIP: return ast_skip(); + case NT_ASSIGN: return ast_assign(ast_clone(node->u.d_assign.var), ast_clone(node->u.d_assign.aexp)); + case NT_SEQ: return ast_seq(ast_clone(node->u.d_seq.stm1), ast_clone(node->u.d_seq.stm2)); + case NT_IF: return ast_if( + ast_clone(node->u.d_if.bexp), + ast_clone(node->u.d_if.stm1), + ast_clone(node->u.d_if.stm2)); + case NT_WHILE: return ast_while( + ast_clone(node->u.d_while.bexp), + ast_clone(node->u.d_while.stm)); + case NT_INT: return ast_int(node->u.d_int.val); + case NT_VAR: return ast_var(node->u.d_var.name); + case NT_AOP: return ast_aop( + node->u.d_aop.aop, + ast_clone(node->u.d_aop.aexp1), + ast_clone(node->u.d_aop.aexp2)); + case NT_BOP: return ast_bop( + node->u.d_bop.bop, + ast_clone(node->u.d_bop.bexp1), + ast_clone(node->u.d_bop.bexp2)); + case NT_NOT: return ast_not(ast_clone(node->u.d_not.bexp)); + case NT_ROP: return ast_rop( + node->u.d_rop.rop, + ast_clone(node->u.d_rop.aexp1), + ast_clone(node->u.d_rop.aexp2)); + case NT_LET: return ast_let( + ast_clone(node->u.d_let.var), + ast_clone(node->u.d_let.aexp), + ast_clone(node->u.d_let.stm)); + case NT_PROCDECL: return ast_procdecl( + node->u.d_procdecl.name, + ast_node_list_clone(node->u.d_procdecl.args), + ast_node_list_clone(node->u.d_procdecl.vargs), + ast_clone(node->u.d_procdecl.stm)); + case NT_PROCCALL: return ast_proccall( + node->u.d_proccall.name, + ast_node_list_clone(node->u.d_proccall.args), + ast_node_list_clone(node->u.d_proccall.vargs)); + default: assert(0); + } } \ No newline at end of file diff --git a/src/driver.c b/src/driver.c index fc2a3ae..e3938a6 100644 --- a/src/driver.c +++ b/src/driver.c @@ -2,22 +2,23 @@ #include #include #include + #include "interpreter.h" #include "repl.h" + static void interpret_file(const char *path) { - hashmap_t context = hashmap_create(); - exec_file(context, path); - context_print(context); - hashmap_free(context); + context_t context = context_create(); + interp_file(context, path); + context_print_var_table(context); + context_free(context); } int main(int argc, char **argv) { int opt; - const char *script = NULL; while ((opt = getopt(argc, argv, "i:h")) != -1) { switch (opt){ - case 'i': + case 'i': interpret_file(optarg); return EXIT_SUCCESS; case 'h': diff --git a/src/hash_map.c b/src/hash_map.c deleted file mode 100644 index 5f80205..0000000 --- a/src/hash_map.c +++ /dev/null @@ -1,126 +0,0 @@ -#include "hash_map.h" -#include -#include -#include -#include - -#define INITIAL_SIZE (16) -#define LOAD_FACTOR_THRESHOLD (0.75) - -typedef struct Pair { - char *key; - int value; - struct Pair *next; -} Pair; - -typedef struct HashMap { - Pair **table; - size_t size; - size_t count; -} HashMap; - -static unsigned int hash(const char *key, size_t size) { - unsigned int hash_value = 0; - while (*key) hash_value = (hash_value * 31) + *key++; - return hash_value % size; -} - -static void resize(HashMap *map) { - size_t new_size = map->size * 2; - Pair **new_table = (Pair**)calloc(new_size, sizeof(Pair*)); - assert(new_table); - for (size_t i = 0; i < map->size; ++i) { - Pair *pair = map->table[i]; - while (pair) { - unsigned int index = hash(pair->key, new_size); - Pair *next = pair->next; - pair->next = new_table[index]; - new_table[index] = pair; - pair = next; - } - } - - free(map->table); - map->table = new_table; - map->size = new_size; -} - -HashMap *hashmap_create(void) { - HashMap *map = (HashMap*)malloc(sizeof(HashMap)); - assert(map); - map->size = INITIAL_SIZE; - map->count = 0; - map->table = (Pair**)calloc(map->size, sizeof(Pair*)); - assert(map->table); - return map; -} - -void hashmap_insert(HashMap *map, const char *key, int value) { - int *old_value = hashmap_get(map, key); - if (old_value) { - *old_value = value; - return; - } - if ((float)map->count / map->size > LOAD_FACTOR_THRESHOLD) resize(map); - unsigned int index = hash(key, map->size); - Pair *new_pair = (Pair*)malloc(sizeof(Pair)); - assert(new_pair); - new_pair->key = strdup(key); - assert(new_pair->key); - new_pair->value = value; - new_pair->next = map->table[index]; - map->table[index] = new_pair; - map->count++; -} - -int *hashmap_get(HashMap *map, const char *key) { - unsigned int index = hash(key, map->size); - Pair *pair = map->table[index]; - while (pair) { - if (strcmp(pair->key, key) == 0) return &pair->value; - pair = pair->next; - } - return NULL; -} - -void hashmap_delete(HashMap *map, const char *key) { - unsigned int index = hash(key, map->size); - Pair *pair = map->table[index]; - Pair *prev = NULL; - while (pair) { - if (strcmp(pair->key, key) == 0) { - if (prev) prev->next = pair->next; - else map->table[index] = pair->next; - free(pair->key); - free(pair); - map->count--; - return; - } - prev = pair; - pair = pair->next; - } -} - -void hashmap_free(HashMap *map) { - for (size_t i = 0; i < map->size; ++i) { - Pair *pair = map->table[i]; - while (pair) { - Pair *temp = pair; - pair = pair->next; - free(temp->key); - free(temp); - } - } - free(map->table); - free(map); -} - -void hashmap_iterate(HashMap *map, void (*callback)(const char *key, int value)) { - for (size_t i = 0; i < map->size; ++i) { - Pair *pair = map->table[i]; - while (pair) { - callback(pair->key, pair->value); - pair = pair->next; - } - } -} \ No newline at end of file diff --git a/src/hashmap.c b/src/hashmap.c new file mode 100644 index 0000000..a712134 --- /dev/null +++ b/src/hashmap.c @@ -0,0 +1,169 @@ +#include "hashmap.h" + +#include +#include +#include + + +#define INITIAL_SIZE (16) +#define LOAD_FACTOR_THRESHOLD (0.75) + + +typedef struct Pair { + char *key; + void *value; + struct Pair *next; +} Pair; + +typedef struct HashMap { + Pair **table; + size_t size; + size_t count; +} HashMap; + +typedef struct HashMapKeys { + char **keys; + size_t count; + size_t index; +} HashMapKeys; + + +static unsigned int hash(const char *key, size_t size) { + unsigned int hash_value = 0; + while (*key) hash_value = (hash_value * 31) + *key++; + return hash_value % size; +} + +static void resize(HashMap *map) { + size_t new_size = map->size * 2; + Pair **new_table = (Pair**)calloc(new_size, sizeof(Pair*)); + assert(new_table); + for (size_t i = 0; i < map->size; ++i) { + Pair *pair = map->table[i]; + while (pair) { + unsigned int index = hash(pair->key, new_size); + Pair *next = pair->next; + pair->next = new_table[index]; + new_table[index] = pair; + pair = next; + } + } + + free(map->table); + map->table = new_table; + map->size = new_size; +} + +HashMap *hashmap_create(void) { + HashMap *map = (HashMap*)malloc(sizeof(HashMap)); + assert(map); + map->size = INITIAL_SIZE; + map->count = 0; + map->table = (Pair**)calloc(map->size, sizeof(Pair*)); + assert(map->table); + return map; +} + +void hashmap_insert(HashMap *map, const char *key, void *value) { + void **old_value = hashmap_get(map, key); + if (old_value) { + *old_value = value; + return; + } + if ((float)map->count / map->size > LOAD_FACTOR_THRESHOLD) resize(map); + unsigned int index = hash(key, map->size); + Pair *new_pair = (Pair*)malloc(sizeof(Pair)); + assert(new_pair); + new_pair->key = strdup(key); + assert(new_pair->key); + new_pair->value = value; + new_pair->next = map->table[index]; + map->table[index] = new_pair; + map->count++; +} + +void **hashmap_get(HashMap *map, const char *key) { + unsigned int index = hash(key, map->size); + Pair *pair = map->table[index]; + while (pair) { + if (strcmp(pair->key, key) == 0) return &pair->value; + pair = pair->next; + } + return NULL; +} + +int hashmap_delete(HashMap *map, const char *key) { + unsigned int index = hash(key, map->size); + Pair *pair = map->table[index]; + Pair *prev = NULL; + while (pair) { + if (strcmp(pair->key, key) == 0) { + if (prev) prev->next = pair->next; + else map->table[index] = pair->next; + free(pair->key); + free(pair); + map->count--; + return 0; + } + prev = pair; + pair = pair->next; + } + return -1; +} + +void hashmap_free(HashMap *map) { + for (size_t i = 0; i < map->size; ++i) { + Pair *pair = map->table[i]; + while (pair) { + Pair *temp = pair; + pair = pair->next; + free(temp->key); + free(temp); + } + } + free(map->table); + free(map); +} + +void hashmap_iterate(HashMap *map, void (*callback)(const char *key, void *value)) { + for (size_t i = 0; i < map->size; ++i) { + Pair *pair = map->table[i]; + while (pair) { + callback(pair->key, pair->value); + pair = pair->next; + } + } +} + +HashMapKeys *hashmap_keys_create(HashMap *map) { + HashMapKeys *iter = malloc(sizeof(HashMapKeys)); + assert(iter); + iter->keys = malloc(map->count * sizeof(char*)); + assert(iter->keys); + iter->count = 0; + iter->index = 0; + for (size_t i = 0; i < map->size; ++i) { + Pair *pair = map->table[i]; + while (pair) { + iter->keys[iter->count++] = strdup(pair->key); + pair = pair->next; + } + } + return iter; +} + +const char *hashmap_keys_next(HashMapKeys *iter) { + if (iter->index < iter->count) { + return iter->keys[iter->index++]; + } + return NULL; +} + +void hashmap_keys_free(HashMapKeys *iter) { + if (!iter) return; + for (size_t i = 0; i < iter->count; ++i) { + free(iter->keys[i]); + } + free(iter->keys); + free(iter); +} \ No newline at end of file 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 #include -#include +#include + +#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; } diff --git a/src/lexer.l b/src/lexer.l index b2cbaab..285cbf7 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -19,10 +19,13 @@ WHITESPACE [ \t\r\n]+ "do" { return T_DO; } "var" { return T_VAR; } "in" { return T_IN; } +"procedure" { return T_PROC; } +"begin" { return T_BEGIN; } "(" { return T_LPAREN; } ")" { return T_RPAREN; } ";" { return T_SEM; } +"," { return T_COM; } ":=" { return T_ASSIGN; } "+" { return T_PLUS; } diff --git a/src/parser.y b/src/parser.y index f03e54f..164b3cc 100644 --- a/src/parser.y +++ b/src/parser.y @@ -15,9 +15,10 @@ void yyerror(const char *s) { %union { - int num; - char *id; - struct ASTNode *node; + int num; + char *id; + struct ASTNode *node; + struct ASTNodeList *node_list; } %start prog @@ -32,13 +33,12 @@ void yyerror(const char *s) { %left T_PLUS T_MINUS %left T_STAR %right T_UMINUS -%token T_END T_IF T_THEN T_ELSE T_WHILE T_DO T_VAR T_IN -%token T_SKIP +%token T_SKIP T_END T_IF T_THEN T_ELSE T_WHILE T_DO T_VAR T_IN T_PROC T_BEGIN %token T_ASSIGN -%token T_LPAREN T_RPAREN -%token T_SEM +%token T_LPAREN T_RPAREN T_COM T_SEM -%type prog stm var aexp bexp +%type prog stm var aexp bexp procd procc +%type args %% @@ -64,6 +64,10 @@ stm : T_SKIP { $$ = ast_while($2, $4); } | T_VAR var T_ASSIGN aexp T_IN stm T_END { $$ = ast_let($2, $4, $6); } + | procd + { $$ = $1; } + | procc + { $$ = $1; } ; var : T_ID @@ -112,4 +116,17 @@ bexp : bexp T_OR bexp { $$ = ast_rop(ROP_EQ, ast_int(0), ast_int(1)); } ; +args : var + { $$ = ast_node_list($1, NULL); } + | args T_COM var + { $$ = ast_node_list($3, $1); } + ; + +procd : T_PROC T_ID T_LPAREN args T_SEM args T_RPAREN T_BEGIN stm T_END + { $$ = ast_procdecl($2, $4, $6, $9); } + ; + +procc : T_ID T_LPAREN args T_SEM args T_RPAREN + { $$ = ast_proccall($1, $3, $5); } + ; %% diff --git a/src/repl.c b/src/repl.c index 5ea9792..f6387a2 100644 --- a/src/repl.c +++ b/src/repl.c @@ -1,11 +1,15 @@ #include "repl.h" -#include "interpreter.h" -#include -#include + #include #include #include +#include +#include + +#include "interpreter.h" + + static void print_help(void) { printf( "IMP REPL (type IMP statements or commands starting with '%%')\n" @@ -17,7 +21,7 @@ static void print_help(void) { " %%help show this message\n"); } -static void repl_exec_command(hashmap_t context, const char *command) { +static void repl_exec_command(context_t context, char *command) { char *cmd = strtok(command, " \t"); if (strcmp(cmd, "%quit") == 0) { exit(EXIT_SUCCESS); @@ -26,30 +30,30 @@ static void repl_exec_command(hashmap_t context, const char *command) { } else if (strcmp(cmd, "%run") == 0) { char *file = strtok(NULL, " \t"); if (file) { - if (!exec_file(context, file)) context_print(context); + if (!interp_file(context, file)) context_print_var_table(context); } else { fprintf(stderr, "Usage: %%run \n"); } } else if (strcmp(cmd, "%set") == 0) { char *var = strtok(NULL, " \t"); char *val = strtok(NULL, " \t"); - if (var && val) context_set(context, var, atoi(val)); + if (var && val) context_set_var(context, var, atoi(val)); else fprintf(stderr, "Usage: %%set \n"); } else if (strcmp(cmd, "%print") == 0) { char *var = strtok(NULL, " \t"); - if (var) printf("%s = %d\n", var, context_get(context, var)); - else context_print(context); + if (var) printf("%s = %d\n", var, context_get_var(context, var)); + else context_print_var_table(context); } else { fprintf(stderr, "Unknown command: %s\n", cmd); } } -static void repl_exec_statement(hashmap_t context, const char *statement) { - if (!exec_str(context, statement)) context_print(context); +static void repl_exec_statement(context_t context, const char *statement) { + if (!interp_str(context, statement)) context_print_var_table(context); } void repl(void) { - hashmap_t context = hashmap_create(); + context_t context = context_create(); char *line; print_help(); @@ -61,5 +65,5 @@ void repl(void) { } printf("\n"); - hashmap_free(context); + context_free(context); } \ No newline at end of file -- cgit v1.2.3