-
Notifications
You must be signed in to change notification settings - Fork 1
/
llh.c
277 lines (181 loc) · 6.16 KB
/
llh.c
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#include "llh.h"
/* input */
/* isQuit can't be defined in read.c because it affects
how the evaluator itself runs, whereas the other
user commands (e.g. flag toggling) are executed
just by the read function. */
bool isQuit(Obj expr) {
return GETTAG(expr) == NAME && cmpForm(GETNAME(expr), QUIT_COMMAND);
}
/* numbers */
bool isNum(Obj expr) {
form_check_count++;
return GETTAG(expr) == NUM || isBool(expr);
}
bool isBool(Obj expr) { return GETTAG(expr) == BOOL_; }
/* variables */
bool isVar(Obj expr) {
form_check_count++;
return GETTAG(expr) == NAME;
}
bool isUnbound(Obj expr) { return GETTAG(expr) == DUMMY; }
/* special forms */
char* specialForm(Obj expr) { return GETNAME(CAR(expr)); }
bool cmpForm(char* cand, char* form) { return strcmp(cand, form) == 0; }
bool hasForm(Obj expr, char* form) {
form_check_count++;
return cmpForm(specialForm(expr), form);
}
/* quotation */
bool isQuote(Obj expr) { return hasForm(expr, QUOTE_KEY); }
Obj quotedText(Obj expr) { return CADR(expr); }
/* begin */
bool isBegin(Obj expr) { return hasForm(expr, BEGIN_KEY); }
Obj beginActions(Obj expr) { return CDR(expr); }
/* delay */
bool isDelay(Obj expr) { return hasForm(expr, DELAY_KEY); }
Obj delayExpr(Obj expr) { return CADR(expr); }
Obj transformDelay(Obj expr) {
List* list =
makeList(LAMBDAOBJ, makeList(NULLOBJ, makeList(delayExpr(expr), NULL)));
Obj obj = LISTOBJ(list);
return obj;
}
/* if */
bool isIf(Obj expr) { return hasForm(expr, IF_KEY); }
Obj ifTest(Obj expr) { return CADR(expr); }
// is this right?
bool isTrue(Obj expr) {
switch (GETTAG(expr)) {
case NUM:
return GETNUM(expr) != false;
case BOOL_:
return GETBOOL(expr) != false;
default:
return true;
}
}
Obj ifThen(Obj expr) { return CADDR(expr); }
Obj ifElse(Obj expr) { return CADDDR(expr); }
/* other boolean macros */
bool isAnd(Obj expr) { return hasForm(expr, AND_KEY); }
bool isOr(Obj expr) { return hasForm(expr, OR_KEY); }
Obj boolExps(Obj expr) { return CDR(expr); }
/* transformAnd and transformOr take and- and or-expressions and
transform them into if-expressions. For example, the
expression (and a b c d) is transformed into
(if a (and b c d) false), and the expression
(or a b c d) is tranformed into (if a true (or b c d)).
This is not a very efficient way to implement boolean
expression, but it is the easiest way */
Obj transformAnd(Obj expr) {
Obj seq = boolExps(expr);
if (noExps(seq)) return TRUEOBJ;
Obj first = firstExp(seq);
List* cdr = GETLIST(seq)->cdr;
Obj rest = LISTOBJ(makeList(ANDOBJ, cdr));
List* ifTrans = makeList(
IFOBJ, makeList(first, makeList(rest, makeList(FALSEOBJ, NULL))));
return LISTOBJ(ifTrans);
}
Obj transformOr(Obj expr) {
Obj seq = boolExps(expr);
if (noExps(seq)) return FALSEOBJ;
Obj first = firstExp(seq);
List* cdr = GETLIST(seq)->cdr;
Obj rest = LISTOBJ(makeList(OROBJ, cdr));
List* ifTrans = makeList(
IFOBJ, makeList(first, makeList(TRUEOBJ, makeList(rest, NULL))));
return LISTOBJ(ifTrans);
}
/* lambda */
bool isLambda(Obj expr) { return hasForm(expr, LAMBDA_KEY); }
Obj lambdaParams(Obj expr) { return CADR(expr); }
/* to allow for implicit begin blocks, change this
and some other functions to provide for a list of
body expressions; otherwise, explicit begins are needed
for, e.g, iterative factorial */
Obj lambdaBody(Obj expr) { return CDDR(expr); }
Obj makeFunc(Obj params, Obj body, Obj env) {
List* list = makeList(env, makeList(params, makeList(body, NULL)));
return LISTOBJ(list);
}
/* ass, def */
bool isDef(Obj expr) { return hasForm(expr, DEF_KEY); }
bool isSugarDef(Obj expr) { return GETTAG(CADR(expr)) == LIST; }
Obj transformSugarDef(Obj expr) {
Obj funcArgs = CADR(expr);
Obj func = CAR(funcArgs);
Obj args = CDR(funcArgs);
Obj body = CDDR(expr);
Obj lambdaExpr = CONS(LAMBDAOBJ, CONS(args, body));
Obj transformed = CONS(DEFOBJ, CONS(func, CONS(lambdaExpr, NULLOBJ)));
return transformed;
}
Obj defVar(Obj expr) { return CADR(expr); }
Obj defVal(Obj expr) { return CADDR(expr); }
bool isAss(Obj expr) { return hasForm(expr, ASS_KEY); }
Obj assVar(Obj expr) { return CADR(expr); }
Obj assVal(Obj expr) { return CADDR(expr); }
/* function */
Obj getFunc(Obj expr) { return CAR(expr); }
bool isSimple(Obj expr) { return isVar(expr) || isNum(expr); }
Obj getArgs(Obj expr) { return CDR(expr); }
bool noArgs(Obj expr) { return GETLIST(expr) == NULL; }
bool noCompoundArgs(Obj expr) {
if (noArgs(expr))
return true;
else {
List* list = GETLIST(expr);
return isSimple(list->car) && noCompoundArgs(LISTOBJ(list->cdr));
}
}
Obj firstArg(Obj expr) { return CAR(expr); }
bool isLastArg(Obj expr) { return GETLIST(expr)->cdr == NULL; }
/* adjoinArg walks down the whole length
of the arglist to append a value to the end.
This is less efficient than building the list
backwards and then reversing, but it makes
the info display easier to read. */
Obj adjoinArg(Obj val, Obj arglist) {
List* args = GETLIST(arglist);
if (!args) return LISTOBJ(makeList(val, args));
List* pnr = args;
while (pnr->cdr) pnr = pnr->cdr;
pnr->cdr = malloc(sizeof(List));
pnr = pnr->cdr;
pnr->car = val;
pnr->cdr = NULL;
return LISTOBJ(args);
}
Obj restArgs(Obj expr) { return CDR(expr); }
/* apply */
bool isPrimitive(Obj obj) {
// isPrimitive_count++;
return GETTAG(obj) == PRIM;
}
bool isCompound(Obj obj) {
// isCompound_count++;
return GETTAG(obj) == LIST;
}
bool isCompiled(Obj obj) {
// isCompiled_count++;
return GETTAG(obj) == COMP;
}
// make sure these coordinate with makeFunc
Obj funcParams(Obj obj) { return CADR(obj); }
Obj funcBody(Obj obj) { return CADDR(obj); }
Obj funcEnv(Obj obj) { return CAR(obj); }
/* sequence */
Obj firstExp(Obj seq) { return CAR(seq); }
Obj restExps(Obj seq) { return CDR(seq); }
bool isLastExp(Obj seq) {
List* next = GETLIST(seq)->cdr;
return next == NULL;
}
bool noExps(Obj seq) {
List* list = GETLIST(seq);
return list == NULL;
}
/* error-checking */
bool isError(Obj obj) { return GETTAG(obj) == ERROR; }