Bind values to symbols during evaluation. Call builtin functions.
[berndj-bootstrap.git] / lisp / lisp.c
blobfa8f76d194d79f2610f317815814779d22b76ee5
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
5 struct pair;
7 struct charseq {
8 size_t len;
9 char *s;
12 union value_pointer {
13 int vp_int;
14 struct pair *vp_pair;
15 struct charseq *vp_charseq;
16 union value_pointer (*vp_builtin)(union value_pointer rest);
19 struct binding {
20 struct charseq *name;
21 union value_pointer type_dot_value;
24 struct environment {
25 struct binding **variables;
26 int variables_used;
27 int variables_size;
28 struct environment *parent;
31 struct pair {
32 union value_pointer car;
33 union value_pointer cdr;
36 void pointer_mark(union value_pointer *v, int type)
38 int pointer_bits = v->vp_int;
40 pointer_bits &= ~3;
41 pointer_bits |= type;
43 v->vp_int = pointer_bits;
46 int pointer_type(union value_pointer v)
48 return (v.vp_int & 3);
51 int get_integer(union value_pointer v)
53 return (v.vp_int >> 2);
56 struct pair *get_pair(union value_pointer v)
58 v.vp_int &= ~3;
59 return v.vp_pair;
62 struct charseq *get_charseq(union value_pointer v)
64 v.vp_int &= ~3;
65 return v.vp_charseq;
68 size_t get_charseq_length(union value_pointer v)
70 struct charseq *cs;
72 cs = get_charseq(v);
74 return cs->len;
77 char *get_charseq_chars(union value_pointer v)
79 struct charseq *cs;
81 cs = get_charseq(v);
83 return cs->s;
86 struct charseq *charseq_new(void)
88 return malloc(sizeof (struct charseq));
91 struct pair *pair_new(void)
93 return malloc(sizeof (struct pair));
96 struct binding *binding_new(char const *name,
97 union value_pointer type_dot_value)
99 struct binding *b;
101 b = malloc(sizeof (*b));
103 b->name = charseq_new();
104 b->name->len = strlen(name);
105 b->name->s = strdup(name);
107 b->type_dot_value = type_dot_value;
109 return b;
112 void binding_builtin(struct environment *env,
113 char const *name,
114 union value_pointer (*builtin)(union value_pointer rest))
116 union value_pointer v;
117 struct pair *type_dot_value;
119 if (env->variables_used >= env->variables_size) {
120 int newsize = env->variables_used * 2 + 16;
122 env->variables = realloc(env->variables,
123 sizeof (*env->variables) * newsize);
124 env->variables_size = newsize;
127 type_dot_value = pair_new();
128 type_dot_value->car.vp_int = 1 << 2;
129 pointer_mark(&type_dot_value->car, 0);
130 type_dot_value->cdr.vp_builtin = builtin;
131 v.vp_pair = type_dot_value;
132 pointer_mark(&v, 3);
134 env->variables[env->variables_used++] = binding_new(name, v);
137 size_t parse_word(union value_pointer *vp, char const *buf, size_t len)
139 size_t i;
140 int n;
142 for (n = 0, i = 0; i < len; i++) {
143 if (buf[i] < '0' || buf[i] > '9') {
144 break;
146 n = n*10 + buf[i] - '0';
149 if (i < len) {
150 char *symbol;
152 switch (buf[i]) {
153 case ')':
154 case ' ':
155 case '\n':
156 case '\t':
157 break;
158 default:
159 for (i++; i < len; i++) {
160 switch (buf[i]) {
161 case ')':
162 case ' ':
163 case '\n':
164 case '\t':
165 len = i + 1;
166 break;
169 vp->vp_charseq = charseq_new();
170 vp->vp_charseq->len = i;
171 vp->vp_charseq->s = malloc(i + 1);
172 memcpy(vp->vp_charseq->s, buf, i);
173 vp->vp_charseq->s[i] = 0;
174 pointer_mark(vp, 1);
175 return i;
178 vp->vp_int = n << 2;
179 pointer_mark(vp, 0);
180 return i;
183 size_t parse_string(union value_pointer *vp, char const *buf, size_t len)
185 size_t i;
187 for (i = 1; i < len; i++) {
188 if (buf[i] == '"') {
189 break;
193 vp->vp_charseq = charseq_new();
194 vp->vp_charseq->len = i - 1;
195 vp->vp_charseq->s = malloc(i);
196 memcpy(vp->vp_charseq->s, buf + 1, i - 1);
197 vp->vp_charseq->s[i-1] = 0;
198 pointer_mark(vp, 2);
200 return i + 1;
203 size_t parse_form(char const *buf, size_t len, union value_pointer *form)
205 size_t i, n;
206 int word_start = -1;
208 for (i = 0; i < len; i++) {
209 char const c = buf[i];
210 union value_pointer u, v;
212 switch (c) {
213 case '(':
214 v.vp_pair = pair_new();
215 v.vp_pair->car.vp_pair = NULL;
216 pointer_mark(&v.vp_pair->car, 3);
217 i += parse_form(buf + i + 1, len - i - 1, &v.vp_pair->car) + 1;
218 v.vp_pair->cdr.vp_pair = NULL;
219 pointer_mark(&v.vp_pair->cdr, 3);
220 *form = v;
221 pointer_mark(form, 3);
222 form = &v.vp_pair->cdr;
223 break;
224 case ')':
225 case ' ':
226 case '\n':
227 case '\t':
228 if (word_start != -1) {
229 v.vp_pair = pair_new();
230 parse_word(&v.vp_pair->car, buf + word_start, i - word_start);
231 v.vp_pair->cdr.vp_pair = NULL;
232 pointer_mark(&v.vp_pair->cdr, 3);
233 *form = v;
234 pointer_mark(form, 3);
235 form = &v.vp_pair->cdr;
237 word_start = -1;
238 break;
239 case '"':
240 v.vp_pair = pair_new();
241 n = parse_string(&v.vp_pair->car, buf + i, len - i);
242 i += n;
243 v.vp_pair->cdr.vp_pair = NULL;
244 pointer_mark(&v.vp_pair->cdr, 3);
245 *form = v;
246 pointer_mark(form, 3);
247 form = &v.vp_pair->cdr;
248 break;
249 default:
250 if (word_start == -1) {
251 word_start = i;
253 break;
256 if (c == ')') {
257 break;
261 return i;
264 void pretty_print(union value_pointer v)
266 union value_pointer i;
268 switch (pointer_type(v)) {
269 case 0:
270 printf("%d", get_integer(v));
271 break;
272 case 1:
273 printf("%s", get_charseq_chars(v));
274 break;
275 case 2:
276 printf("\"%s\"", get_charseq_chars(v));
277 break;
278 case 3:
279 printf("(");
280 for (i = v; i.vp_int != 3; i = get_pair(i)->cdr) {
281 if (i.vp_pair != v.vp_pair) {
282 printf(" ");
284 pretty_print(get_pair(i)->car);
286 printf(")");
287 break;
291 union value_pointer eval(struct environment *env, union value_pointer v)
293 union value_pointer retval, function, rest;
294 union value_pointer *args;
295 char const *symbol_name;
296 struct pair *list, *closure;
297 int i;
299 switch (pointer_type(v)) {
300 case 0:
301 case 2:
302 retval = v;
303 break;
304 case 1:
305 symbol_name = get_charseq_chars(v);
306 do {
307 for (i = 0; i < env->variables_used; i++) {
308 if (strcmp(env->variables[i]->name->s,
309 symbol_name) == 0) {
310 return env->variables[i]->type_dot_value;
313 env = env->parent;
314 } while (env != NULL);
315 break;
316 case 3:
317 rest.vp_pair = NULL;
318 pointer_mark(&rest, 3);
319 args = &rest;
320 for (list = get_pair(v); list != NULL; list = get_pair(list->cdr)) {
321 union value_pointer element;
323 element.vp_pair = pair_new();
324 element.vp_pair->car = eval(env, list->car);
325 element.vp_pair->cdr.vp_pair = NULL;
326 pointer_mark(&element.vp_pair->cdr, 3);
328 *args = element;
329 pointer_mark(args, 3);
330 args = &element.vp_pair->cdr;
333 list = get_pair(rest);
334 function = list->car;
335 rest = list->cdr;
337 closure = get_pair(function);
338 switch (get_integer(closure->car)) {
339 case 1:
340 retval = (*closure->cdr.vp_builtin)(rest);
341 break;
344 break;
347 return retval;
350 union value_pointer builtin_plus(union value_pointer rest)
352 struct pair *i;
353 union value_pointer retval;
354 int sum;
356 for (sum = 0, i = get_pair(rest); i != NULL; i = get_pair(i->cdr)) {
357 sum += get_integer(i->car);
360 retval.vp_int = sum << 2;
361 pointer_mark(&retval, 0);
363 return retval;
366 int main()
368 char *buf = NULL;
369 size_t bufused = 0;
370 size_t bufsize = 0;
371 size_t formsize;
372 union value_pointer form;
373 struct pair *i;
374 struct environment top_env;
376 while (!feof(stdin) && !ferror(stdin)) {
377 size_t n;
379 if (bufused >= bufsize) {
380 buf = realloc(buf, bufsize * 2 + 16);
381 if (buf == NULL) {
382 abort();
384 bufsize = bufsize * 2 + 16;
386 n = fread(buf + bufused, 1, bufsize - bufused, stdin);
387 bufused += n;
390 top_env.variables = NULL;
391 top_env.variables_used = 0;
392 top_env.variables_size = 0;
393 top_env.parent = NULL;
395 binding_builtin(&top_env, "+", builtin_plus);
396 form.vp_pair = pair_new();
397 pointer_mark(&form, 3);
399 formsize = parse_form(buf, bufused, &form);
401 if (formsize != bufused) {
402 printf("this stuff left over: \"%.*s\"\n",
403 bufused - formsize, buf + formsize);
406 for (i = get_pair(form); i != NULL; i = get_pair(i->cdr)) {
407 pretty_print(i->car);
408 printf(" -> ");
409 pretty_print(eval(&top_env, i->car));
410 printf("\n");
413 return 0;