main jeefle/potoo / forsp / forsp.c
  1#include <stdio.h>
  2#include <stdlib.h>
  3#include <string.h>
  4
  5#define DBGS(s) printf("DBG LINE %d: %s\n", __LINE__, s)
  6#define DBGF(n) printf("DBG LINE %d: %f\n", __LINE__, n)
  7#define DBGN(n) printf("DBG LINE %d: %d\n", __LINE__, n)
  8
  9struct Cons;
 10
 11typedef struct Expr {
 12  enum {T_NMBR, T_PRIM, T_CONS, T_SYMB, T_NIL} tag;
 13  union {
 14	double number;
 15	char* symbol;
 16	struct Cons* cons;
 17	//rest of fn( prog, stack, binds )
 18	struct Expr (*fn)(struct Expr, struct Expr, struct Expr*);
 19  } value;
 20} Expr;
 21
 22typedef struct Cons {
 23  Expr car;
 24  Expr cdr;
 25} Cons;
 26
 27Cons* cons(Expr car, Expr cdr) {
 28  Cons* c = malloc(sizeof(Cons));
 29  c->car = car;
 30  c->cdr = cdr;
 31  return c;
 32}
 33
 34#define DELIMS " \n\t"
 35
 36char* getnext() {
 37  char* next = strtok(NULL, DELIMS);
 38  if (next == NULL) {
 39	printf("Unexpected EOF");
 40  }
 41  return next;
 42}
 43
 44int isnum(char* tok) {
 45  return (strspn(tok, "0123456789") == strlen(tok));
 46}
 47
 48void makesymb(Expr* e, char* tok) {
 49  e->tag = T_SYMB;
 50  int toklen = strlen(tok);
 51  e->value.symbol = malloc((toklen + 1) * sizeof(char));
 52  strcpy(e->value.symbol, tok);
 53}
 54
 55void makenum(Expr* e, double f) {
 56  e->tag = T_NMBR;
 57  e->value.number = f;
 58}
 59
 60void makecons(Expr* e, Expr car, Expr cdr) {
 61  e->value.cons = cons(car, cdr);
 62  e->tag = T_CONS;
 63}
 64
 65void parseatom(Expr* e, char* tok) {
 66  if (isnum(tok)) {
 67	return makenum(e, atof(tok));
 68  }
 69  return makesymb(e, tok);
 70}
 71
 72void parselist(Expr*);
 73
 74void parsetok(Expr* e, char* tok) {
 75  if (strcmp(tok, ")") == 0) {
 76	exit(1);
 77  }
 78  if (strcmp(tok, "(") == 0) {
 79	return parselist(e);
 80  }
 81  return parseatom(e, tok);
 82}
 83
 84void parselist(Expr* e) {
 85  char* tok;
 86  tok = getnext();
 87  if (strcmp(tok, ")") == 0) {
 88	e->tag = T_NIL;
 89	return;
 90  }
 91  if (strcmp(tok, ".") == 0) {
 92	tok = getnext();
 93	parsetok(e, tok);
 94	tok = getnext();
 95	if (strcmp(tok, ")") != 0) {
 96	  exit(1);
 97	}
 98	return;
 99  }
100  Expr head;
101  parsetok(&head, tok);
102  Expr tail;
103  parselist(&tail);
104  makecons(e, head, tail);
105}
106
107struct Expr parse(char* progstr) {
108  int proglen = strlen(progstr);
109  char* prog = malloc(sizeof(char) * (proglen + 1));
110  strcpy(prog, progstr);
111  char* tok;
112  tok = strtok(prog, DELIMS);
113  Expr r;
114  parsetok(&r, tok);
115  free(prog);
116  return r;
117}
118
119void printexp(Expr);
120
121void printlist(Expr e) {
122  Expr car = e.value.cons->car;
123  Expr cdr = e.value.cons->cdr;
124  printexp(car);
125  printf(" ");
126  if (cdr.tag == T_CONS) {
127	printlist(cdr);
128	return;
129  }
130  if (cdr.tag == T_NIL) {
131	printf(")");
132	return;
133  }
134  printf(". ");
135  printexp(cdr);
136  printf(")");
137}
138
139void printexp(Expr e) {
140  switch (e.tag) {
141  case T_NMBR:
142	printf("%f", e.value.number);
143	break;
144  case T_SYMB:
145	printf("%s", e.value.symbol);
146	break;
147  case T_NIL:
148	printf("()");
149	break;
150  case T_CONS:
151	printf("( ");
152	printlist(e);
153	break;
154  case T_PRIM:
155	printf("PRIMITIVE");
156	break;
157  }
158}
159
160void freeexpr(Expr* tofree) {
161  if (tofree->tag == T_CONS) {
162	freeexpr(&(tofree->value.cons->car));
163	Expr cdr = tofree->value.cons->cdr;
164	free(tofree->value.cons);
165	return freeexpr(&cdr);
166  }
167  if (tofree->tag == T_SYMB) {
168	free(tofree->value.symbol);
169  }
170}
171
172void dup(Expr* into, Expr* e) {
173  switch (e->tag) {
174  case T_SYMB:
175	return makesymb(into, e->value.symbol);
176	break;
177  case T_CONS:
178	Expr car;
179	Expr cdr;
180	makecons(into, car, cdr);
181	dup(&(into->value.cons->car), &(e->value.cons->car));
182	// We make the recursive call on the cdr for lists
183	return dup(&(into->value.cons->cdr), &(e->value.cons->cdr));
184	break;
185  case T_NIL:
186	into->tag = T_NIL;
187	return;
188	break;
189  }
190  into->tag = e->tag;
191  into->value = e->value;
192}
193
194// Checks if two expressions are equal, Non recursive
195int expsequal(Expr* e1, Expr* e2) {
196  if (e1->tag != e2->tag) {return 0;}
197  switch (e1->tag) {
198  case T_SYMB:
199	return strcmp(e1->value.symbol, e2->value.symbol) == 0;
200  case T_NMBR:
201	return e1->value.number == e2->value.number;
202  case T_CONS:
203	return e1->value.cons == e2->value.cons;
204  }
205  return 0;
206}
207
208// Adds a bind onto the list, returns pointer to the new list
209void makebind(Expr* newbinds, char* sym, Expr value, Expr binds) {
210  Expr symb;
211  Expr bind;
212  makesymb(&symb, sym);
213  makecons(&bind, symb, value);
214  makecons(newbinds, bind, binds);
215}
216
217Expr* findbind(char* sym, Expr* binds) {
218  if (binds == NULL) {
219	return NULL;
220  }
221  if (strcmp(binds->value.cons->car.value.cons->car.value.symbol, sym) == 0) {
222	return &(binds->value.cons->car.value.cons->cdr);
223  }
224  return findbind(sym, &(binds->value.cons->cdr));
225}
226
227void evalatom(Expr* val, Expr* binds) {
228  if (val->tag == T_SYMB) {
229	dup(val, findbind(val->value.symbol, binds));
230	return;
231  }
232}
233
234void uncons(Expr* car, Expr* cdr, Expr pair) {
235  *car = pair.value.cons->car;
236  *cdr = pair.value.cons->cdr;
237  free(pair.value.cons);
238}
239
240Expr evallist(Expr val, Expr stack, Expr* binds) {
241  if (val.tag == T_NIL) {return stack;}
242  Expr head;
243  Expr tail;
244  uncons(&head, &tail, val);
245  DBGS("CURRENT EVAL:");
246  printexp(head);
247  printf("\n");
248  evalatom(&head, binds);
249  if (head.tag == T_PRIM) {
250	return head.value.fn(tail, stack, binds);
251  }
252  Expr newstack;
253  makecons(&newstack, head, stack);
254  return evallist(tail, newstack, binds);
255}
256
257void popstack(Expr* top, Expr* stack) {
258  *top = stack->value.cons->car;
259  Expr cdr = stack->value.cons->cdr;
260  free(stack->value.cons);
261  *stack = cdr;
262}
263
264void pushstack(Expr val, Expr* stack) {
265  Expr newstack;
266  makecons(&newstack, val, *stack);
267  *stack = newstack;
268}
269
270// Builtins
271
272Expr add2(Expr prog, Expr stack, Expr* binds) {
273  Expr arg1;
274  Expr arg2;
275  popstack(&arg1, &stack);
276  popstack(&arg2, &stack);
277  Expr res;
278  makenum(&res, arg1.value.number + arg2.value.number);
279  pushstack(res, &stack);
280  return evallist(prog, stack, binds);
281}
282
283Expr execmacro(Expr prog, Expr stack, Expr* binds) {
284  Expr macro;
285  popstack(&macro, &stack);
286  pushstack(prog, &stack);
287  return evallist(macro, stack, binds);
288}
289
290Expr unconsbuiltin(Expr prog, Expr stack, Expr* binds) {
291  Expr arg1;
292  popstack(&arg1, &stack);
293  Expr car;
294  Expr cdr;
295  uncons(&car, &cdr, arg1);
296  pushstack(cdr, &stack);
297  pushstack(car, &stack);
298  return evallist(prog, stack, binds);
299}
300
301Expr bindbuiltin(Expr prog, Expr stack, Expr* binds) {
302  Expr tobind;
303  Expr sym;
304  Expr restprog;
305  popstack(&tobind, &stack);
306  uncons(&sym, &restprog, prog);
307  makebind(binds, sym.value.symbol, tobind, *binds);
308  return evallist(restprog, stack, binds);
309}
310
311Expr evalbuiltin(Expr prog, Expr stack, Expr* binds) {
312  Expr top;
313  popstack(&top, &stack);
314  Expr newbinds;
315  dup(&newbinds, binds);
316  Expr nstack = evallist(top, stack, &newbinds);
317  freeexpr(&newbinds);
318  return evallist(prog, nstack, binds);
319}
320
321// End Builtins
322
323Expr createpriminst(Expr (*prim)(Expr, Expr, Expr*)) {
324  Expr p;
325  p.tag = T_PRIM;
326  p.value.fn = prim;
327  return p;
328}
329
330void makebase(Expr* binds) {
331  makebind(binds, "+", createpriminst(add2), *binds);
332  makebind(binds, ",", createpriminst(evalbuiltin), *binds);
333  makebind(binds, "$", createpriminst(bindbuiltin), *binds);
334  makebind(binds, "uncons", createpriminst(unconsbuiltin), *binds);
335  makebind(binds, "execmacro", createpriminst(execmacro), *binds);
336}
337
338Expr evalprog(char* progstr) {
339  Expr p = parse(progstr);
340  DBGS("Finished Parsing");
341  Expr binds;
342  binds.tag = T_NIL;
343  makebase(&binds);
344  DBGS("Finished Making Binds");
345  printexp(binds);
346  printf("\n");
347  DBGS("Now Evaluating Prog");
348  Expr s;
349  s.tag = T_NIL;
350  Expr e = evallist(p, s, &binds);
351  return e;
352}
353
354int main() {
355  Expr s = evalprog("( ( $ x $ y y x ) $ swap ( uncons , ) execmacro x )");
356  printf("Result: ");
357  printexp(s);
358}