aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFlavian Kaufmann <flavian@flaviankaufmann.ch>2025-05-22 07:25:16 +0200
committerFlavian Kaufmann <flavian@flaviankaufmann.ch>2025-05-22 07:25:16 +0200
commit3369805cc122788edf2bd6d3d0cebef7c153d638 (patch)
tree599b08b8ad8721354539163bed3ce9c3a270ca06 /src
parentb8006ecd24830c849a989554b059bc452371e5b2 (diff)
downloadimp-3369805cc122788edf2bd6d3d0cebef7c153d638.tar.gz
imp-3369805cc122788edf2bd6d3d0cebef7c153d638.zip
interpreter error propagation
Diffstat (limited to 'src')
-rw-r--r--src/driver.c9
-rw-r--r--src/interpreter.c67
-rw-r--r--src/repl.c1
3 files changed, 54 insertions, 23 deletions
diff --git a/src/driver.c b/src/driver.c
index e3938a6..c9ac098 100644
--- a/src/driver.c
+++ b/src/driver.c
@@ -7,11 +7,16 @@
#include "repl.h"
-static void interpret_file(const char *path) {
+static int interpret_file(const char *path) {
context_t context = context_create();
- interp_file(context, path);
+ if (interp_file(context, path)) {
+ fprintf(stderr, "Error interpreting file: %s\n", path);
+ context_free(context);
+ return -1;
+ }
context_print_var_table(context);
context_free(context);
+ return 0;
}
int main(int argc, char **argv) {
diff --git a/src/interpreter.c b/src/interpreter.c
index bf147df..d200145 100644
--- a/src/interpreter.c
+++ b/src/interpreter.c
@@ -20,6 +20,7 @@ typedef struct Context{
hashmap_t proc_table;
} Context;
+
static ASTNode *context_get_proc(Context *context, const char *name) {
ASTNode **procdecl = (ASTNode**)hashmap_get(context->proc_table, name);
if (procdecl) return *procdecl;
@@ -119,47 +120,54 @@ static int eval_bexpr(Context *context, ASTNode *node) {
}
}
-void interp_ast(Context *context, ASTNode *node) {
+int interp_ast(Context *context, ASTNode *node) {
switch (node->type) {
- case NT_SKIP: return;
+ case NT_SKIP: return 0;
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;
+ return 0;
}
case NT_SEQ:
- interp_ast(context, node->u.d_seq.stm1);
- interp_ast(context, node->u.d_seq.stm2);
- return;
+ if (interp_ast(context, node->u.d_seq.stm1)) return -1;
+ if (interp_ast(context, node->u.d_seq.stm2)) return -1;
+ return 0;
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;
+ if (eval_bexpr(context, node->u.d_if.bexp)) return interp_ast(context, node->u.d_if.stm1);
+ else return interp_ast(context, node->u.d_if.stm2);
case NT_WHILE:
- while (eval_bexpr(context, node->u.d_while.bexp)) interp_ast(context, node->u.d_while.stm);
- return;
+ while (eval_bexpr(context, node->u.d_while.bexp)) {
+ if (interp_ast(context, node->u.d_while.stm)) return -1;
+ }
+ return 0;
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);
+ int ret = interp_ast(context, node->u.d_let.stm);
context_set_var(context, name, old_val);
- return;
+ return ret;
}
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);
+ if (procdecl_old) {
+ fprintf(stderr, "Error: procedure %s already defined\n", name);
+ return -1;
+ }
+ ASTNode *procdecl = ast_clone(node);
context_set_proc(context, name, procdecl);
- return;
+ return 0;
}
case NT_PROCCALL: {
char *name = node->u.d_proccall.name;
ASTNode *procdecl = context_get_proc(context, name);
- if (!procdecl) return;
+ if (!procdecl) {
+ fprintf(stderr, "Error: procedure %s not defined\n", name);
+ return -1;
+ }
ASTNodeList *caller_args = node->u.d_proccall.args;
ASTNodeList *callee_args = procdecl->u.d_procdecl.args;
Context *proc_context = context_create();
@@ -178,7 +186,15 @@ void interp_ast(Context *context, ASTNode *node) {
caller_args = caller_args->next;
callee_args = callee_args->next;
}
- interp_ast(proc_context, procdecl->u.d_procdecl.stm);
+ if (caller_args || callee_args) {
+ fprintf(stderr, "Error: procedure %s called with wrong number of arguments\n", name);
+ context_free(proc_context);
+ return -1;
+ }
+ if (interp_ast(proc_context, procdecl->u.d_procdecl.stm)) {
+ context_free(proc_context);
+ return -1;
+ }
ASTNodeList *caller_vargs = node->u.d_proccall.vargs;
ASTNodeList *callee_vargs = procdecl->u.d_procdecl.vargs;
while (caller_vargs && callee_vargs) {
@@ -189,7 +205,7 @@ void interp_ast(Context *context, ASTNode *node) {
callee_vargs = callee_vargs->next;
}
context_free(proc_context);
- return;
+ return 0;
}
default: assert(0);
}
@@ -200,9 +216,14 @@ int interp_file (Context *context, const char *path) {
if (!yyin) return -1;
yyrestart(yyin);
if (!yyparse()) {
- interp_ast(context, ast_root);
+ if (interp_ast(context, ast_root)) {
+ ast_free(ast_root);
+ fclose(yyin);
+ return -1;
+ }
ast_free(ast_root);
} else {
+ /* TODO: potential memory leak, when parsing fails*/
fclose(yyin);
return -1;
}
@@ -213,7 +234,11 @@ int interp_file (Context *context, const char *path) {
int interp_str (Context *context, const char *str) {
YY_BUFFER_STATE buf = yy_scan_string(str);
if (!yyparse()) {
- interp_ast(context, ast_root);
+ if (interp_ast(context, ast_root)) {
+ ast_free(ast_root);
+ yy_delete_buffer(buf);
+ return -1;
+ }
ast_free(ast_root);
} else {
yy_delete_buffer(buf);
diff --git a/src/repl.c b/src/repl.c
index f6387a2..8fbbd2f 100644
--- a/src/repl.c
+++ b/src/repl.c
@@ -50,6 +50,7 @@ static void repl_exec_command(context_t context, char *command) {
static void repl_exec_statement(context_t context, const char *statement) {
if (!interp_str(context, statement)) context_print_var_table(context);
+ else fprintf(stderr, "Error interpreting statement: %s\n", statement);
}
void repl(void) {