-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjmclisp.c
291 lines (250 loc) · 6.67 KB
/
jmclisp.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
278
279
280
281
282
283
284
285
286
287
288
289
290
/*
* JMC Lisp: defined in McCarthy's 1960 paper,
* derived from http://www.paulgraham.com/lispcode.html
*
* This code is Licensed under CC0.
* https://creativecommons.org/publicdomain/zero/1.0/
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define SSTR_MAX 4096
typedef uintptr_t value_t;
enum NODE_TAG { NODE_STRG, NODE_CONS };
typedef struct _node_t_ {
value_t value;
enum NODE_TAG tag;
} _node_t, *node_t;
node_t node(value_t value, enum NODE_TAG tag);
typedef struct _cons_t_ {
node_t x;
node_t y;
} _cons_t, *cons_t;
#define str_to_node(s) (node((value_t)(s), NODE_STRG))
#define node_to_str(s) ((char *)(s->value))
#define car(s) (((cons_t)(s->value))->x)
#define cdr(s) (((cons_t)(s->value))->y)
#define n_strg(s) (s->tag == NODE_STRG)
#define n_cons(s) (s->tag == NODE_CONS)
#define atom(s) (eq(s, NULL) || n_strg(s))
#define S_T (str_to_node("t"))
#define S_NIL (NULL)
int s_lex(const char *s, char* sl[])
{
char sf[SSTR_MAX * 3];
int i, j = 0;
for (i = 0; i < strlen(s); i++) {
switch (s[i]) {
case '(':
case ')':
case '\'':
sf[j++] = ' '; sf[j++] = s[i]; sf[j++] = ' ';
break;
case '\n': j++; break;
default: sf[j++] = s[i];
}
}
sf[j] = '\0';
char *t;
int len = 0;
for (t = strtok(sf, " "); t != NULL; t = strtok(NULL, " "))
sl[len++] = t;
sl[len] = NULL;
return (len);
}
node_t cons(node_t x, node_t y);
node_t s_syn(char *s[], int *pos)
{
char *t = s[*pos];
*pos = *pos - 1;
if (t[0] == ')') {
node_t r = NULL;
while (s[*pos][0] != '(') {
if (s[*pos][0] == '.') {
*pos = *pos - 1;
r = cons(s_syn(s, pos), car(r));
} else {
r = cons(s_syn(s, pos), r);
}
}
*pos = *pos - 1;
if (*pos != -1 && s[*pos][0] == '\'') {
*pos = *pos - 1;
return cons(str_to_node("quote"), cons(r, NULL));
} else {
return (r);
}
} else {
node_t tn = str_to_node(t);
if (*pos != -1 && s[*pos][0] == '\'') {
*pos = *pos - 1;
return cons(str_to_node("quote"), cons(tn, NULL));
} else {
return (tn);
}
}
}
node_t node(value_t value, enum NODE_TAG tag)
{
node_t n = (node_t)malloc(sizeof(_node_t));
n->value = value; n->tag = tag;
return (n);
}
node_t cons(node_t x, node_t y)
{
cons_t c = (cons_t)malloc(sizeof(_cons_t));
c->x = x; c->y = y;
node_t n = node((value_t)c, NODE_CONS);
return (n);
}
int eq(node_t s1, node_t s2)
{
if (s1 == NULL && s2 == NULL) return (1);
else if (s1 == NULL || s2 == NULL) return (0);
else if (n_cons(s1) || n_cons(s2)) return (0);
else return (!strcmp(node_to_str(s1), node_to_str(s2)));
}
node_t caar(node_t x) { return car(car(x)); }
node_t cadr(node_t x) { return car(cdr(x)); }
node_t cadar(node_t x) { return car(cdr(car(x))); }
node_t caddr(node_t x) { return car(cdr(cdr(x))); }
node_t caddar(node_t x) { return car(cdr(cdr(car(x)))); }
node_t s_null(node_t x) {
if (eq(x, NULL)) return S_T; else return S_NIL;
}
node_t s_append(node_t x, node_t y)
{
if (s_null(x)) return y;
else return cons(car(x), s_append(cdr(x), y));
}
node_t s_list(node_t x, node_t y)
{
return cons(x, cons(y, NULL));
}
node_t s_pair(node_t x, node_t y)
{
if (s_null(x) && s_null(y)) return NULL;
else if (!atom(x) && !atom(y))
return cons(s_list(car(x), car(y)),
s_pair(cdr(x), cdr(y)));
else return S_NIL;
}
node_t s_assoc(node_t x, node_t y)
{
if (s_null(y)) return S_NIL;
else if (eq(caar(y), x)) return cadar(y);
else return s_assoc(x, cdr(y));
}
node_t evcon(node_t c, node_t a);
node_t evlis(node_t m, node_t a);
node_t s_eval(node_t e, node_t a)
{
if (eq(e, str_to_node("t"))) return S_T;
else if (eq(e, str_to_node("nil"))) return S_NIL;
else if (atom(e)) return s_assoc(e, a);
else if (atom(car(e))) {
if (eq(car(e), str_to_node("quote"))) return cadr(e);
else if (eq(car(e), str_to_node("atom")))
if (atom(s_eval(cadr(e), a))) return S_T;
else return S_NIL;
else if (eq(car(e), str_to_node("eq")))
if (eq(s_eval(cadr(e), a), s_eval(caddr(e), a))) return S_T;
else return S_NIL;
else if (eq(car(e), str_to_node("car"))) return car( s_eval(cadr(e), a));
else if (eq(car(e), str_to_node("cdr"))) return cdr( s_eval(cadr(e), a));
else if (eq(car(e), str_to_node("cons"))) return cons(s_eval(cadr(e), a),
s_eval(caddr(e), a));
else if (eq(car(e), str_to_node("cond"))) return evcon(cdr(e), a);
else return s_eval(cons(s_assoc(car(e), a), cdr(e)), a);
} else if (eq(caar(e), str_to_node("lambda"))) {
return s_eval(caddar(e),
s_append(s_pair(cadar(e), evlis(cdr(e), a)), a));
} else {
return S_NIL;
}
}
node_t evcon(node_t c, node_t a)
{
if (s_eval(caar(c), a)) return s_eval(cadar(c), a);
else return evcon(cdr(c), a);
}
node_t evlis(node_t m, node_t a)
{
if (s_null(m)) return NULL;
else return cons(s_eval(car(m), a), evlis(cdr(m), a));
}
char s_eval_retval[SSTR_MAX];
void s_output(node_t s);
void s_strcons(node_t s)
{
s_output(car(s));
node_t sd = cdr(s);
if (sd == NULL) {
} else if (n_strg(sd)) {
strcat(s_eval_retval, " . ");
strcat(s_eval_retval, node_to_str(sd));
} else {
strcat(s_eval_retval, " ");
s_strcons(sd);
}
}
void s_output(node_t s)
{
if (s == S_NIL) {
strcat(s_eval_retval, "()");
} else if (n_strg(s)) {
strcat(s_eval_retval, node_to_str(s));
} else {
strcat(s_eval_retval, "(");
s_strcons(s);
strcat(s_eval_retval, ")");
}
}
void s_eval_string(char *s)
{
char *lr_s[SSTR_MAX];
int s_len;
s_len = s_lex(s, lr_s) - 1;
node_t rs = s_syn(lr_s, &s_len);
node_t r = s_eval(rs, S_NIL);
s_eval_retval[0] = '\0';
s_output(r);
}
#ifndef JMC
int main(void)
{
s_eval_string(
"(car (cdr '(10 20 30)))"
);
printf("%s\n", s_eval_retval);
s_eval_string(
"((lambda (x) (car (cdr x))) '(abc def ghi))"
);
printf("%s\n", s_eval_retval);
s_eval_string(
"((lambda (func x y) (func x (func y '()))) \
'cons '10 '20)"
);
printf("%s\n", s_eval_retval);
s_eval_string(
"((lambda (func x y) (func x (func y '()))) \
'(lambda (x y) (cons x (cons y '()))) \
'10 '20)"
);
printf("%s\n", s_eval_retval);
s_eval_string(
"((lambda (assoc k v) (cdr (assoc k v))) \
'(lambda (k v) \
(cond ((eq v '()) nil) \
((eq (car (car v)) k) \
(car v)) \
('t (assoc k (cdr v))))) \
'Orange \
'((Apple . 120) (Orange . 210) (Lemon . 180)))"
);
printf("%s\n", s_eval_retval);
return (0);
}
#endif