1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
#include "interpreter.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
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 imp_interpreter_context_var_get(context, node->data.variable.name);
case IMP_AST_NT_AOP: {
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 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);
}
}
default: assert(0);
}
}
static int eval_bexpr(IMP_InterpreterContext *context, const IMP_ASTNode *node) {
switch (node->type) {
case IMP_AST_NT_BOP: {
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 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 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 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);
}
}
default: assert(0);
}
}
static int interpret_proccall(IMP_InterpreterContext *context, const IMP_ASTNode *node) {
const char *name = node->data.proc_call.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_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) {
int val = eval_aexpr(context, caller_val_args->node);
const char *callee_arg_name = callee_val_args->node->data.variable.name;
imp_interpreter_context_var_set(proc_context, callee_arg_name, val);
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);
imp_interpreter_context_destroy(proc_context);
return -1;
}
if (imp_interpreter_interpret_ast(proc_context, procdecl->data.proc_decl.body_stmt)) {
imp_interpreter_context_destroy(proc_context);
return -1;
}
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_var_args || callee_var_args) {
fprintf(stderr, "Error: procedure %s called with wrong number of variable arguments\n", name);
imp_interpreter_context_destroy(proc_context);
return -1;
}
imp_interpreter_context_destroy(proc_context);
return 0;
}
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);
imp_interpreter_context_var_set(context, name, val);
return 0;
}
case IMP_AST_NT_SEQ:
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 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 (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 = imp_interpreter_context_var_get(context, name);
int new_val = eval_aexpr(context, node->data.let_stmt.aexpr);
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;
if (imp_interpreter_context_proc_get(context, name)) {
fprintf(stderr, "Error: procedure %s already defined\n", name);
return -1;
}
imp_interpreter_context_proc_set(context, name, node);
return 0;
}
case IMP_AST_NT_PROCCALL: {
return interpret_proccall(context, node);
}
default: assert(0);
}
}
|