diff options
author | Flavian Kaufmann <flavian@flaviankaufmann.ch> | 2025-05-25 15:54:50 +0200 |
---|---|---|
committer | Flavian Kaufmann <flavian@flaviankaufmann.ch> | 2025-05-25 15:54:50 +0200 |
commit | 330e46236b421ffb8fe263caf91196f4cd1114c5 (patch) | |
tree | 09b3df77fca2d23dacef64f6962e9a1afd5b4d29 /src | |
parent | de59dbd1773dff06051b7b604977bcb2803ada4f (diff) | |
download | imp-330e46236b421ffb8fe263caf91196f4cd1114c5.tar.gz imp-330e46236b421ffb8fe263caf91196f4cd1114c5.zip |
[cleanup] codebase cleanup
Diffstat (limited to 'src')
-rw-r--r-- | src/ast.c | 56 | ||||
-rw-r--r-- | src/driver.c | 260 | ||||
-rw-r--r-- | src/hashmap.c | 160 | ||||
-rw-r--r-- | src/interpreter.c | 421 | ||||
-rw-r--r-- | src/interpreter_context.c | 123 | ||||
-rw-r--r-- | src/main.c | 45 | ||||
-rw-r--r-- | src/repl.c | 28 |
7 files changed, 505 insertions, 588 deletions
@@ -170,27 +170,27 @@ IMP_ASTNode *imp_ast_clone(const IMP_ASTNode *node) { } } -void imp_ast_free(IMP_ASTNode *node) { +void imp_ast_destroy(IMP_ASTNode *node) { if (!node) return; switch (node->type) { case IMP_AST_NT_SKIP: break; case IMP_AST_NT_ASSIGN: - imp_ast_free(node->data.assign.var); - imp_ast_free(node->data.assign.aexpr); + imp_ast_destroy(node->data.assign.var); + imp_ast_destroy(node->data.assign.aexpr); break; case IMP_AST_NT_SEQ: - imp_ast_free(node->data.seq.fst_stmt); - imp_ast_free(node->data.seq.snd_stmt); + imp_ast_destroy(node->data.seq.fst_stmt); + imp_ast_destroy(node->data.seq.snd_stmt); break; case IMP_AST_NT_IF: - imp_ast_free(node->data.if_stmt.cond_bexpr); - imp_ast_free(node->data.if_stmt.then_stmt); - imp_ast_free(node->data.if_stmt.else_stmt); + imp_ast_destroy(node->data.if_stmt.cond_bexpr); + imp_ast_destroy(node->data.if_stmt.then_stmt); + imp_ast_destroy(node->data.if_stmt.else_stmt); break; case IMP_AST_NT_WHILE: - imp_ast_free(node->data.while_stmt.cond_bexpr); - imp_ast_free(node->data.while_stmt.body_stmt); + imp_ast_destroy(node->data.while_stmt.cond_bexpr); + imp_ast_destroy(node->data.while_stmt.body_stmt); break; case IMP_AST_NT_INT: break; @@ -198,35 +198,35 @@ void imp_ast_free(IMP_ASTNode *node) { free(node->data.variable.name); break; case IMP_AST_NT_AOP: - imp_ast_free(node->data.arith_op.l_aexpr); - imp_ast_free(node->data.arith_op.r_aexpr); + imp_ast_destroy(node->data.arith_op.l_aexpr); + imp_ast_destroy(node->data.arith_op.r_aexpr); break; case IMP_AST_NT_BOP: - imp_ast_free(node->data.bool_op.l_bexpr); - imp_ast_free(node->data.bool_op.r_bexpr); + imp_ast_destroy(node->data.bool_op.l_bexpr); + imp_ast_destroy(node->data.bool_op.r_bexpr); break; case IMP_AST_NT_ROP: - imp_ast_free(node->data.rel_op.l_aexpr); - imp_ast_free(node->data.rel_op.r_aexpr); + imp_ast_destroy(node->data.rel_op.l_aexpr); + imp_ast_destroy(node->data.rel_op.r_aexpr); break; case IMP_AST_NT_NOT: - imp_ast_free(node->data.bool_not.bexpr); + imp_ast_destroy(node->data.bool_not.bexpr); break; case IMP_AST_NT_LET: - imp_ast_free(node->data.let_stmt.var); - imp_ast_free(node->data.let_stmt.aexpr); - imp_ast_free(node->data.let_stmt.body_stmt); + imp_ast_destroy(node->data.let_stmt.var); + imp_ast_destroy(node->data.let_stmt.aexpr); + imp_ast_destroy(node->data.let_stmt.body_stmt); break; case IMP_AST_NT_PROCDECL: free(node->data.proc_decl.name); - imp_ast_list_free(node->data.proc_decl.val_args); - imp_ast_list_free(node->data.proc_decl.var_args); - imp_ast_free(node->data.proc_decl.body_stmt); + imp_ast_list_destroy(node->data.proc_decl.val_args); + imp_ast_list_destroy(node->data.proc_decl.var_args); + imp_ast_destroy(node->data.proc_decl.body_stmt); break; case IMP_AST_NT_PROCCALL: free(node->data.proc_call.name); - imp_ast_list_free(node->data.proc_call.val_args); - imp_ast_list_free(node->data.proc_call.var_args); + imp_ast_list_destroy(node->data.proc_call.val_args); + imp_ast_list_destroy(node->data.proc_call.var_args); break; default: assert(0 && "Unknown AST node type"); } @@ -241,9 +241,9 @@ IMP_ASTNodeList *imp_ast_list(IMP_ASTNode *node, IMP_ASTNodeList *list) { return new_list; } -void imp_ast_list_free(IMP_ASTNodeList *list) { +void imp_ast_list_destroy(IMP_ASTNodeList *list) { if (!list) return; - imp_ast_free(list->node); - imp_ast_list_free(list->next); + imp_ast_destroy(list->node); + imp_ast_list_destroy(list->next); free(list); }
\ No newline at end of file diff --git a/src/driver.c b/src/driver.c index 441ee40..5f6037d 100644 --- a/src/driver.c +++ b/src/driver.c @@ -1,44 +1,238 @@ -#include <stdio.h> +#include "driver.h" + #include <stdlib.h> -#include <string.h> -#include <unistd.h> +#include <stdio.h> +#include <assert.h> +#include "ast.h" #include "interpreter.h" -#include "repl.h" -static int interpret_file(const char *path) { - context_t context = context_create(); - if (interp_file(context, path)) { - fprintf(stderr, "Error interpreting file: %s\n", path); - context_free(context); +typedef void *YY_BUFFER_STATE; +extern FILE *yyin; +extern IMP_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); + +int imp_driver_interpret_file (IMP_InterpreterContext *context, const char *path) { + yyin = fopen(path, "r"); + if (!yyin) return -1; + yyrestart(yyin); + if (yyparse()) { + imp_ast_destroy(ast_root); + fclose(yyin); + return -1; + } + if (imp_interpreter_interpret_ast(context, ast_root)) { + imp_ast_destroy(ast_root); + fclose(yyin); return -1; } - context_print_var_table(context); - context_free(context); + imp_ast_destroy(ast_root); + fclose(yyin); return 0; } -int main(int argc, char **argv) { - int opt; - while ((opt = getopt(argc, argv, "i:a:h")) != -1) { - switch (opt) { - case 'i': - return interpret_file(optarg) ? EXIT_FAILURE : EXIT_SUCCESS; - case 'a': - return print_ast_file(optarg) ? EXIT_FAILURE : EXIT_SUCCESS; - case 'h': - default: - fprintf(stderr, - "Usage: %s [ARGS]\n" - " (no args) start REPL\n" - " -i <program.imp> interpret program\n" - " -a <program.imp> print ast\n" - " -h print this message\n", - argv[0]); - return (opt == 'h') ? EXIT_SUCCESS : EXIT_FAILURE; - } - } - repl(); - return EXIT_SUCCESS; +int imp_driver_interpret_str (IMP_InterpreterContext *context, const char *str) { + YY_BUFFER_STATE buf = yy_scan_string(str); + if (yyparse()) { + imp_ast_destroy(ast_root); + yy_delete_buffer(buf); + return -1; + } + if (imp_interpreter_interpret_ast(context, ast_root)) { + imp_ast_destroy(ast_root); + yy_delete_buffer(buf); + return -1; + } + yy_delete_buffer(buf); + return 0; +} + +static void ast_print (IMP_ASTNode *node, int depth) { + int indent = depth * 2; + switch (node->type) { + case IMP_AST_NT_SKIP: { + printf("%*sSKIP\n", indent, ""); + break; + } + case IMP_AST_NT_ASSIGN: { + printf("%*sASSIGN %s=", indent, "", + node->data.assign.var->data.variable.name); + ast_print(node->data.assign.aexpr, 0); + printf("\n"); + break; + } + case IMP_AST_NT_SEQ: { + ast_print(node->data.seq.fst_stmt, depth); + printf("%*sSEQ\n", indent, ""); + ast_print(node->data.seq.snd_stmt, depth); + break; + } + case IMP_AST_NT_IF: { + printf("%*sIF (", indent, ""); + ast_print(node->data.if_stmt.cond_bexpr, 0); + printf(")\n"); + ast_print(node->data.if_stmt.then_stmt, depth + 1); + printf("%*sELSE\n", indent, ""); + ast_print(node->data.if_stmt.else_stmt, depth + 1); + break; + } + case IMP_AST_NT_WHILE: { + printf("%*sWHILE (", indent, ""); + ast_print(node->data.while_stmt.cond_bexpr, 0); + printf(")\n"); + ast_print(node->data.while_stmt.body_stmt, depth + 1); + break; + } + case IMP_AST_NT_INT: { + printf("%d", node->data.integer.val); + break; + } + case IMP_AST_NT_VAR: { + printf("%s", node->data.variable.name); + break; + } + case IMP_AST_NT_AOP: { + printf("("); + ast_print(node->data.arith_op.l_aexpr, 0); + switch (node->data.arith_op.aopr) { + case IMP_AST_AOP_ADD: printf(" + "); break; + case IMP_AST_AOP_SUB: printf(" - "); break; + case IMP_AST_AOP_MUL: printf(" * "); break; + default: assert(0); + } + ast_print(node->data.arith_op.r_aexpr, 0); + printf(")"); + break; + } + case IMP_AST_NT_BOP: { + printf("("); + ast_print(node->data.bool_op.l_bexpr, 0); + switch (node->data.bool_op.bopr) { + case IMP_AST_BOP_AND: printf(" && "); break; + case IMP_AST_BOP_OR: printf(" || "); break; + default: assert(0); + } + ast_print(node->data.bool_op.r_bexpr, 0); + printf(")"); + break; + } + case IMP_AST_NT_NOT: { + printf("!"); + ast_print(node->data.bool_not.bexpr, 0); + break; + } + case IMP_AST_NT_ROP: { + printf("("); + ast_print(node->data.rel_op.l_aexpr, 0); + switch (node->data.rel_op.ropr) { + case IMP_AST_ROP_EQ: printf(" == "); break; + case IMP_AST_ROP_NE: printf(" != "); break; + case IMP_AST_ROP_LT: printf(" < "); break; + case IMP_AST_ROP_LE: printf(" <= "); break; + case IMP_AST_ROP_GT: printf(" > "); break; + case IMP_AST_ROP_GE: printf(" >= "); break; + default: assert(0); + } + ast_print(node->data.rel_op.r_aexpr, 0); + printf(")"); + break; + } + case IMP_AST_NT_LET: { + printf("%*sLET %s = ", indent, "", node->data.let_stmt.var->data.variable.name); + ast_print(node->data.let_stmt.aexpr, 0); + printf("\n"); + ast_print(node->data.let_stmt.body_stmt, depth + 1); + break; + } + case IMP_AST_NT_PROCDECL: { + printf("%*sPROC %s(", indent, "", node->data.proc_decl.name); + IMP_ASTNodeList *args = node->data.proc_decl.val_args; + while (args) { + printf("%s", args->node->data.variable.name); + args = args->next; + if (args) printf(", "); + } + printf("; "); + IMP_ASTNodeList *vargs = node->data.proc_decl.var_args; + while (vargs) { + printf("%s", vargs->node->data.variable.name); + vargs = vargs->next; + if (vargs) printf(", "); + } + printf(")\n"); + ast_print(node->data.proc_decl.body_stmt, depth + 1); + break; + } + case IMP_AST_NT_PROCCALL: { + printf("%*sCALL %s(", indent, "", node->data.proc_call.name); + IMP_ASTNodeList *args = node->data.proc_call.val_args; + while (args) { + printf("%s", args->node->data.variable.name); + args = args->next; + if (args) printf(", "); + } + printf("; "); + IMP_ASTNodeList *vargs = node->data.proc_call.var_args; + while (vargs) { + printf("%s", vargs->node->data.variable.name); + vargs = vargs->next; + if (vargs) printf(", "); + } + printf(")\n"); + break; + } + default: assert(0); + } +} + +int imp_driver_print_ast_file (const char *path) { + yyin = fopen(path, "r"); + if (!yyin) return -1; + yyrestart(yyin); + if (yyparse()) { + imp_ast_destroy(ast_root); + fclose(yyin); + return -1; + } + ast_print(ast_root, 0); + imp_ast_destroy(ast_root); + fclose(yyin); + return 0; +} + +void imp_driver_print_var_table(IMP_InterpreterContext *context) { + IMP_InterpreterContextVarIter *iter = imp_interpreter_context_var_iter_create(context); + const IMP_InterpreterContextVarTableEntry *var_entry; + while ((var_entry = imp_interpreter_context_var_iter_next(iter))) { + printf("%s = %d\n", var_entry->key, var_entry->value); + } + imp_interpreter_context_var_iter_destroy(iter); +} + +void imp_driver_print_proc_table(IMP_InterpreterContext *context) { + IMP_InterpreterContextProcIter *iter = imp_interpreter_context_proc_iter_create(context); + const IMP_InterpreterContextProcTableEntry *proc_entry; + while ((proc_entry = imp_interpreter_context_proc_iter_next(iter))) { + const IMP_ASTNode *procdecl = proc_entry->value; + printf("%s(", proc_entry->key); + IMP_ASTNodeList *args = procdecl->data.proc_decl.val_args; + while (args) { + printf("%s", args->node->data.variable.name); + args = args->next; + if (args) printf(", "); + } + printf("; "); + IMP_ASTNodeList *vargs = procdecl->data.proc_decl.var_args; + while (vargs) { + printf("%s", vargs->node->data.variable.name); + vargs = vargs->next; + if (vargs) printf(", "); + } + printf(")\n"); + } + imp_interpreter_context_proc_iter_destroy(iter); }
\ No newline at end of file diff --git a/src/hashmap.c b/src/hashmap.c deleted file mode 100644 index 89d0106..0000000 --- a/src/hashmap.c +++ /dev/null @@ -1,160 +0,0 @@ -#include "hashmap.h" - -#include <stdlib.h> -#include <string.h> -#include <assert.h> - - -#define INITIAL_SIZE (16) -#define LOAD_FACTOR_THRESHOLD (0.75) - - -typedef struct Pair { - char *key; - void *element; - struct Pair *next; -} Pair; - -typedef struct HashMap { - Pair **table; - size_t size; - size_t count; -} HashMap; - -typedef struct HashMapKeysIter { - HashMap *map; - size_t bucket_index; - Pair *current; -} HashMapKeysIter; - - -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 *element) { - void **old_value = hashmap_get(map, key); - if (old_value) { - *old_value = element; - 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->element = element; - 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->element; - 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); -} - -HashMapKeysIter *hashmap_keys_iter_create(HashMap *map) { - HashMapKeysIter *iter = (HashMapKeysIter*)malloc(sizeof(HashMapKeysIter)); - assert(iter); - iter->map = map; - iter->bucket_index = 0; - iter->current = NULL; - while (iter->bucket_index < map->size && map->table[iter->bucket_index] == NULL) { - iter->bucket_index++; - } - if (iter->bucket_index < map->size) { - iter->current = map->table[iter->bucket_index]; - } - return iter; -} - -const char *hashmap_keys_iter_next(HashMapKeysIter *iter) { - if (!iter->current) return NULL; - const char *key = iter->current->key; - if (iter->current->next) { - iter->current = iter->current->next; - } else { - iter->bucket_index++; - while (iter->bucket_index < iter->map->size && iter->map->table[iter->bucket_index] == NULL) { - iter->bucket_index++; - } - iter->current = (iter->bucket_index < iter->map->size) ? iter->map->table[iter->bucket_index] : NULL; - } - return key; -} - -void hashmap_keys_iter_free(HashMapKeysIter *iter) { - free(iter); -}
\ No newline at end of file diff --git a/src/interpreter.c b/src/interpreter.c index c0678b7..b04a293 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -4,248 +4,18 @@ #include <stdio.h> #include <assert.h> -#include "hashmap.h" - -typedef void *YY_BUFFER_STATE; -extern FILE *yyin; -extern IMP_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); - -typedef struct Context{ - hashmap_t var_table; - hashmap_t proc_table; -} Context; - - -static IMP_ASTNode *context_get_proc(Context *context, const char *name) { - IMP_ASTNode **procdecl = (IMP_ASTNode**)hashmap_get(context->proc_table, name); - if (procdecl) return *procdecl; - return NULL; -} - -static void context_set_proc(Context *context, const char *name, IMP_ASTNode *procdecl) { - hashmap_insert(context->proc_table, name, (void*)procdecl); -} - -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_free(Context *context) { - hashmap_free(context->var_table); - hashmap_keys_iter_t iter = hashmap_keys_iter_create(context->proc_table); - const char *key; - while ((key = hashmap_keys_iter_next(iter)) != NULL) { - IMP_ASTNode *procdecl = context_get_proc(context, key); - assert(procdecl); - imp_ast_free(procdecl); - } - hashmap_keys_iter_free(iter); - 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; -} - -void context_set_var(Context *context, const char *name, int val) { - hashmap_insert(context->var_table, name, (void*)val); -} - -void context_print_var_table(Context *context) { - hashmap_keys_iter_t iter = hashmap_keys_iter_create(context->var_table); - const char *key; - while ((key = hashmap_keys_iter_next(iter)) != NULL) { - int val = context_get_var(context, key); - printf("%s = %d\n", key, val); - } - hashmap_keys_iter_free(iter); -} - -void context_print_proc_table(Context *context) { - hashmap_keys_iter_t iter = hashmap_keys_iter_create(context->proc_table); - const char *key; - while ((key = hashmap_keys_iter_next(iter)) != NULL) { - IMP_ASTNode *procdecl = context_get_proc(context, key); - printf("%s(", key); - IMP_ASTNodeList *args = procdecl->data.proc_decl.val_args; - while (args) { - printf("%s", args->node->data.variable.name); - args = args->next; - if (args) printf(", "); - } - printf("; "); - IMP_ASTNodeList *vargs = procdecl->data.proc_decl.var_args; - while (vargs) { - printf("%s", vargs->node->data.variable.name); - vargs = vargs->next; - if (vargs) printf(", "); - } - printf(")\n"); - } - hashmap_keys_iter_free(iter); -} - -void ast_print(IMP_ASTNode *node, int depth) { - int indent = depth * 2; - switch (node->type) { - case IMP_AST_NT_SKIP: { - printf("%*sSKIP\n", indent, ""); - break; - } - case IMP_AST_NT_ASSIGN: { - printf("%*sASSIGN %s=", indent, "", - node->data.assign.var->data.variable.name); - ast_print(node->data.assign.aexpr, 0); - printf("\n"); - break; - } - case IMP_AST_NT_SEQ: { - ast_print(node->data.seq.fst_stmt, depth); - printf("%*sSEQ\n", indent, ""); - ast_print(node->data.seq.snd_stmt, depth); - break; - } - case IMP_AST_NT_IF: { - printf("%*sIF (", indent, ""); - ast_print(node->data.if_stmt.cond_bexpr, 0); - printf(")\n"); - ast_print(node->data.if_stmt.then_stmt, depth + 1); - printf("%*sELSE\n", indent, ""); - ast_print(node->data.if_stmt.else_stmt, depth + 1); - break; - } - case IMP_AST_NT_WHILE: { - printf("%*sWHILE (", indent, ""); - ast_print(node->data.while_stmt.cond_bexpr, 0); - printf(")\n"); - ast_print(node->data.while_stmt.body_stmt, depth + 1); - break; - } - case IMP_AST_NT_INT: { - printf("%d", node->data.integer.val); - break; - } - case IMP_AST_NT_VAR: { - printf("%s", node->data.variable.name); - break; - } - case IMP_AST_NT_AOP: { - printf("("); - ast_print(node->data.arith_op.l_aexpr, 0); - switch (node->data.arith_op.aopr) { - case IMP_AST_AOP_ADD: printf(" + "); break; - case IMP_AST_AOP_SUB: printf(" - "); break; - case IMP_AST_AOP_MUL: printf(" * "); break; - default: assert(0); - } - ast_print(node->data.arith_op.r_aexpr, 0); - printf(")"); - break; - } - case IMP_AST_NT_BOP: { - printf("("); - ast_print(node->data.bool_op.l_bexpr, 0); - switch (node->data.bool_op.bopr) { - case IMP_AST_BOP_AND: printf(" && "); break; - case IMP_AST_BOP_OR: printf(" || "); break; - default: assert(0); - } - ast_print(node->data.bool_op.r_bexpr, 0); - printf(")"); - break; - } - case IMP_AST_NT_NOT: { - printf("!"); - ast_print(node->data.bool_not.bexpr, 0); - break; - } - case IMP_AST_NT_ROP: { - printf("("); - ast_print(node->data.rel_op.l_aexpr, 0); - switch (node->data.rel_op.ropr) { - case IMP_AST_ROP_EQ: printf(" == "); break; - case IMP_AST_ROP_NE: printf(" != "); break; - case IMP_AST_ROP_LT: printf(" < "); break; - case IMP_AST_ROP_LE: printf(" <= "); break; - case IMP_AST_ROP_GT: printf(" > "); break; - case IMP_AST_ROP_GE: printf(" >= "); break; - default: assert(0); - } - ast_print(node->data.rel_op.r_aexpr, 0); - printf(")"); - break; - } - case IMP_AST_NT_LET: { - printf("%*sLET %s = ", indent, "", node->data.let_stmt.var->data.variable.name); - ast_print(node->data.let_stmt.aexpr, 0); - printf("\n"); - ast_print(node->data.let_stmt.body_stmt, depth + 1); - break; - } - case IMP_AST_NT_PROCDECL: { - printf("%*sPROC %s(", indent, "", node->data.proc_decl.name); - IMP_ASTNodeList *args = node->data.proc_decl.val_args; - while (args) { - printf("%s", args->node->data.variable.name); - args = args->next; - if (args) printf(", "); - } - printf("; "); - IMP_ASTNodeList *vargs = node->data.proc_decl.var_args; - while (vargs) { - printf("%s", vargs->node->data.variable.name); - vargs = vargs->next; - if (vargs) printf(", "); - } - printf(")\n"); - ast_print(node->data.proc_decl.body_stmt, depth + 1); - break; - } - case IMP_AST_NT_PROCCALL: { - printf("%*sCALL %s(", indent, "", node->data.proc_call.name); - IMP_ASTNodeList *args = node->data.proc_call.val_args; - while (args) { - printf("%s", args->node->data.variable.name); - args = args->next; - if (args) printf(", "); - } - printf("; "); - IMP_ASTNodeList *vargs = node->data.proc_call.var_args; - while (vargs) { - printf("%s", vargs->node->data.variable.name); - vargs = vargs->next; - if (vargs) printf(", "); - } - printf(")\n"); - break; - } - default: assert(0); - } -} - -static int eval_aexpr(Context *context, IMP_ASTNode *node) { +static int eval_aexpr(IMP_InterpreterContext *context, const IMP_ASTNode *node) { switch (node->type) { case IMP_AST_NT_INT: return node->data.integer.val; - case IMP_AST_NT_VAR: return context_get_var(context, node->data.variable.name); + case IMP_AST_NT_VAR: return imp_interpreter_context_var_get(context, node->data.variable.name); case IMP_AST_NT_AOP: { - int aexp1_val = eval_aexpr(context, node->data.arith_op.l_aexpr); - int aexp2_val = eval_aexpr(context, node->data.arith_op.r_aexpr); + int l_val = eval_aexpr(context, node->data.arith_op.l_aexpr); + int r_val = eval_aexpr(context, node->data.arith_op.r_aexpr); switch (node->data.arith_op.aopr) { - case IMP_AST_AOP_ADD: return aexp1_val + aexp2_val; - case IMP_AST_AOP_SUB: return aexp1_val - aexp2_val; - case IMP_AST_AOP_MUL: return aexp1_val * aexp2_val; + case IMP_AST_AOP_ADD: return l_val + r_val; + case IMP_AST_AOP_SUB: return l_val - r_val; + case IMP_AST_AOP_MUL: return l_val * r_val; default: assert(0); } } @@ -253,28 +23,28 @@ static int eval_aexpr(Context *context, IMP_ASTNode *node) { } } -static int eval_bexpr(Context *context, IMP_ASTNode *node) { +static int eval_bexpr(IMP_InterpreterContext *context, const IMP_ASTNode *node) { switch (node->type) { case IMP_AST_NT_BOP: { - int bexp1_val = eval_bexpr(context, node->data.bool_op.l_bexpr); - int bexp2_val = eval_bexpr(context, node->data.bool_op.r_bexpr); + int l_val = eval_bexpr(context, node->data.bool_op.l_bexpr); + int r_val = eval_bexpr(context, node->data.bool_op.r_bexpr); switch (node->data.bool_op.bopr) { - case IMP_AST_BOP_AND: return bexp1_val && bexp2_val; - case IMP_AST_BOP_OR: return bexp1_val || bexp2_val; + case IMP_AST_BOP_AND: return l_val && r_val; + case IMP_AST_BOP_OR: return l_val || r_val; default: assert(0); } } case IMP_AST_NT_NOT: return !eval_bexpr(context, node->data.bool_not.bexpr); case IMP_AST_NT_ROP: { - int aexp1_val = eval_aexpr(context, node->data.rel_op.l_aexpr); - int aexp2_val = eval_aexpr(context, node->data.rel_op.r_aexpr); + int l_val = eval_aexpr(context, node->data.rel_op.l_aexpr); + int r_val = eval_aexpr(context, node->data.rel_op.r_aexpr); switch (node->data.rel_op.ropr) { - case IMP_AST_ROP_EQ: return aexp1_val == aexp2_val; - case IMP_AST_ROP_NE: return aexp1_val != aexp2_val; - case IMP_AST_ROP_LT: return aexp1_val < aexp2_val; - case IMP_AST_ROP_LE: return aexp1_val <= aexp2_val; - case IMP_AST_ROP_GT: return aexp1_val > aexp2_val; - case IMP_AST_ROP_GE: return aexp1_val >= aexp2_val; + case IMP_AST_ROP_EQ: return l_val == r_val; + case IMP_AST_ROP_NE: return l_val != r_val; + case IMP_AST_ROP_LT: return l_val < r_val; + case IMP_AST_ROP_LE: return l_val <= r_val; + case IMP_AST_ROP_GT: return l_val > r_val; + case IMP_AST_ROP_GE: return l_val >= r_val; default: assert(0); } } @@ -282,155 +52,98 @@ static int eval_bexpr(Context *context, IMP_ASTNode *node) { } } -static int interp_proccall(Context *context, IMP_ASTNode *node) { +static int interpret_proccall(IMP_InterpreterContext *context, const IMP_ASTNode *node) { const char *name = node->data.proc_call.name; - IMP_ASTNode *procdecl = context_get_proc(context, name); + const IMP_ASTNode *procdecl = imp_interpreter_context_proc_get(context, name); if (!procdecl) { fprintf(stderr, "Error: procedure %s not defined\n", name); return -1; } - IMP_ASTNodeList *caller_args = node->data.proc_call.val_args; - IMP_ASTNodeList *callee_args = procdecl->data.proc_decl.val_args; - Context *proc_context = context_create(); - hashmap_keys_iter_t iter = hashmap_keys_iter_create(context->proc_table); - const char *key; - while ((key = hashmap_keys_iter_next(iter)) != NULL) { - IMP_ASTNode *proc = context_get_proc(context, key); - context_set_proc(proc_context, key, imp_ast_clone(proc)); - } - hashmap_keys_iter_free(iter); - while (caller_args && callee_args) { - const char *caller_arg_name = caller_args->node->data.variable.name; - const char *callee_arg_name = callee_args->node->data.variable.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; - } - if (caller_args || callee_args) { + IMP_InterpreterContext *proc_context = imp_interpreter_context_create(); + IMP_InterpreterContextProcIter *proc_iter = imp_interpreter_context_proc_iter_create(context); + const IMP_InterpreterContextProcTableEntry *proc_entry; + while ((proc_entry = imp_interpreter_context_proc_iter_next(proc_iter))) { + imp_interpreter_context_proc_set(proc_context, proc_entry->key, proc_entry->value); + } + imp_interpreter_context_proc_iter_destroy(proc_iter); + IMP_ASTNodeList *caller_val_args = node->data.proc_call.val_args; + IMP_ASTNodeList *callee_val_args = procdecl->data.proc_decl.val_args; + while (caller_val_args && callee_val_args) { + const char *caller_arg_name = caller_val_args->node->data.variable.name; + const char *callee_arg_name = callee_val_args->node->data.variable.name; + imp_interpreter_context_var_set(proc_context, callee_arg_name, imp_interpreter_context_var_get(context, caller_arg_name)); + caller_val_args = caller_val_args->next; + callee_val_args = callee_val_args->next; + } + if (caller_val_args || callee_val_args) { fprintf(stderr, "Error: procedure %s called with wrong number of value arguments\n", name); - context_free(proc_context); + imp_interpreter_context_destroy(proc_context); return -1; } - if (interp_ast(proc_context, procdecl->data.proc_decl.body_stmt)) { - context_free(proc_context); + if (imp_interpreter_interpret_ast(proc_context, procdecl->data.proc_decl.body_stmt)) { + imp_interpreter_context_destroy(proc_context); return -1; } - IMP_ASTNodeList *caller_vargs = node->data.proc_call.var_args; - IMP_ASTNodeList *callee_vargs = procdecl->data.proc_decl.var_args; - while (caller_vargs && callee_vargs) { - const char *caller_varg_name = caller_vargs->node->data.variable.name; - const char *callee_varg_name = callee_vargs->node->data.variable.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; + IMP_ASTNodeList *caller_var_args = node->data.proc_call.var_args; + IMP_ASTNodeList *callee_var_args = procdecl->data.proc_decl.var_args; + while (caller_var_args && callee_var_args) { + const char *caller_varg_name = caller_var_args->node->data.variable.name; + const char *callee_varg_name = callee_var_args->node->data.variable.name; + imp_interpreter_context_var_set(context, caller_varg_name, imp_interpreter_context_var_get(proc_context, callee_varg_name)); + caller_var_args = caller_var_args->next; + callee_var_args = callee_var_args->next; } - if (caller_vargs || callee_vargs) { + if (caller_var_args || callee_var_args) { fprintf(stderr, "Error: procedure %s called with wrong number of variable arguments\n", name); - context_free(proc_context); + imp_interpreter_context_destroy(proc_context); return -1; } - context_free(proc_context); + imp_interpreter_context_destroy(proc_context); return 0; } -int interp_ast(Context *context, IMP_ASTNode *node) { +int imp_interpreter_interpret_ast(IMP_InterpreterContext *context, const IMP_ASTNode *node) { switch (node->type) { case IMP_AST_NT_SKIP: return 0; case IMP_AST_NT_ASSIGN: { const char *name = node->data.assign.var->data.variable.name; int val = eval_aexpr(context, node->data.assign.aexpr); - context_set_var(context, name, val); + imp_interpreter_context_var_set(context, name, val); return 0; } case IMP_AST_NT_SEQ: - if (interp_ast(context, node->data.seq.fst_stmt)) return -1; - if (interp_ast(context, node->data.seq.snd_stmt)) return -1; + if (imp_interpreter_interpret_ast(context, node->data.seq.fst_stmt)) return -1; + if (imp_interpreter_interpret_ast(context, node->data.seq.snd_stmt)) return -1; return 0; case IMP_AST_NT_IF: - if (eval_bexpr(context, node->data.if_stmt.cond_bexpr)) return interp_ast(context, node->data.if_stmt.then_stmt); - else return interp_ast(context, node->data.if_stmt.else_stmt); + if (eval_bexpr(context, node->data.if_stmt.cond_bexpr)) return imp_interpreter_interpret_ast(context, node->data.if_stmt.then_stmt); + else return imp_interpreter_interpret_ast(context, node->data.if_stmt.else_stmt); case IMP_AST_NT_WHILE: while (eval_bexpr(context, node->data.while_stmt.cond_bexpr)) { - if (interp_ast(context, node->data.while_stmt.body_stmt)) return -1; + if (imp_interpreter_interpret_ast(context, node->data.while_stmt.body_stmt)) return -1; } return 0; case IMP_AST_NT_LET: { const char *name = node->data.let_stmt.var->data.variable.name; - int old_val = context_get_var(context, name); + int old_val = imp_interpreter_context_var_get(context, name); int new_val = eval_aexpr(context, node->data.let_stmt.aexpr); - context_set_var(context, name, new_val); - int ret = interp_ast(context, node->data.let_stmt.body_stmt); - context_set_var(context, name, old_val); + imp_interpreter_context_var_set(context, name, new_val); + int ret = imp_interpreter_interpret_ast(context, node->data.let_stmt.body_stmt); + imp_interpreter_context_var_set(context, name, old_val); return ret; } case IMP_AST_NT_PROCDECL: { const char *name = node->data.proc_decl.name; - IMP_ASTNode *procdecl_old = context_get_proc(context, name); - if (procdecl_old) { + if (imp_interpreter_context_proc_get(context, name)) { fprintf(stderr, "Error: procedure %s already defined\n", name); return -1; } - IMP_ASTNode *procdecl = imp_ast_clone(node); - context_set_proc(context, name, procdecl); + imp_interpreter_context_proc_set(context, name, node); return 0; } case IMP_AST_NT_PROCCALL: { - return interp_proccall(context, node); + return interpret_proccall(context, node); } default: assert(0); } -} - -int interp_file (Context *context, const char *path) { - yyin = fopen(path, "r"); - if (!yyin) { - return -1; - } - yyrestart(yyin); - if (yyparse()) { - imp_ast_free(ast_root); - fclose(yyin); - return -1; - } - if (interp_ast(context, ast_root)) { - imp_ast_free(ast_root); - fclose(yyin); - return -1; - } - imp_ast_free(ast_root); - fclose(yyin); - return 0; -} - -int interp_str (Context *context, const char *str) { - YY_BUFFER_STATE buf = yy_scan_string(str); - if (yyparse()) { - imp_ast_free(ast_root); - yy_delete_buffer(buf); - return -1; - } - if (interp_ast(context, ast_root)) { - imp_ast_free(ast_root); - yy_delete_buffer(buf); - return -1; - } - yy_delete_buffer(buf); - return 0; -} - -int print_ast_file (const char *path) { - yyin = fopen(path, "r"); - if (!yyin) { - return -1; - } - yyrestart(yyin); - if (yyparse()) { - imp_ast_free(ast_root); - fclose(yyin); - return -1; - } - ast_print(ast_root, 0); - imp_ast_free(ast_root); - fclose(yyin); - return 0; }
\ No newline at end of file diff --git a/src/interpreter_context.c b/src/interpreter_context.c new file mode 100644 index 0000000..488f872 --- /dev/null +++ b/src/interpreter_context.c @@ -0,0 +1,123 @@ +#include "interpreter_context.h" + +#define STB_DS_IMPLEMENTATION +#include "3rdparty/stb_ds/stb_ds.h" + + +struct IMP_InterpreterContext { + IMP_InterpreterContextVarTableEntry *var_table; + IMP_InterpreterContextProcTableEntry *proc_table; +}; + +struct IMP_InterpreterContextVarIter { + IMP_InterpreterContextVarTableEntry *var_table; + ptrdiff_t index; + ptrdiff_t len; +}; + +struct IMP_InterpreterContextProcIter { + IMP_InterpreterContextProcTableEntry *proc_table; + ptrdiff_t index; + ptrdiff_t len; +}; + +IMP_InterpreterContext *imp_interpreter_context_create(void) { + IMP_InterpreterContext *context = malloc(sizeof(IMP_InterpreterContext)); + assert(context && "Memory allocation failed"); + context->var_table = NULL; + context->proc_table = NULL; + return context; +} + +void imp_interpreter_context_destroy(IMP_InterpreterContext *context) { + ptrdiff_t len = shlen(context->var_table); + for (ptrdiff_t i = 0; i < len; ++i) free((char*)context->var_table[i].key); + shfree(context->var_table); +} + +int imp_interpreter_context_var_get(IMP_InterpreterContext *context, const char *name) { + ptrdiff_t index = shgeti(context->var_table, name); + if (index < 0) return 0; + return context->var_table[index].value; +} + +void imp_interpreter_context_var_set(IMP_InterpreterContext *context, const char *name, int value) { + ptrdiff_t index = shgeti(context->var_table, name); + if (index < 0) { + if (value == 0) return; + const char* key = strdup(name); + assert(key && "Memory allocation failed"); + shput(context->var_table, key, value); + } else { + if (value == 0) { + const char *key = context->var_table[index].key; + shdel(context->var_table, name); + free((char*)key); + return; + } + context->var_table[index].value = value; + } +} + +const IMP_ASTNode *imp_interpreter_context_proc_get(IMP_InterpreterContext *context, const char *name) { + ptrdiff_t index = shgeti(context->proc_table, name); + if (index < 0) return NULL; + return context->proc_table[index].value; +} + +void imp_interpreter_context_proc_set(IMP_InterpreterContext *context, const char *name, const IMP_ASTNode *proc) { + ptrdiff_t index = shgeti(context->proc_table, name); + proc = imp_ast_clone(proc); + if (proc) assert(proc->type == IMP_AST_NT_PROCDECL); + if (index < 0) { + if (proc == NULL) return; + const char* key = strdup(name); + assert(key && "Memory allocation failed"); + shput(context->proc_table, key, proc); + } else { + imp_ast_destroy((IMP_ASTNode*)context->proc_table[index].value); + if (proc == NULL) { + const char *key = context->proc_table[index].key; + shdel(context->proc_table, name); + free((char*)key); + return; + } + context->proc_table[index].value = proc; + } +} + +IMP_InterpreterContextVarIter *imp_interpreter_context_var_iter_create(IMP_InterpreterContext *context) { + IMP_InterpreterContextVarIter *iter = malloc(sizeof(IMP_InterpreterContextVarIter)); + assert(iter && "Memory allocation failed"); + iter->var_table = context->var_table; + iter->index = 0; + iter->len = shlen(context->var_table); + return iter; +} + +void imp_interpreter_context_var_iter_destroy(IMP_InterpreterContextVarIter *iter) { + free(iter); +} + +IMP_InterpreterContextVarTableEntry *imp_interpreter_context_var_iter_next(IMP_InterpreterContextVarIter *iter) { + if (iter->index >= iter->len) return NULL; + return &iter->var_table[iter->index++]; +} + +IMP_InterpreterContextProcIter *imp_interpreter_context_proc_iter_create(IMP_InterpreterContext *context) { + IMP_InterpreterContextProcIter *iter = malloc(sizeof(IMP_InterpreterContextProcIter)); + assert(iter && "Memory allocation failed"); + iter->proc_table = context->proc_table; + iter->index = 0; + iter->len = shlen(context->proc_table); + return iter; +} + +void imp_interpreter_context_proc_iter_destroy(IMP_InterpreterContextProcIter *iter) { + free(iter); +} + +IMP_InterpreterContextProcTableEntry *imp_interpreter_context_proc_iter_next(IMP_InterpreterContextProcIter *iter) { + if (iter->index >= iter->len) return NULL; + return &iter->proc_table[iter->index++]; +}
\ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..5ef854d --- /dev/null +++ b/src/main.c @@ -0,0 +1,45 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "interpreter_context.h" +#include "driver.h" +#include "repl.h" + + +static int interpret_file(const char *path) { + IMP_InterpreterContext *context = imp_interpreter_context_create(); + if (imp_driver_interpret_file(context, path)) { + fprintf(stderr, "Error interpreting file: %s\n", path); + imp_interpreter_context_destroy(context); + return -1; + } + imp_driver_print_var_table(context); + imp_interpreter_context_destroy(context); + return 0; +} + +int main(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "i:a:h")) != -1) { + switch (opt) { + case 'i': + return interpret_file(optarg) ? EXIT_FAILURE : EXIT_SUCCESS; + case 'a': + return imp_driver_print_ast_file(optarg) ? EXIT_FAILURE : EXIT_SUCCESS; + case 'h': + default: + fprintf(stderr, + "Usage: %s [ARGS]\n" + " (no args) start REPL\n" + " -i <program.imp> interpret program\n" + " -a <program.imp> print ast\n" + " -h print this message\n", + argv[0]); + return (opt == 'h') ? EXIT_SUCCESS : EXIT_FAILURE; + } + } + imp_repl(); + return EXIT_SUCCESS; +}
\ No newline at end of file @@ -8,7 +8,8 @@ #include <readline/readline.h> #include <readline/history.h> -#include "interpreter.h" +#include "interpreter_context.h" +#include "driver.h" static void print_help(void) { @@ -31,7 +32,7 @@ static int is_valid_identifier(const char *var) { return 1; } -static void repl_exec_command(context_t context, char *command) { +static void repl_exec_command(IMP_InterpreterContext *context, char *command) { char *cmd = strtok(command, " \t"); if (strcmp(cmd, "%quit") == 0) { exit(EXIT_SUCCESS); @@ -40,7 +41,8 @@ static void repl_exec_command(context_t context, char *command) { } else if (strcmp(cmd, "%run") == 0) { char *file = strtok(NULL, " \t"); if (file) { - if (!interp_file(context, file)) context_print_var_table(context); + if (!imp_driver_interpret_file(context, file)) imp_driver_print_var_table(context); + else fprintf(stderr, "Error interpreting file: %s\n", file); } else { fprintf(stderr, "Usage: %%run <path/to/file.imp>\n"); } @@ -49,7 +51,7 @@ static void repl_exec_command(context_t context, char *command) { char *val = strtok(NULL, " \t"); if (var && val) { if (is_valid_identifier(var)) { - context_set_var(context, var, atoi(val)); + imp_interpreter_context_var_set(context, var, atoi(val)); } else { fprintf(stderr, "Invalid variable name: %s\n", var); } @@ -58,28 +60,28 @@ static void repl_exec_command(context_t context, char *command) { char *var = strtok(NULL, " \t"); if (var) { if (is_valid_identifier(var)) { - printf("%s = %d\n", var, context_get_var(context, var)); + printf("%s = %d\n", var, imp_interpreter_context_var_get(context, var)); } else { fprintf(stderr, "Invalid variable name: %s\n", var); } - } else context_print_var_table(context); + } else imp_driver_print_var_table(context); } else if (strcmp(cmd, "%procedures") == 0) { - context_print_proc_table(context); + imp_driver_print_proc_table(context); } else { fprintf(stderr, "Unknown command: %s\n", cmd); } } -static void repl_exec_statement(context_t context, const char *statement) { - if (interp_str(context, statement)) { +static void repl_exec_statement(IMP_InterpreterContext *context, const char *statement) { + if (imp_driver_interpret_str(context, statement)) { fprintf(stderr, "Error interpreting statement: %s\n", statement); return; } - context_print_var_table(context); + imp_driver_print_var_table(context); } -void repl(void) { - context_t context = context_create(); +void imp_repl(void) { + IMP_InterpreterContext *context = imp_interpreter_context_create(); char *line; print_help(); @@ -91,5 +93,5 @@ void repl(void) { } printf("\n"); - context_free(context); + imp_interpreter_context_destroy(context); }
\ No newline at end of file |