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
|
#include "run.h"
#include "ast.h"
#include "ht.h"
#include <stdio.h>
#include <string.h>
// return pointer to nth subnode of AST_LIST node *l.
// doesn't check that l is a list, or that it has at least n elems.
#define NTH(l,n) (&(l)->as.list.vals[(n)])
// n is max index
#define CK_LEN(s, l, n) do { if(l.len-1 != n) { \
printf("%s fn requires exactly %d args (%ld provided)",\
s, n, l.len-1); return 0; } } while(0);
static int func_plus(Env *s, AstVec l) {
CK_LEN("+",l,2);
return eval(s, l.vals[1]) + eval(s, l.vals[2]);
}
static int func_id(Env *s, AstVec l) {
CK_LEN("id",l,1);
return eval(s, l.vals[1]);
}
static int func_minus(Env *s, AstVec l) {
CK_LEN("-",l,2);
return eval(s, l.vals[1]) - eval(s, l.vals[2]);
}
static int func_mult(Env *s, AstVec l) {
CK_LEN("*",l,2);
return eval(s, l.vals[1]) * eval(s, l.vals[2]);
}
static int func_div(Env *s, AstVec l) {
CK_LEN("/",l,2);
return eval(s, l.vals[1]) / eval(s, l.vals[2]);
}
static int func_print(Env *s, AstVec l) {
CK_LEN("print",l,1);
int v = eval(s, l.vals[1]);
printf("%d\n",v);
return v;
}
static int func_set(Env *s, AstVec l) {
CK_LEN("set", l, 2);
if (l.vals[1].ty != AST_SYMBOL) {
printf("can only assign to symbols");
return 0;
}
int v = eval(s, l.vals[2]);
printf(" %p set %s %d\n", (void*)s, l.vals[1].as.str, v);
ht_put(s, l.vals[1].as.str, v);
return v;
}
static int func_do(Env *s, AstVec l) {
for (int i = 1; i < l.len; i++) {
eval(s, l.vals[i]);
}
return 0;
}
typedef int (*builtin_func)(Env*, AstVec);
typedef struct {
char *name;
builtin_func func;
} BuiltinDesc;
BuiltinDesc builtins[] = {
{ "+", func_plus },
{ "-", func_minus },
{ "*", func_mult },
{ "/", func_div },
{ "id", func_id },
{ "print", func_print },
{ "set", func_set },
{ "do", func_do },
{ NULL, NULL },
};
static int call_builtin(Env *s, char *name, AstVec arglist) {
for (BuiltinDesc *bd = builtins; bd->name != NULL; bd++) {
if (0 == strcmp(bd->name, name)) {
return bd->func(s, arglist);
}
}
printf("couldn't find builtin fn %s\n",name);
return 0;
}
int eval(Env *s, AstNode a) {
switch (a.ty) {
case AST_SYMBOL:;
int v;
if (ht_get(s, a.as.str, &v)) {
return v;
} else {
printf("unset variable %s\n",a.as.str);
return 0;
}
break;
case AST_NUM:
return a.as.num;
break;
case AST_LIST:;
AstVec l = a.as.list;
if (l.len < 1) {
printf("can't execute empty list\n");
return 0;
}
AstNode *first = &l.vals[0];
if (first->ty != AST_SYMBOL) {
printf("first element of list must be symbol\n");
return 0;
}
return call_builtin(s, first->as.str, l);
break;
default:
printf("???\n");
return 0;
}
}
|