Jared DiCarlo
/
manworm_tv_gpu
asdf
Fork of manworm_ticker_tv by
lisp.cpp
- Committer:
- dicarloj
- Date:
- 2018-05-04
- Revision:
- 12:e99cc1e9d928
- Parent:
- 10:1163fb31b0a7
File content as of revision 12:e99cc1e9d928:
/* A minimal Lisp interpreter Copyright 2004 Andru Luvisi This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License , or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <ctype.h> #include "main.h" #define error(X) do { printf("ERROR: %s\n", X); } while (0) #define out_buf_size 5000 #define in_buf_size 5000 int out_counter = 0; int in_counter = 0; char out_buf[out_buf_size]; char in_buf [in_buf_size]; char lisp_exit = 0; void init_buf() { for(int i = 0; i < out_buf_size; i++) out_buf[i] = 0; for(int i = 0; i < in_buf_size; i++) in_buf[i] = 0; out_buf[out_buf_size - 1] = 0; out_counter = 0; in_counter = 0; } char getc_2() { //draw_vincent_string("getc2"); in_counter++; if(in_counter >= in_buf_size) { lisp_exit = 1; return EOF; } char next_char = in_buf[in_counter - 1]; if(next_char == 0) { lisp_exit = 1; return EOF; } return in_buf[in_counter-1]; } void ungetc_2(char c) { in_counter--; } char* strdup_2(char* in) { char* new_string = (char*)malloc(strlen(in)); strcpy(new_string,in); return new_string; } void write_out(char* str) { printf("write_out: %s\n",str); int len = strlen(str); if(len + out_counter < out_buf_size) { printf("BUUFER OVERLFOW!\n"); return; } memcpy(out_buf + out_counter, str, len); } int line_num = 1; int total_malloc = 0; /*** List Structured Memory ***/ enum otype { INT, SYM, CONS, PROC, PRIMOP }; typedef struct obj { enum otype type; int line_num; struct obj *p[1]; } obj; typedef obj * (*primop)(obj *); obj *all_symbols, *top_env, *nil, *tee, *quote, *s_if, *s_lambda, *s_define, *s_setb, *s_begin; #define cons(X, Y) omake(CONS, 2, (X), (Y)) obj *car(obj *X) { if(X == 0) { sprintf(out_buf + strlen(out_buf),"warning: car argument null on line %d\n", line_num); return nil; } if(X == nil) return nil; if(X->type != CONS) { sprintf(out_buf + strlen(out_buf),"warning: car argument not a list (%d) on line %d\n", X->p[0], X->line_num); return nil; } return X->p[0]; } obj *cdr(obj *X) { if(X == nil) return nil; if(X->type != CONS) { sprintf(out_buf + strlen(out_buf),"warning: cdr argument not a list on line %d\n", X->line_num); return nil; } if(X->p[1] == 0) { sprintf(out_buf + strlen(out_buf),"error: cdr list element is zero-pointer at %d\n", X->line_num); return nil; } return X->p[1]; } #define setcar(X,Y) (((X)->p[0]) = (Y)) #define setcdr(X,Y) (((X)->p[1]) = (Y)) #define mkint(X) omake(INT, 1, (obj *)(X)) #define intval(X) ((int)((X)->type == INT ? (X)->p[0] : 0)) // intval for INT only #define mksym(X) omake(SYM, 1, (obj *)(X)) #define symname(X) ((char *)((X)->p[0])) #define mkprimop(X) omake(PRIMOP, 1, (obj *)(X)) #define primopval(X) ((primop)(X)->p[0]) #define mkproc(X,Y,Z) omake(PROC, 3, (X), (Y), (Z)) #define procargs(X) ((X)->p[0]) #define proccode(X) ((X)->p[1]) #define procenv(X) ((X)->p[2]) #define isnil(X) ((X) == nil) obj *omake(enum otype type, int count, ...) { obj *ret; va_list ap; int i; va_start(ap, count); int object_size = sizeof(obj) + (count - 1)*sizeof(obj *); total_malloc += object_size; if(type == INT) printf("malloc %d bytes for INT\r\n",object_size); if(type == SYM) printf("malloc %d bytes for SYM\r\n",object_size); if(type == CONS) printf("malloc %d bytes for CONS\r\n",object_size); if(type == SYM) printf("malloc %d bytes for PROC\r\n",object_size); if(type == PRIMOP) printf("malloc %d bytes for PRIMOP\r\n",object_size); //enum otype { INT, SYM, CONS, PROC, PRIMOP }; ret = (obj *) malloc(object_size); ret->type = type; ret->line_num = line_num; for(i = 0; i < count; i++) ret->p[i] = va_arg(ap, obj *); va_end(ap); return ret; } obj *findsym(char *name) { obj *symlist; for(symlist = all_symbols; !isnil(symlist); symlist = cdr(symlist)) if(!strcmp(name, symname(car(symlist)))) return symlist; return nil; } obj *intern(char *name) { obj *op = findsym(name); if(!isnil(op)) return car(op); op = mksym(name); all_symbols = cons(op, all_symbols); return op; } /*** Environment ***/ #define extend(ENV, SYM, VAL) (cons(cons((SYM), (VAL)), (ENV))) obj *multiple_extend(obj *env, obj *syms, obj *vals) { return isnil(syms) ? env : multiple_extend(extend(env, car(syms), car(vals)), cdr(syms), cdr(vals)); } obj *extend_top(obj *sym, obj *val) { setcdr(top_env, cons(cons(sym, val), cdr(top_env))); return val; } obj *assoc(obj *key, obj *alist) { if(isnil(alist)) return nil; if(car(car(alist)) == key) return car(alist); return assoc(key, cdr(alist)); } /*** Input/Output ***/ //FILE *ifp; char *token_la; int la_valid = 0; #define MAXLEN 100 char buf[MAXLEN]; int bufused; void add_to_buf(char ch) { if(bufused < MAXLEN - 1) buf[bufused++] = ch; } char *buf2str() { buf[bufused++] = '\0'; return strdup_2(buf); } //void setinput(FILE *fp) { ifp = fp; } void putback_token(char *token) { token_la = token; la_valid = 1; } void myexit(int code); char *gettoken() { int ch; char comment=0; bufused = 0; if(la_valid) { la_valid = 0; return token_la; } do { if((ch = getc_2()) == EOF) {myexit(0); return NULL;} // replace with serial //draw_vincent_string("gettoken"); if(ch == ';') comment = 1; if(ch == '\n') { comment = 0; line_num++; } } while(isspace(ch) || comment); add_to_buf(ch); if(strchr("()\'", ch)) return buf2str(); for(;;) { if(lisp_exit) { return NULL; } if((ch = getc_2()) == EOF) {myexit(0); return NULL;} if(strchr("()\'", ch) || isspace(ch)) { ungetc_2(ch); return buf2str(); } add_to_buf(ch); } } obj *readlist(); obj *readobj() { char *token; token = gettoken(); if(token == NULL) return NULL; if(!strcmp(token, "(")) return readlist(); if(!strcmp(token, "\'")) return cons(quote, cons(readobj(), nil)); if(token[strspn(token, "0123456789")] == '\0' || (token[0] == '-' && strlen(token) > 1)) return mkint(atoi(token)); return intern(token); } obj *readlist() { char *token = gettoken(); if(token == NULL) return NULL; obj *tmp; if(!strcmp(token, ")")) return nil; if(!strcmp(token, ".")) { tmp = readobj(); if(strcmp(gettoken(), ")")) myexit(1); return tmp; } putback_token(token); tmp = readobj(); /* Must force evaluation order */ return cons(tmp, readlist()); } void writeobj(obj *op) { if(op == NULL) { return; } switch(op->type) { case INT: sprintf(out_buf + strlen(out_buf),"%d", intval(op)); break; case CONS: //draw_vincent_string(" write_cons "); sprintf(out_buf + strlen(out_buf),"("); for(;;) { writeobj(car(op)); if(isnil(cdr(op))) { sprintf(out_buf + strlen(out_buf),")"); break; } op = cdr(op); if(op->type != CONS) { sprintf(out_buf + strlen(out_buf)," . "); writeobj(op); sprintf(out_buf + strlen(out_buf),")"); break; } sprintf(out_buf + strlen(out_buf)," "); } break; case SYM: if(isnil(op)) sprintf(out_buf + strlen(out_buf),"()"); else sprintf(out_buf + strlen(out_buf),"%s", symname(op)); break; case PRIMOP: sprintf(out_buf + strlen(out_buf),"#<PRIMOP>"); break; case PROC: sprintf(out_buf + strlen(out_buf),"#<PROC>"); break; default: myexit(1); } } /*** Evaluator (Eval/no Apply) ***/ obj *evlis(obj *exps, obj *env); obj *eval(obj *exp, obj *env) { if(lisp_exit) return NULL; obj *tmp, *proc, *vals; eval_start: if(exp == NULL) return nil; if(exp == nil) return nil; switch(exp->type) { case INT: return exp; case SYM: tmp = assoc(exp, env); if(tmp == nil) { sprintf(out_buf + strlen(out_buf), "Unbound symbol "); writeobj(exp); sprintf(out_buf + strlen(out_buf), "\n"); return nil; } return cdr(tmp); case CONS: if(car(exp) == s_if) { if(eval(car(cdr(exp)), env) != nil) return eval(car(cdr(cdr(exp))), env); else return eval(car(cdr(cdr(cdr(exp)))), env); } if(car(exp) == s_lambda) return mkproc(car(cdr(exp)), cdr(cdr(exp)), env); if(car(exp) == quote) return car(cdr(exp)); if(car(exp) == s_define) return(extend_top(car(cdr(exp)), eval(car(cdr(cdr(exp))), env))); if(car(exp) == s_setb) { obj *pair = assoc(car(cdr(exp)), env); obj *newval = eval(car(cdr(cdr(exp))), env); setcdr(pair, newval); return newval; } if(car(exp) == s_begin) { exp = cdr(exp); if(exp == nil) return nil; for(;;) { if(cdr(exp) == nil) { exp = car(exp); goto eval_start; } eval(car(exp), env); exp = cdr(exp); } } proc = eval(car(exp), env); vals = evlis(cdr(exp), env); if(proc->type == PRIMOP) return (*primopval(proc))(vals); if(proc->type == PROC) { /* For dynamic scope, use env instead of procenv(proc) */ env = multiple_extend(procenv(proc), procargs(proc), vals); exp = cons(s_begin, proccode(proc)); goto eval_start; } sprintf(out_buf + strlen(out_buf),"Bad PROC type\n"); return nil; case PRIMOP: return exp; case PROC: return exp; } /* Not reached */ return exp; } obj *evlis(obj *exps, obj *env) { if(exps == nil) return nil; return cons(eval(car(exps), env), evlis(cdr(exps), env)); } /*** Primitives ***/ obj *prim_sum(obj *args) { int sum; for(sum = 0; !isnil(args); sum += intval(car(args)), args = cdr(args)); return mkint(sum); } obj *prim_sub(obj *args) { int sum; for(sum = intval(car(args)), args = cdr(args); !isnil(args); sum -= intval(car(args)), args = cdr(args)); return mkint(sum); } obj *prim_prod(obj *args) { int prod; for(prod = 1; !isnil(args); prod *= intval(car(args)), args = cdr(args)); return mkint(prod); } obj *prim_divide(obj *args) { int prod = intval(car(args)); args = cdr(args); while(!isnil(args)) { prod /= intval(car(args)); args = cdr(args); } return mkint(prod); } obj *prim_gt(obj *args) { return intval(car(args)) > intval(car(cdr(args))) ? tee : nil; } obj *prim_lt(obj *args) { return intval(car(args)) < intval(car(cdr(args))) ? tee : nil; } obj *prim_ge(obj *args) { return intval(car(args)) >= intval(car(cdr(args))) ? tee : nil; } obj *prim_le(obj *args) { return intval(car(args)) <= intval(car(cdr(args))) ? tee : nil; } obj *prim_numeq(obj *args) { return intval(car(args)) == intval(car(cdr(args))) ? tee : nil; } obj *prim_cons(obj *args) { return cons(car(args), car(cdr(args))); } obj *prim_car(obj *args) { return car(car(args)); } obj *prim_cdr(obj *args) { return cdr(car(args)); } /*** Helpers *****/ obj *prim_print(obj *args) { while(!isnil(args)) { writeobj(car(args)); args = cdr(args); sprintf(out_buf + strlen(out_buf)," "); } sprintf(out_buf + strlen(out_buf),"\n"); return nil; } /*** Initialization ***/ void init_sl3() { nil = mksym("nil"); all_symbols = cons(nil, nil); top_env = cons(cons(nil, nil), nil); tee = intern("t"); extend_top(tee, tee); quote = intern("quote"); s_if = intern("if"); s_lambda = intern("lambda"); s_define = intern("define"); s_setb = intern("set!"); s_begin = intern("begin"); extend_top(intern("+"), mkprimop(prim_sum)); extend_top(intern("-"), mkprimop(prim_sub)); extend_top(intern("*"), mkprimop(prim_prod)); extend_top(intern("/"), mkprimop(prim_divide)); extend_top(intern("="), mkprimop(prim_numeq)); extend_top(intern(">"), mkprimop(prim_gt)); extend_top(intern(">="), mkprimop(prim_ge)); extend_top(intern("<"), mkprimop(prim_lt)); extend_top(intern("<="), mkprimop(prim_le)); extend_top(intern("cons"), mkprimop(prim_cons)); extend_top(intern("car"), mkprimop(prim_car)); extend_top(intern("cdr"), mkprimop(prim_cdr)); extend_top(intern("print"), mkprimop(prim_print)); } char* get_output() { return out_buf; } int lisp_init = 0; /*** Main Driver ***/ int run_lisp(char* input) { if(!lisp_init) { init_sl3(); lisp_init = 1; } init_buf(); lisp_exit = 0; strcpy(in_buf, input); if(!strncmp(input,"clear",4)){ clear_all_text(); return 0; } if(!strncmp(input,"mem",3)) { char memuse[40]; sprintf(memuse,"MEM: %d bytes",total_malloc); draw_vincent_string(memuse); return; } in_buf[in_buf_size - 1] = 0; //new_line(); //draw_vincent_string(in_buf); //new_line(); //print_vincent_string(in_buf); // if(argc == 2) // { // memcpy(in_buf,argv[1],strlen(argv[1])); // printf("%s\n",in_buf); // } // else //sprintf(in_buf,"(+ 2 2)\n"); // char test_in[] = "(+ 2 2)\n"; // FILE* input_stream = open_memstream(test_in,8); // fprintf(input_stream,"(+ 2 3)\n"); // char test_out[50]; // FILE* output_stream = fmemopen(test_out,50,"w"); //setinput(input_stream); int lisp_count = 0; while(!lisp_exit) { writeobj(eval(readobj(), top_env)); //fflush(output_stream); printf("\n"); printf("%s\n",out_buf); lisp_count++; if(lisp_count > 500) break; //printf("outstream: %s\n",test_out); } draw_vincent_string(out_buf); //draw_vincent_string("done!"); return 0; } void myexit(int code) { printf("%d bytes left hanging\n", total_malloc); lisp_exit = 1; }