diff --git a/Makefile b/Makefile index c3395692..ba871a28 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ test: $(TESTFILES) cyclone # A temporary testing directive .PHONY: test2 -test2: examples/hello-library/int-test/hello.c +test2: examples/hello-library/int-test/hello.c libcyclone.a # ./cyclone -t examples/hello-library/hello.scm # ./cyclone -t examples/hello-library/libs/lib2.sld # gcc examples/hello-library/int-test/lib2.c -I. -g -c -o lib2.o diff --git a/runtime-main.h b/runtime-main.h index 297e42d6..c3bff183 100644 --- a/runtime-main.h +++ b/runtime-main.h @@ -11,6 +11,9 @@ #include "cyclone.h" +long global_stack_size = 0; +long global_heap_size = 0; + static long long_arg(int argc,char **argv,char *name,long dval); static void c_entry_pt(int,closure,closure); static void main_main(long stack_size,long heap_size,char *stack_base) never_returns; diff --git a/runtime.c b/runtime.c index 6e35dc9f..a9eb94cc 100644 --- a/runtime.c +++ b/runtime.c @@ -1,5 +1,981 @@ #include "cyclone.h" +object Cyc_global_variables = nil; + +static symbol_type __EOF = {eof_tag, "", nil}; // symbol_type in lieu of custom type +const object Cyc_EOF = &__EOF; + +object cell_get(object cell){ + return car(cell); +} + +/* Symbol Table */ + +/* Notes for the symbol table + + string->symbol can: + - lookup symbol in the table + - if found, return that pointer + - otherwise, allocate symbol in table and return ptr to it + + For now, GC of symbols is missing. long-term it probably would be desirable +*/ +list symbol_table = nil; + +char *_strdup (const char *s) { + char *d = malloc (strlen (s) + 1); + if (d) { strcpy (d,s); } + return d; +} + +object find_symbol_by_name(const char *name) { + list l = symbol_table; + for (; !nullp(l); l = cdr(l)) { + const char *str = symbol_pname(car(l)); + if (strcmp(str, name) == 0) return car(l); + } + return nil; +} + +object add_symbol(symbol_type *psym) { + symbol_table = mcons(psym, symbol_table); + return psym; +} + +object add_symbol_by_name(const char *name) { + symbol_type sym = {symbol_tag, _strdup(name), nil}; + symbol_type *psym = malloc(sizeof(symbol_type)); + memcpy(psym, &sym, sizeof(symbol_type)); + return add_symbol(psym); +} + +object find_or_add_symbol(const char *name){ + object sym = find_symbol_by_name(name); + if (sym){ + return sym; + } else { + return add_symbol_by_name(name); + } +} +/* END symbol table */ + +/* Mutation table + * + * Keep track of mutations (EG: set-car!) so that new + * values are transported to the heap during GC. + */ +list mutation_table = nil; + +void add_mutation(object var, object value){ + if (is_object_type(value)) { + mutation_table = mcons(var, mutation_table); + } +} + +/* TODO: consider a more efficient implementation, such as reusing old nodes + instead of reclaiming them each time + */ +void clear_mutations() { + list l = mutation_table, next; + while (!nullp(l)) { + next = cdr(l); + free(l); + l = next; + } + mutation_table = nil; +} +/* END mutation table */ + +object terpri() {printf("\n"); return nil;} + +int equal(x, y) object x, y; +{ + if (nullp(x)) return nullp(y); + if (nullp(y)) return nullp(x); + if (obj_is_char(x)) return obj_is_char(y) && x == y; + switch(type_of(x)) { + case integer_tag: + return (type_of(y) == integer_tag && + ((integer_type *) x)->value == ((integer_type *) y)->value); + case double_tag: + return (type_of(y) == double_tag && + ((double_type *) x)->value == ((double_type *) y)->value); + case string_tag: + return (type_of(y) == string_tag && + strcmp(((string_type *) x)->str, + ((string_type *) y)->str) == 0); + default: + return x == y; + } +} + +object Cyc_get_global_variables(){ + return Cyc_global_variables; +} + +object Cyc_get_cvar(object var) { + if (is_object_type(var) && type_of(var) == cvar_tag) { + return *(((cvar_type *)var)->pvar); + } + return var; +} + +object Cyc_set_cvar(object var, object value) { + if (is_object_type(var) && type_of(var) == cvar_tag) { + *(((cvar_type *)var)->pvar) = value; + } + return var;} + +object Cyc_has_cycle(object lst) { + object slow_lst, fast_lst; + int is_obj = is_object_type(lst); + int type = type_of(lst); + if (nullp(lst) || is_value_type(lst) || + (is_object_type(lst) && type_of(lst) != cons_tag)) { + return (boolean_f); + } + slow_lst = lst; + fast_lst = cdr(lst); + while(1) { + if (nullp(fast_lst)) return boolean_f; + if (Cyc_is_cons(fast_lst) == boolean_f) return boolean_f; + if (nullp(cdr(fast_lst))) return boolean_f; + if (Cyc_is_cons(cdr(fast_lst)) == boolean_f) return boolean_f; + if (is_object_type(car(slow_lst)) && + boolean_f == Cyc_is_boolean(car(slow_lst)) && // Avoid expected dupes + //boolean_f == Cyc_is_symbol(car(slow_lst)) && // + eq(car(slow_lst), car(fast_lst))) return boolean_t; + + slow_lst = cdr(slow_lst); + fast_lst = cddr(fast_lst); + } +} + +object Cyc_display(x) object x; +{object tmp = nil; + object has_cycle = boolean_f; + int i = 0; + if (nullp(x)) {printf("()"); return x;} + if (obj_is_char(x)) {printf("%c", obj_obj2char(x)); return x;} + switch (type_of(x)) + {case closure0_tag: + case closure1_tag: + case closure2_tag: + case closure3_tag: + case closure4_tag: + case closureN_tag: + printf("",(void *)((closure) x)->fn); + break; + case eof_tag: + printf(""); + break; + case port_tag: + printf(""); + break; + case primitive_tag: + printf("", prim_name(x)); + break; + case cvar_tag: + Cyc_display(Cyc_get_cvar(x)); + break; + case boolean_tag: + printf("#%s",((boolean_type *) x)->pname); + break; + case symbol_tag: + printf("%s",((symbol_type *) x)->pname); + break; + case integer_tag: + printf("%d", ((integer_type *) x)->value); + break; + case double_tag: + printf("%lf", ((double_type *) x)->value); + break; + case string_tag: + printf("%s", ((string_type *) x)->str); + break; + case cons_tag: + has_cycle = Cyc_has_cycle(x); + printf("("); + Cyc_display(car(x)); + + // Experimenting with displaying lambda defs in REPL + // not good enough but this is a start. would probably need + // the same code in write() + if (equal(quote_Cyc_191procedure, car(x))) { + printf(" "); + Cyc_display(cadr(x)); + printf(" ...)"); /* skip body and env for now */ + break; + } + + for (tmp = cdr(x); tmp && ((closure) tmp)->tag == cons_tag; tmp = cdr(tmp)) { + if (has_cycle == boolean_t) { + if (i++ > 20) break; /* arbitrary number, for now */ + } + printf(" "); + Cyc_display(car(tmp)); + } + if (has_cycle == boolean_t) { + printf(" ..."); + } else if (tmp) { + printf(" . "); + Cyc_display(tmp); + } + printf(")"); + break; + default: + printf("Cyc_display: bad tag x=%ld\n", ((closure)x)->tag); getchar(); exit(0);} + return x;} + +static object _Cyc_write(x) object x; +{object tmp = nil; + object has_cycle = boolean_f; + int i = 0; + if (nullp(x)) {printf("()"); return x;} + if (obj_is_char(x)) {printf("#\\%c", obj_obj2char(x)); return x;} + switch (type_of(x)) + {case string_tag: + printf("\"%s\"", ((string_type *) x)->str); + break; + // TODO: what about a list? contents should be displayed per (write) + case cons_tag: + has_cycle = Cyc_has_cycle(x); + printf("("); + _Cyc_write(car(x)); + + // Experimenting with displaying lambda defs in REPL + // not good enough but this is a start. would probably need + // the same code in write() + if (equal(quote_Cyc_191procedure, car(x))) { + printf(" "); + _Cyc_write(cadr(x)); + printf(" ...)"); /* skip body and env for now */ + break; + } + + for (tmp = cdr(x); tmp && ((closure) tmp)->tag == cons_tag; tmp = cdr(tmp)) { + if (has_cycle == boolean_t) { + if (i++ > 20) break; /* arbitrary number, for now */ + } + printf(" "); + _Cyc_write(car(tmp)); + } + if (has_cycle == boolean_t) { + printf(" ..."); + } else if (tmp) { + printf(" . "); + _Cyc_write(tmp); + } + printf(")"); + break; + default: + Cyc_display(x);} + return x;} + +object Cyc_write(x) object x; +{object y = _Cyc_write(x); + printf("\n"); + return y;} + +/* Some of these non-consing functions have been optimized from CPS. */ + +// TODO: should not be a predicate, may end up moving these to Scheme code +object memberp(x,l) object x; list l; +{for (; !nullp(l); l = cdr(l)) if (boolean_f != equalp(x,car(l))) return boolean_t; + return boolean_f;} + +object memqp(x,l) object x; list l; +{for (; !nullp(l); l = cdr(l)) if (eq(x,car(l))) return boolean_t; + return boolean_f;} + +object get(x,i) object x,i; +{register object plist; register object plistd; + if (nullp(x)) return x; + if (type_of(x)!=symbol_tag) {printf("get: bad x=%ld\n",((closure)x)->tag); exit(0);} + plist = symbol_plist(x); + for (; !nullp(plist); plist = cdr(plistd)) + {plistd = cdr(plist); + if (eq(car(plist),i)) return car(plistd);} + return nil;} + +object equalp(x,y) object x,y; +{for (; ; x = cdr(x), y = cdr(y)) + {if (equal(x,y)) return boolean_t; + if (obj_is_char(x) || obj_is_char(y) || + nullp(x) || nullp(y) || + type_of(x)!=cons_tag || type_of(y)!=cons_tag) return boolean_f; + if (boolean_f == equalp(car(x),car(y))) return boolean_f;}} + +list assq(x,l) object x; list l; +{for (; !nullp(l); l = cdr(l)) + {register list la = car(l); if (eq(x,car(la))) return la;} + return boolean_f;} + +list assoc(x,l) object x; list l; +{for (; !nullp(l); l = cdr(l)) + {register list la = car(l); if (boolean_f != equalp(x,car(la))) return la;} + return boolean_f;} + + +// TODO: generate these using macros??? +object __num_eq(x, y) object x, y; +{if (x && y && ((integer_type *)x)->value == ((integer_type *)y)->value) + return boolean_t; + return boolean_f;} + +object __num_gt(x, y) object x, y; +{//printf("DEBUG cmp %d, x %d, y %d, x tag %d, y tag %d\n", + // (((integer_type *)x)->value > ((integer_type *)y)->value), + // ((integer_type *)x)->value, ((integer_type *)y)->value, + // ((list)x)->tag, ((list)y)->tag); + //exit(1); + if (((integer_type *)x)->value > ((integer_type *)y)->value) + return boolean_t; + return boolean_f;} + +object __num_lt(x, y) object x, y; +{if (((integer_type *)x)->value < ((integer_type *)y)->value) + return boolean_t; + return boolean_f;} + +object __num_gte(x, y) object x, y; +{if (((integer_type *)x)->value >= ((integer_type *)y)->value) + return boolean_t; + return boolean_f;} + +object __num_lte(x, y) object x, y; +{if (((integer_type *)x)->value <= ((integer_type *)y)->value) + return boolean_t; + return boolean_f;} + +// TODO: object Cyc_is_eq(x, y) object x, y) +object Cyc_is_boolean(object o){ + if (!nullp(o) && + !is_value_type(o) && + ((list)o)->tag == boolean_tag && + (eq(boolean_f, o) || eq(boolean_t, o))) + return boolean_t; + return boolean_f;} + +object Cyc_is_cons(object o){ + if (!nullp(o) && !is_value_type(o) && ((list)o)->tag == cons_tag) + return boolean_t; + return boolean_f;} + +object Cyc_is_null(object o){ + if (nullp(o)) + return boolean_t; + return boolean_f;} + +object Cyc_is_number(object o){ + if (!nullp(o) && !is_value_type(o) && + (type_of(o) == integer_tag || type_of(o) == double_tag)) + return boolean_t; + return boolean_f;} + +object Cyc_is_real(object o){ + return Cyc_is_number(o);} + +object Cyc_is_integer(object o){ + if (!nullp(o) && !is_value_type(o) && type_of(o) == integer_tag) + return boolean_t; + return boolean_f;} + +object Cyc_is_symbol(object o){ + if (!nullp(o) && !is_value_type(o) && ((list)o)->tag == symbol_tag) + return boolean_t; + return boolean_f;} + +object Cyc_is_string(object o){ + if (!nullp(o) && !is_value_type(o) && ((list)o)->tag == string_tag) + return boolean_t; + return boolean_f;} + +object Cyc_is_char(object o){ + if (obj_is_char(o)) + return boolean_t; + return boolean_f;} + +object Cyc_is_procedure(object o) { + int tag; + if (!nullp(o) && !is_value_type(o)) { + tag = type_of(o); + if (tag == closure0_tag || + tag == closure1_tag || + tag == closure2_tag || + tag == closure3_tag || + tag == closure4_tag || + tag == closureN_tag || + tag == primitive_tag) { + return boolean_t; + } + } + return boolean_f; +} + +object Cyc_is_eof_object(object o) { + if (!nullp(o) && !is_value_type(o) && type_of(o) == eof_tag) + return boolean_t; + return boolean_f;} + +object Cyc_is_cvar(object o) { + if (!nullp(o) && !is_value_type(o) && type_of(o) == cvar_tag) + return boolean_t; + return boolean_f;} + +object Cyc_eq(object x, object y) { + if (eq(x, y)) + return boolean_t; + return boolean_f; +} + +object Cyc_set_car(object l, object val) { + car(l) = val; + add_mutation(l, val); + return l; +} + +object Cyc_set_cdr(object l, object val) { + cdr(l) = val; + add_mutation(l, val); + return l; +} + +integer_type Cyc_length(object l){ + make_int(len, 0); + while(!nullp(l)){ + if (((list)l)->tag != cons_tag){ + printf("length - invalid parameter, expected list\n"); + exit(1); + } + l = cdr(l); + len.value++; + } + return len; +} + +string_type Cyc_number2string(object n) { + char buffer[1024]; + if (type_of(n) == integer_tag) { + snprintf(buffer, 1024, "%d", ((integer_type *)n)->value); + } else if (type_of(n) == double_tag) { + snprintf(buffer, 1024, "%lf", ((double_type *)n)->value); + } else { + buffer[0] = '\0'; // TODO: throw error instead + } + make_string(str, buffer); + return str; +} + +string_type Cyc_symbol2string(object sym) { + make_string(str, symbol_pname(sym)); + return str; +} + +object Cyc_string2symbol(object str) { + object sym = find_symbol_by_name(symbol_pname(str)); + if (!sym) { + sym = add_symbol_by_name(symbol_pname(str)); + } + return sym; +} + +string_type Cyc_list2string(object lst){ + char *buf; + int i = 0; + integer_type len = Cyc_length(lst); // Inefficient, walks whole list + buf = alloca(sizeof(char) * (len.value + 1)); + + while(!nullp(lst)){ + buf[i++] = obj_obj2char(car(lst)); + lst = cdr(lst); + } + buf[i] = '\0'; + + make_string(str, buf); + return str; +} + +#define string2list(c,s) object c = nil; { \ + char *str = ((string_type *)s)->str; \ + int len = strlen(str); \ + cons_type *buf; \ + if (len > 0) { \ + buf = alloca(sizeof(cons_type) * len); \ + __string2list(str, buf, len); \ + c = (object)&(buf[0]); \ + } \ +} + +void __string2list(const char *str, cons_type *buf, int buflen){ + int i = 0; + while (str[i]){ + buf[i].tag = cons_tag; + buf[i].cons_car = obj_char2obj(str[i]); + buf[i].cons_cdr = (i == buflen - 1) ? nil : buf + (i + 1); + i++; + } +} + +common_type Cyc_string2number(object str){ + common_type result; + double n; + if (type_of(str) == string_tag && + ((string_type *) str)->str){ + n = atof(((string_type *) str)->str); + + if (ceilf(n) == n) { + result.integer_t.tag = integer_tag; + result.integer_t.value = (int)n; + } + else { + result.double_t.tag = double_tag; + result.double_t.value = n; + } + } else { + // TODO: not good enough because we do pointer comparisons to #f + //result.boolean_t = boolean_f; + } + + return result; +} + +void dispatch_string_91append(int argc, object clo, object cont, object str1, ...) { + string_type result; + va_list ap; + va_start(ap, str1); + result = Cyc_string_append_va_list(argc - 1, str1, ap); + va_end(ap); + return_funcall1(cont, &result); +} + +string_type Cyc_string_append(int argc, object str1, ...) { + string_type result; + va_list ap; + va_start(ap, str1); + result = Cyc_string_append_va_list(argc, str1, ap); + va_end(ap); + return result; +} + +string_type Cyc_string_append_va_list(int argc, object str1, va_list ap) { + // TODO: one way to do this, perhaps not the most efficient: + // compute lengths of the strings, + // store lens and str ptrs + // allocate buffer, memcpy each str to buffer + // make_string using buffer + + int i = 0, total_len = 1; // for null char + int *len = alloca(sizeof(int) * argc); + char *buffer, *bufferp, **str = alloca(sizeof(char *) * argc); + object tmp; + + if (argc > 0) { + str[i] = ((string_type *)str1)->str; + len[i] = strlen(str[i]); + total_len += len[i]; + } + + for (i = 1; i < argc; i++) { + tmp = va_arg(ap, object); + str[i] = ((string_type *)tmp)->str; + len[i] = strlen(str[i]); + total_len += len[i]; + } + + buffer = bufferp = alloca(sizeof(char) * total_len); + for (i = 0; i < argc; i++) { + memcpy(bufferp, str[i], len[i]); + bufferp += len[i]; + } + *bufferp = '\0'; + make_string(result, buffer); + return result; +} + +integer_type Cyc_char2integer(object chr){ + make_int(n, obj_obj2char(chr)); + return n; +} + +object Cyc_integer2char(object n){ + int val = 0; + + if (!nullp(n)) { + val = ((integer_type *) n)->value; + } + + return obj_char2obj(val); +} + +void my_exit(closure) never_returns; +void my_exit(env) closure env; { +#if DEBUG_SHOW_DIAG + printf("my_exit: heap bytes allocated=%d time=%ld ticks no_gcs=%ld no_m_gcs=%ld\n", + allocp-bottom,clock()-start,no_gcs,no_major_gcs); + printf("my_exit: ticks/second=%ld\n",(long) CLOCKS_PER_SEC); +#endif + exit(0);} + +object __halt(object obj) { +#if DEBUG_SHOW_DIAG + printf("\nhalt: "); + Cyc_display(obj); + printf("\n"); +#endif + my_exit(obj); + return nil; +} + +#define declare_num_op(FUNC, FUNC_OP, FUNC_APPLY, OP) \ +common_type FUNC_OP(object x, object y) { \ + common_type s; \ + int tx = type_of(x), ty = type_of(y); \ + s.double_t.tag = double_tag; \ + if (tx == integer_tag && ty == integer_tag) { \ + s.integer_t.tag = integer_tag; \ + s.integer_t.value = ((integer_type *)x)->value OP ((integer_type *)y)->value; \ + } else if (tx == double_tag && ty == integer_tag) { \ + s.double_t.value = ((double_type *)x)->value OP ((integer_type *)y)->value; \ + } else if (tx == integer_tag && ty == double_tag) { \ + s.double_t.value = ((integer_type *)x)->value OP ((double_type *)y)->value; \ + } else if (tx == double_tag && ty == double_tag) { \ + s.double_t.value = ((double_type *)x)->value OP ((double_type *)y)->value; \ + } else { \ + make_string(s, "Bad argument type"); \ + make_cons(c1, y, nil); \ + make_cons(c0, &s, &c1); \ + Cyc_rt_raise(&c0); \ + } \ + return s; \ +} \ +common_type FUNC(int argc, object n, ...) { \ + va_list ap; \ + va_start(ap, n); \ + common_type result = Cyc_num_op_va_list(argc, FUNC_OP, n, ap); \ + va_end(ap); \ + return result; \ +} \ +void FUNC_APPLY(int argc, object clo, object cont, object n, ...) { \ + va_list ap; \ + va_start(ap, n); \ + common_type result = Cyc_num_op_va_list(argc - 1, FUNC_OP, n, ap); \ + va_end(ap); \ + return_funcall1(cont, &result); \ +} + +declare_num_op(Cyc_sum, Cyc_sum_op, dispatch_sum, +); +declare_num_op(Cyc_sub, Cyc_sub_op, dispatch_sub, -); +declare_num_op(Cyc_mul, Cyc_mul_op, dispatch_mul, *); +// TODO: what about divide-by-zero, and casting to double when +// result contains a decimal component? +declare_num_op(Cyc_div, Cyc_div_op, dispatch_div, /); + +common_type Cyc_num_op_va_list(int argc, common_type (fn_op(object, object)), object n, va_list ns) { + common_type sum; + int i; + if (argc == 0) { + sum.integer_t.tag = integer_tag; + sum.integer_t.value = 0; + return sum; + } + + if (type_of(n) == integer_tag) { + sum.integer_t.tag = integer_tag; + sum.integer_t.value = ((integer_type *)n)->value; + } else if (type_of(n) == double_tag) { + sum.double_t.tag = double_tag; + sum.double_t.value = ((double_type *)n)->value; + } else { + make_string(s, "Bad argument type"); + make_cons(c1, n, nil); + make_cons(c0, &s, &c1); + Cyc_rt_raise(&c0); + } + + for (i = 1; i < argc; i++) { + common_type result = fn_op(&sum, va_arg(ns, object)); + if (type_of(&result) == integer_tag) { + sum.integer_t.tag = integer_tag; + sum.integer_t.value = ((integer_type *) &result)->value; + } else if (type_of(&result) == double_tag) { + sum.double_t.tag = double_tag; + sum.double_t.value = ((double_type *) &result)->value; + } else { + Cyc_rt_raise_msg("Internal error, invalid tag in Cyc_num_op_va_list"); + } + } + + return sum; +} + +/* I/O functions */ + +port_type Cyc_io_current_input_port() { + make_port(p, stdin, 0); + return p; +} + +port_type Cyc_io_open_input_file(object str) { + const char *fname = ((string_type *)str)->str; + make_port(p, NULL, 0); + p.fp = fopen(fname, "r"); + return p; +} + +object Cyc_io_close_input_port(object port) { + if (port && type_of(port) == port_tag) { + FILE *stream = ((port_type *)port)->fp; + if (stream) fclose(stream); + ((port_type *)port)->fp = NULL; + } + return port; +} + +// TODO: port arg is optional! (maybe handle that in expansion section??) +object Cyc_io_read_char(object port) { + if (type_of(port) == port_tag) { + int c = fgetc(((port_type *) port)->fp); + if (c != EOF) { + return obj_char2obj(c); + } + } + return Cyc_EOF; +} + +object Cyc_io_peek_char(object port) { + FILE *stream; + int c; + + if (type_of(port) == port_tag) { + stream = ((port_type *) port)->fp; + c = fgetc(stream); + ungetc(c, stream); + if (c != EOF) { + return obj_char2obj(c); + } + } + return Cyc_EOF; +} + +void _Cyc_91global_91vars(object cont, object args){ + return_funcall1(cont, Cyc_global_variables); } +void _car(object cont, object args) { + return_funcall1(cont, car(car(args))); } +void _cdr(object cont, object args) { + return_funcall1(cont, cdr(car(args))); } +void _caar(object cont, object args) { + return_funcall1(cont, caar(car(args))); } +void _cadr(object cont, object args) { + return_funcall1(cont, cadr(car(args))); } +void _cdar(object cont, object args) { + return_funcall1(cont, cdar(car(args))); } +void _cddr(object cont, object args) { + return_funcall1(cont, cddr(car(args))); } +void _caaar(object cont, object args) { + return_funcall1(cont, caaar(car(args))); } +void _caadr(object cont, object args) { + return_funcall1(cont, caadr(car(args))); } +void _cadar(object cont, object args) { + return_funcall1(cont, cadar(car(args))); } +void _caddr(object cont, object args) { + return_funcall1(cont, caddr(car(args))); } +void _cdaar(object cont, object args) { + return_funcall1(cont, cdaar(car(args))); } +void _cdadr(object cont, object args) { + return_funcall1(cont, cdadr(car(args))); } +void _cddar(object cont, object args) { + return_funcall1(cont, cddar(car(args))); } +void _cdddr(object cont, object args) { + return_funcall1(cont, cdddr(car(args))); } +void _caaaar(object cont, object args) { + return_funcall1(cont, caaaar(car(args))); } +void _caaadr(object cont, object args) { + return_funcall1(cont, caaadr(car(args))); } +void _caadar(object cont, object args) { + return_funcall1(cont, caadar(car(args))); } +void _caaddr(object cont, object args) { + return_funcall1(cont, caaddr(car(args))); } +void _cadaar(object cont, object args) { + return_funcall1(cont, cadaar(car(args))); } +void _cadadr(object cont, object args) { + return_funcall1(cont, cadadr(car(args))); } +void _caddar(object cont, object args) { + return_funcall1(cont, caddar(car(args))); } +void _cadddr(object cont, object args) { + return_funcall1(cont, cadddr(car(args))); } +void _cdaaar(object cont, object args) { + return_funcall1(cont, cdaaar(car(args))); } +void _cdaadr(object cont, object args) { + return_funcall1(cont, cdaadr(car(args))); } +void _cdadar(object cont, object args) { + return_funcall1(cont, cdadar(car(args))); } +void _cdaddr(object cont, object args) { + return_funcall1(cont, cdaddr(car(args))); } +void _cddaar(object cont, object args) { + return_funcall1(cont, cddaar(car(args))); } +void _cddadr(object cont, object args) { + return_funcall1(cont, cddadr(car(args))); } +void _cdddar(object cont, object args) { + return_funcall1(cont, cdddar(car(args))); } +void _cddddr(object cont, object args) { + return_funcall1(cont, cddddr(car(args))); } +void _cons(object cont, object args) { + make_cons(c, car(args), cadr(args)); + return_funcall1(cont, &c); } +void _eq_127(object cont, object args){ + return_funcall1(cont, Cyc_eq(car(args), cadr(args))); } +void _eqv_127(object cont, object args){ + _eq_127(cont, args); } +void _equal_127(object cont, object args){ + return_funcall1(cont, equalp(car(args), cadr(args))); } +void _length(object cont, object args){ + integer_type i = Cyc_length(car(args)); + return_funcall1(cont, &i); } +void _null_127(object cont, object args) { + return_funcall1(cont, Cyc_is_null(car(args))); } +void _set_91car_67(object cont, object args) { + return_funcall1(cont, Cyc_set_car(car(args), cadr(args))); } +void _set_91cdr_67(object cont, object args) { + return_funcall1(cont, Cyc_set_cdr(car(args), cadr(args))); } +void _Cyc_91has_91cycle_127(object cont, object args) { + return_funcall1(cont, Cyc_has_cycle(car(args))); } +void __87(object cont, object args) { + integer_type argc = Cyc_length(args); + dispatch(argc.value, (function_type)dispatch_sum, cont, cont, args); } +void __91(object cont, object args) { + integer_type argc = Cyc_length(args); + dispatch(argc.value, (function_type)dispatch_sub, cont, cont, args); } +void __85(object cont, object args) { + integer_type argc = Cyc_length(args); + dispatch(argc.value, (function_type)dispatch_mul, cont, cont, args); } +void __95(object cont, object args) { + integer_type argc = Cyc_length(args); + dispatch(argc.value, (function_type)dispatch_div, cont, cont, args); } +void _Cyc_91cvar_127(object cont, object args) { + return_funcall1(cont, Cyc_is_cvar(car(args))); } +void _boolean_127(object cont, object args) { + return_funcall1(cont, Cyc_is_boolean(car(args))); } +void _char_127(object cont, object args) { + return_funcall1(cont, Cyc_is_char(car(args))); } +void _eof_91object_127(object cont, object args) { + return_funcall1(cont, Cyc_is_eof_object(car(args))); } +void _number_127(object cont, object args) { + return_funcall1(cont, Cyc_is_number(car(args))); } +void _real_127(object cont, object args) { + return_funcall1(cont, Cyc_is_real(car(args))); } +void _integer_127(object cont, object args) { + return_funcall1(cont, Cyc_is_integer(car(args))); } +void _pair_127(object cont, object args) { + return_funcall1(cont, Cyc_is_cons(car(args))); } +void _procedure_127(object cont, object args) { + return_funcall1(cont, Cyc_is_procedure(car(args))); } +void _string_127(object cont, object args) { + return_funcall1(cont, Cyc_is_string(car(args))); } +void _symbol_127(object cont, object args) { + return_funcall1(cont, Cyc_is_symbol(car(args))); } + +void _Cyc_91get_91cvar(object cont, object args) { + printf("not implemented\n"); exit(1); } +void _Cyc_91set_91cvar_67(object cont, object args) { + printf("not implemented\n"); exit(1); } +/* Note we cannot use _exit (per convention) because it is reserved by C */ +void _cyc_exit(object cont, object args) { + if(nullp(args)) + __halt(nil); + __halt(car(args)); +} +void __75halt(object cont, object args) { + exit(0); } +void _cell_91get(object cont, object args) { + printf("not implemented\n"); exit(1); } +void _set_91global_67(object cont, object args) { + printf("not implemented\n"); exit(1); } +void _set_91cell_67(object cont, object args) { + printf("not implemented\n"); exit(1); } +void _cell(object cont, object args) { + printf("not implemented\n"); exit(1); } + +void __123(object cont, object args) { + return_funcall1(cont, __num_eq(car(args), cadr(args)));} +void __125(object cont, object args) { + return_funcall1(cont, __num_gt(car(args), cadr(args)));} +void __121(object cont, object args) { + return_funcall1(cont, __num_lt(car(args), cadr(args)));} +void __125_123(object cont, object args) { + return_funcall1(cont, __num_gte(car(args), cadr(args)));} +void __121_123(object cont, object args) { + return_funcall1(cont, __num_lte(car(args), cadr(args)));} + +void _apply(object cont, object args) { + apply(cont, car(args), cdr(args)); } +void _assoc (object cont, object args) { + return_funcall1(cont, assoc(car(args), cadr(args)));} +void _assq (object cont, object args) { + return_funcall1(cont, assq(car(args), cadr(args)));} +void _assv (object cont, object args) { + return_funcall1(cont, assq(car(args), cadr(args)));} +void _member(object cont, object args) { + return_funcall1(cont, memberp(car(args), cadr(args)));} +void _memq(object cont, object args) { + return_funcall1(cont, memqp(car(args), cadr(args)));} +void _memv(object cont, object args) { + return_funcall1(cont, memqp(car(args), cadr(args)));} +void _char_91_125integer(object cont, object args) { + integer_type i = Cyc_char2integer(car(args)); + return_funcall1(cont, &i);} +void _integer_91_125char(object cont, object args) { + return_funcall1(cont, Cyc_integer2char(car(args)));} +void _string_91_125number(object cont, object args) { + common_type i = Cyc_string2number(car(args)); + return_funcall1(cont, &i);} +//void _error(object cont, object args) { +// integer_type argc = Cyc_length(args); +// dispatch_va(argc.value, dispatch_error, cont, cont, args); } +void _Cyc_91current_91exception_91handler(object cont, object args) { + object handler = Cyc_current_exception_handler(); + return_funcall1(cont, handler); } +void _Cyc_91default_91exception_91handler(object cont, object args) { + // TODO: this is a quick-and-dirty implementation, may be a better way to write this + Cyc_default_exception_handler(1, args, car(args)); +} +void _string_91append(object cont, object args) { + integer_type argc = Cyc_length(args); + dispatch(argc.value, (function_type)dispatch_string_91append, cont, cont, args); } +void _string_91_125list(object cont, object args) { + string2list(lst, car(args)); + return_funcall1(cont, &lst);} +void _list_91_125string(object cont, object args) { + string_type s = Cyc_list2string(car(args)); + return_funcall1(cont, &s);} +void _string_91_125symbol(object cont, object args) { + return_funcall1(cont, Cyc_string2symbol(car(args)));} +void _symbol_91_125string(object cont, object args) { + string_type s = Cyc_symbol2string(car(args)); + return_funcall1(cont, &s);} +void _number_91_125string(object cont, object args) { + string_type s = Cyc_number2string(car(args)); + return_funcall1(cont, &s);} +void _current_91input_91port(object cont, object args) { + port_type p = Cyc_io_current_input_port(); + return_funcall1(cont, &p);} +void _open_91input_91file(object cont, object args) { + port_type p = Cyc_io_open_input_file(car(args)); + return_funcall1(cont, &p);} +void _close_91input_91port(object cont, object args) { + return_funcall1(cont, Cyc_io_close_input_port(car(args)));} +void _read_91char(object cont, object args) { + return_funcall1(cont, Cyc_io_read_char(car(args)));} +void _peek_91char(object cont, object args) { + return_funcall1(cont, Cyc_io_peek_char(car(args)));} +void _write(object cont, object args) { + return_funcall1(cont, Cyc_write(car(args))); } +void _display(object cont, object args) { + return_funcall1(cont, Cyc_display(car(args)));} + + + + /** * Receive a list of arguments and apply them to the given function */ diff --git a/runtime.h b/runtime.h index 0e84ab36..7b6daad5 100644 --- a/runtime.h +++ b/runtime.h @@ -11,15 +11,11 @@ #include "cyclone.h" -long global_stack_size; -long global_heap_size; +extern long global_stack_size; +extern long global_heap_size; +extern const object Cyc_EOF; -static symbol_type __EOF = {eof_tag, "", nil}; // symbol_type in lieu of custom type -static const object Cyc_EOF = &__EOF; - -static object cell_get(object cell){ - return car(cell); -} +object cell_get(object cell); #define global_set(glo,value) (glo=value) @@ -61,141 +57,67 @@ static object cell_get(object cell){ /* Prototypes for Lisp built-in functions. */ -static object Cyc_global_variables = nil; -static object Cyc_get_global_variables(); -static object Cyc_get_cvar(object var); -static object Cyc_set_cvar(object var, object value); -static object apply(object cont, object func, object args); -static void Cyc_apply(int argc, closure cont, object prim, ...); -static void dispatch_string_91append(int argc, object clo, object cont, object str1, ...); -static string_type Cyc_string_append(int argc, object str1, ...); -static string_type Cyc_string_append_va_list(int, object, va_list); -//static void dispatch_error(int argc, object clo, object cont, object obj1, ...); -//static object Cyc_error(int count, object obj1, ...); -//static object Cyc_error_va(int count, object obj1, va_list ap); +extern object Cyc_global_variables; +object Cyc_get_global_variables(); +object Cyc_get_cvar(object var); +object Cyc_set_cvar(object var, object value); +object apply(object cont, object func, object args); +void Cyc_apply(int argc, closure cont, object prim, ...); +void dispatch_string_91append(int argc, object clo, object cont, object str1, ...); +string_type Cyc_string_append(int argc, object str1, ...); +string_type Cyc_string_append_va_list(int, object, va_list); +//void dispatch_error(int argc, object clo, object cont, object obj1, ...); +//object Cyc_error(int count, object obj1, ...); +//object Cyc_error_va(int count, object obj1, va_list ap); //object Cyc_raise(object); -static object Cyc_default_exception_handler(int argc, closure _, object err); +object Cyc_default_exception_handler(int argc, closure _, object err); object Cyc_current_exception_handler(); -static list mcons(object,object); -static object terpri(void); -static object Cyc_display(object); -static object Cyc_write(object); -static object Cyc_is_boolean(object o); -static object Cyc_is_cons(object o); -static object Cyc_is_null(object o); -static object Cyc_is_number(object o); -static object Cyc_is_real(object o); -static object Cyc_is_integer(object o); -static object Cyc_is_symbol(object o); -static object Cyc_is_string(object o); -static object Cyc_is_char(object o); -static object Cyc_is_procedure(object o); -static object Cyc_is_eof_object(object o); -static object Cyc_is_cvar(object o); -static common_type Cyc_sum_op(object x, object y); -static common_type Cyc_sub_op(object x, object y); -static common_type Cyc_mul_op(object x, object y); -static common_type Cyc_div_op(object x, object y); -static common_type Cyc_sum(int argc, object n, ...); -static common_type Cyc_sub(int argc, object n, ...); -static common_type Cyc_mul(int argc, object n, ...); -static common_type Cyc_div(int argc, object n, ...); -static common_type Cyc_num_op_va_list(int argc, common_type (fn_op(object, object)), object n, va_list ns); -static int equal(object,object); -static list assq(object,list); -static object get(object,object); -static object equalp(object,object); -static object memberp(object,list); -static object memqp(object,list); -static char *transport(char *,int); -static void GC(closure,object*,int) never_returns; - -/* Symbol Table */ - -/* Notes for the symbol table - - string->symbol can: - - lookup symbol in the table - - if found, return that pointer - - otherwise, allocate symbol in table and return ptr to it - - For now, GC of symbols is missing. long-term it probably would be desirable -*/ +list mcons(object,object); +object terpri(void); +object Cyc_display(object); +object Cyc_write(object); +object Cyc_is_boolean(object o); +object Cyc_is_cons(object o); +object Cyc_is_null(object o); +object Cyc_is_number(object o); +object Cyc_is_real(object o); +object Cyc_is_integer(object o); +object Cyc_is_symbol(object o); +object Cyc_is_string(object o); +object Cyc_is_char(object o); +object Cyc_is_procedure(object o); +object Cyc_is_eof_object(object o); +object Cyc_is_cvar(object o); +common_type Cyc_sum_op(object x, object y); +common_type Cyc_sub_op(object x, object y); +common_type Cyc_mul_op(object x, object y); +common_type Cyc_div_op(object x, object y); +common_type Cyc_sum(int argc, object n, ...); +common_type Cyc_sub(int argc, object n, ...); +common_type Cyc_mul(int argc, object n, ...); +common_type Cyc_div(int argc, object n, ...); +common_type Cyc_num_op_va_list(int argc, common_type (fn_op(object, object)), object n, va_list ns); +int equal(object,object); +list assq(object,list); +object get(object,object); +object equalp(object,object); +object memberp(object,list); +object memqp(object,list); +char *transport(char *,int); +void GC(closure,object*,int) never_returns; char *_strdup (const char *s); -static object add_symbol(symbol_type *psym); -static object add_symbol_by_name(const char *name); -static object find_symbol_by_name(const char *name); -static object find_or_add_symbol(const char *name); -list symbol_table = nil; +object add_symbol(symbol_type *psym); +object add_symbol_by_name(const char *name); +object find_symbol_by_name(const char *name); +object find_or_add_symbol(const char *name); +extern list symbol_table; -char *_strdup (const char *s) { - char *d = malloc (strlen (s) + 1); - if (d) { strcpy (d,s); } - return d; -} - -static object find_symbol_by_name(const char *name) { - list l = symbol_table; - for (; !nullp(l); l = cdr(l)) { - const char *str = symbol_pname(car(l)); - if (strcmp(str, name) == 0) return car(l); - } - return nil; -} - -static object add_symbol(symbol_type *psym) { - symbol_table = mcons(psym, symbol_table); - return psym; -} - -static object add_symbol_by_name(const char *name) { - symbol_type sym = {symbol_tag, _strdup(name), nil}; - symbol_type *psym = malloc(sizeof(symbol_type)); - memcpy(psym, &sym, sizeof(symbol_type)); - return add_symbol(psym); -} - -static object find_or_add_symbol(const char *name){ - object sym = find_symbol_by_name(name); - if (sym){ - return sym; - } else { - return add_symbol_by_name(name); - } -} -/* END symbol table */ - -/* Mutation table - * - * Keep track of mutations (EG: set-car!) so that new - * values are transported to the heap during GC. - */ -list mutation_table = nil; - -static void add_mutation(object var, object value); -static void clear_mutations(); - -static void add_mutation(object var, object value){ - if (is_object_type(value)) { - mutation_table = mcons(var, mutation_table); - } -} - -/* TODO: consider a more efficient implementation, such as reusing old nodes - instead of reclaiming them each time - */ -static void clear_mutations() { - list l = mutation_table, next; - while (!nullp(l)) { - next = cdr(l); - free(l); - l = next; - } - mutation_table = nil; -} -/* END mutation table */ +void add_mutation(object var, object value); +void clear_mutations(); +extern list mutation_table; +// JAE TODO: not sure how to refactor global section yet /* Global variables. */ static clock_t start; /* Starting time. */ @@ -227,904 +149,16 @@ static jmp_buf jmp_main; /* Where to jump to. */ /* Define the Lisp atoms that we need. */ +// JAE TODO: probably need to break these up, declare extern here and +// put actual assignments into runtime.c defboolean(f,f); defboolean(t,t); defsymbol(Cyc_191procedure, procedure); -//static object quote_list_f; /* Initialized by main to '(f) */ -//static object quote_list_t; /* Initialized by main to '(t) */ - -//static volatile object unify_subst = nil; /* This is a global Lisp variable. */ +// JAE TODO: will probably need to refactor this, since modules (libs) +// can have globals, too DECLARE_GLOBALS -/* These (crufty) printing functions are used for debugging. */ -static object terpri() {printf("\n"); return nil;} - -static int equal(x, y) object x, y; -{ - if (nullp(x)) return nullp(y); - if (nullp(y)) return nullp(x); - if (obj_is_char(x)) return obj_is_char(y) && x == y; - switch(type_of(x)) { - case integer_tag: - return (type_of(y) == integer_tag && - ((integer_type *) x)->value == ((integer_type *) y)->value); - case double_tag: - return (type_of(y) == double_tag && - ((double_type *) x)->value == ((double_type *) y)->value); - case string_tag: - return (type_of(y) == string_tag && - strcmp(((string_type *) x)->str, - ((string_type *) y)->str) == 0); - default: - return x == y; - } -} - -static object Cyc_get_global_variables(){ - return Cyc_global_variables; -} - -static object Cyc_get_cvar(object var) { - if (is_object_type(var) && type_of(var) == cvar_tag) { - return *(((cvar_type *)var)->pvar); - } - return var; -} - -static object Cyc_set_cvar(object var, object value) { - if (is_object_type(var) && type_of(var) == cvar_tag) { - *(((cvar_type *)var)->pvar) = value; - } - return var;} - -static object Cyc_has_cycle(object lst) { - object slow_lst, fast_lst; - int is_obj = is_object_type(lst); - int type = type_of(lst); - if (nullp(lst) || is_value_type(lst) || - (is_object_type(lst) && type_of(lst) != cons_tag)) { - return (boolean_f); - } - slow_lst = lst; - fast_lst = cdr(lst); - while(1) { - if (nullp(fast_lst)) return boolean_f; - if (Cyc_is_cons(fast_lst) == boolean_f) return boolean_f; - if (nullp(cdr(fast_lst))) return boolean_f; - if (Cyc_is_cons(cdr(fast_lst)) == boolean_f) return boolean_f; - if (is_object_type(car(slow_lst)) && - boolean_f == Cyc_is_boolean(car(slow_lst)) && // Avoid expected dupes - //boolean_f == Cyc_is_symbol(car(slow_lst)) && // - eq(car(slow_lst), car(fast_lst))) return boolean_t; - - slow_lst = cdr(slow_lst); - fast_lst = cddr(fast_lst); - } -} - -static object Cyc_display(x) object x; -{object tmp = nil; - object has_cycle = boolean_f; - int i = 0; - if (nullp(x)) {printf("()"); return x;} - if (obj_is_char(x)) {printf("%c", obj_obj2char(x)); return x;} - switch (type_of(x)) - {case closure0_tag: - case closure1_tag: - case closure2_tag: - case closure3_tag: - case closure4_tag: - case closureN_tag: - printf("",(void *)((closure) x)->fn); - break; - case eof_tag: - printf(""); - break; - case port_tag: - printf(""); - break; - case primitive_tag: - printf("", prim_name(x)); - break; - case cvar_tag: - Cyc_display(Cyc_get_cvar(x)); - break; - case boolean_tag: - printf("#%s",((boolean_type *) x)->pname); - break; - case symbol_tag: - printf("%s",((symbol_type *) x)->pname); - break; - case integer_tag: - printf("%d", ((integer_type *) x)->value); - break; - case double_tag: - printf("%lf", ((double_type *) x)->value); - break; - case string_tag: - printf("%s", ((string_type *) x)->str); - break; - case cons_tag: - has_cycle = Cyc_has_cycle(x); - printf("("); - Cyc_display(car(x)); - - // Experimenting with displaying lambda defs in REPL - // not good enough but this is a start. would probably need - // the same code in write() - if (equal(quote_Cyc_191procedure, car(x))) { - printf(" "); - Cyc_display(cadr(x)); - printf(" ...)"); /* skip body and env for now */ - break; - } - - for (tmp = cdr(x); tmp && ((closure) tmp)->tag == cons_tag; tmp = cdr(tmp)) { - if (has_cycle == boolean_t) { - if (i++ > 20) break; /* arbitrary number, for now */ - } - printf(" "); - Cyc_display(car(tmp)); - } - if (has_cycle == boolean_t) { - printf(" ..."); - } else if (tmp) { - printf(" . "); - Cyc_display(tmp); - } - printf(")"); - break; - default: - printf("Cyc_display: bad tag x=%ld\n", ((closure)x)->tag); getchar(); exit(0);} - return x;} - -static object _Cyc_write(x) object x; -{object tmp = nil; - object has_cycle = boolean_f; - int i = 0; - if (nullp(x)) {printf("()"); return x;} - if (obj_is_char(x)) {printf("#\\%c", obj_obj2char(x)); return x;} - switch (type_of(x)) - {case string_tag: - printf("\"%s\"", ((string_type *) x)->str); - break; - // TODO: what about a list? contents should be displayed per (write) - case cons_tag: - has_cycle = Cyc_has_cycle(x); - printf("("); - _Cyc_write(car(x)); - - // Experimenting with displaying lambda defs in REPL - // not good enough but this is a start. would probably need - // the same code in write() - if (equal(quote_Cyc_191procedure, car(x))) { - printf(" "); - _Cyc_write(cadr(x)); - printf(" ...)"); /* skip body and env for now */ - break; - } - - for (tmp = cdr(x); tmp && ((closure) tmp)->tag == cons_tag; tmp = cdr(tmp)) { - if (has_cycle == boolean_t) { - if (i++ > 20) break; /* arbitrary number, for now */ - } - printf(" "); - _Cyc_write(car(tmp)); - } - if (has_cycle == boolean_t) { - printf(" ..."); - } else if (tmp) { - printf(" . "); - _Cyc_write(tmp); - } - printf(")"); - break; - default: - Cyc_display(x);} - return x;} - -static object Cyc_write(x) object x; -{object y = _Cyc_write(x); - printf("\n"); - return y;} - -/* Some of these non-consing functions have been optimized from CPS. */ - -// TODO: should not be a predicate, may end up moving these to Scheme code -static object memberp(x,l) object x; list l; -{for (; !nullp(l); l = cdr(l)) if (boolean_f != equalp(x,car(l))) return boolean_t; - return boolean_f;} - -static object memqp(x,l) object x; list l; -{for (; !nullp(l); l = cdr(l)) if (eq(x,car(l))) return boolean_t; - return boolean_f;} - -static object get(x,i) object x,i; -{register object plist; register object plistd; - if (nullp(x)) return x; - if (type_of(x)!=symbol_tag) {printf("get: bad x=%ld\n",((closure)x)->tag); exit(0);} - plist = symbol_plist(x); - for (; !nullp(plist); plist = cdr(plistd)) - {plistd = cdr(plist); - if (eq(car(plist),i)) return car(plistd);} - return nil;} - -static object equalp(x,y) object x,y; -{for (; ; x = cdr(x), y = cdr(y)) - {if (equal(x,y)) return boolean_t; - if (obj_is_char(x) || obj_is_char(y) || - nullp(x) || nullp(y) || - type_of(x)!=cons_tag || type_of(y)!=cons_tag) return boolean_f; - if (boolean_f == equalp(car(x),car(y))) return boolean_f;}} - -static list assq(x,l) object x; list l; -{for (; !nullp(l); l = cdr(l)) - {register list la = car(l); if (eq(x,car(la))) return la;} - return boolean_f;} - -static list assoc(x,l) object x; list l; -{for (; !nullp(l); l = cdr(l)) - {register list la = car(l); if (boolean_f != equalp(x,car(la))) return la;} - return boolean_f;} - - -// TODO: generate these using macros??? -static object __num_eq(x, y) object x, y; -{if (x && y && ((integer_type *)x)->value == ((integer_type *)y)->value) - return boolean_t; - return boolean_f;} - -static object __num_gt(x, y) object x, y; -{//printf("DEBUG cmp %d, x %d, y %d, x tag %d, y tag %d\n", - // (((integer_type *)x)->value > ((integer_type *)y)->value), - // ((integer_type *)x)->value, ((integer_type *)y)->value, - // ((list)x)->tag, ((list)y)->tag); - //exit(1); - if (((integer_type *)x)->value > ((integer_type *)y)->value) - return boolean_t; - return boolean_f;} - -static object __num_lt(x, y) object x, y; -{if (((integer_type *)x)->value < ((integer_type *)y)->value) - return boolean_t; - return boolean_f;} - -static object __num_gte(x, y) object x, y; -{if (((integer_type *)x)->value >= ((integer_type *)y)->value) - return boolean_t; - return boolean_f;} - -static object __num_lte(x, y) object x, y; -{if (((integer_type *)x)->value <= ((integer_type *)y)->value) - return boolean_t; - return boolean_f;} - -// TODO: static object Cyc_is_eq(x, y) object x, y) -static object Cyc_is_boolean(object o){ - if (!nullp(o) && - !is_value_type(o) && - ((list)o)->tag == boolean_tag && - (eq(boolean_f, o) || eq(boolean_t, o))) - return boolean_t; - return boolean_f;} - -static object Cyc_is_cons(object o){ - if (!nullp(o) && !is_value_type(o) && ((list)o)->tag == cons_tag) - return boolean_t; - return boolean_f;} - -static object Cyc_is_null(object o){ - if (nullp(o)) - return boolean_t; - return boolean_f;} - -static object Cyc_is_number(object o){ - if (!nullp(o) && !is_value_type(o) && - (type_of(o) == integer_tag || type_of(o) == double_tag)) - return boolean_t; - return boolean_f;} - -static object Cyc_is_real(object o){ - return Cyc_is_number(o);} - -static object Cyc_is_integer(object o){ - if (!nullp(o) && !is_value_type(o) && type_of(o) == integer_tag) - return boolean_t; - return boolean_f;} - -static object Cyc_is_symbol(object o){ - if (!nullp(o) && !is_value_type(o) && ((list)o)->tag == symbol_tag) - return boolean_t; - return boolean_f;} - -static object Cyc_is_string(object o){ - if (!nullp(o) && !is_value_type(o) && ((list)o)->tag == string_tag) - return boolean_t; - return boolean_f;} - -static object Cyc_is_char(object o){ - if (obj_is_char(o)) - return boolean_t; - return boolean_f;} - -static object Cyc_is_procedure(object o) { - int tag; - if (!nullp(o) && !is_value_type(o)) { - tag = type_of(o); - if (tag == closure0_tag || - tag == closure1_tag || - tag == closure2_tag || - tag == closure3_tag || - tag == closure4_tag || - tag == closureN_tag || - tag == primitive_tag) { - return boolean_t; - } - } - return boolean_f; -} - -static object Cyc_is_eof_object(object o) { - if (!nullp(o) && !is_value_type(o) && type_of(o) == eof_tag) - return boolean_t; - return boolean_f;} - -static object Cyc_is_cvar(object o) { - if (!nullp(o) && !is_value_type(o) && type_of(o) == cvar_tag) - return boolean_t; - return boolean_f;} - -static object Cyc_eq(object x, object y) { - if (eq(x, y)) - return boolean_t; - return boolean_f; -} - -static object Cyc_set_car(object l, object val) { - car(l) = val; - add_mutation(l, val); - return l; -} - -static object Cyc_set_cdr(object l, object val) { - cdr(l) = val; - add_mutation(l, val); - return l; -} - -static integer_type Cyc_length(object l){ - make_int(len, 0); - while(!nullp(l)){ - if (((list)l)->tag != cons_tag){ - printf("length - invalid parameter, expected list\n"); - exit(1); - } - l = cdr(l); - len.value++; - } - return len; -} - -static string_type Cyc_number2string(object n) { - char buffer[1024]; - if (type_of(n) == integer_tag) { - snprintf(buffer, 1024, "%d", ((integer_type *)n)->value); - } else if (type_of(n) == double_tag) { - snprintf(buffer, 1024, "%lf", ((double_type *)n)->value); - } else { - buffer[0] = '\0'; // TODO: throw error instead - } - make_string(str, buffer); - return str; -} - -static string_type Cyc_symbol2string(object sym) { - make_string(str, symbol_pname(sym)); - return str; -} - -static object Cyc_string2symbol(object str) { - object sym = find_symbol_by_name(symbol_pname(str)); - if (!sym) { - sym = add_symbol_by_name(symbol_pname(str)); - } - return sym; -} - -static string_type Cyc_list2string(object lst){ - char *buf; - int i = 0; - integer_type len = Cyc_length(lst); // Inefficient, walks whole list - buf = alloca(sizeof(char) * (len.value + 1)); - - while(!nullp(lst)){ - buf[i++] = obj_obj2char(car(lst)); - lst = cdr(lst); - } - buf[i] = '\0'; - - make_string(str, buf); - return str; -} - -#define string2list(c,s) object c = nil; { \ - char *str = ((string_type *)s)->str; \ - int len = strlen(str); \ - cons_type *buf; \ - if (len > 0) { \ - buf = alloca(sizeof(cons_type) * len); \ - __string2list(str, buf, len); \ - c = (object)&(buf[0]); \ - } \ -} - -static void __string2list(const char *str, cons_type *buf, int buflen){ - int i = 0; - while (str[i]){ - buf[i].tag = cons_tag; - buf[i].cons_car = obj_char2obj(str[i]); - buf[i].cons_cdr = (i == buflen - 1) ? nil : buf + (i + 1); - i++; - } -} - -static common_type Cyc_string2number(object str){ - common_type result; - double n; - if (type_of(str) == string_tag && - ((string_type *) str)->str){ - n = atof(((string_type *) str)->str); - - if (ceilf(n) == n) { - result.integer_t.tag = integer_tag; - result.integer_t.value = (int)n; - } - else { - result.double_t.tag = double_tag; - result.double_t.value = n; - } - } else { - // TODO: not good enough because we do pointer comparisons to #f - //result.boolean_t = boolean_f; - } - - return result; -} - -static void dispatch_string_91append(int argc, object clo, object cont, object str1, ...) { - string_type result; - va_list ap; - va_start(ap, str1); - result = Cyc_string_append_va_list(argc - 1, str1, ap); - va_end(ap); - return_funcall1(cont, &result); -} - -static string_type Cyc_string_append(int argc, object str1, ...) { - string_type result; - va_list ap; - va_start(ap, str1); - result = Cyc_string_append_va_list(argc, str1, ap); - va_end(ap); - return result; -} - -static string_type Cyc_string_append_va_list(int argc, object str1, va_list ap) { - // TODO: one way to do this, perhaps not the most efficient: - // compute lengths of the strings, - // store lens and str ptrs - // allocate buffer, memcpy each str to buffer - // make_string using buffer - - int i = 0, total_len = 1; // for null char - int *len = alloca(sizeof(int) * argc); - char *buffer, *bufferp, **str = alloca(sizeof(char *) * argc); - object tmp; - - if (argc > 0) { - str[i] = ((string_type *)str1)->str; - len[i] = strlen(str[i]); - total_len += len[i]; - } - - for (i = 1; i < argc; i++) { - tmp = va_arg(ap, object); - str[i] = ((string_type *)tmp)->str; - len[i] = strlen(str[i]); - total_len += len[i]; - } - - buffer = bufferp = alloca(sizeof(char) * total_len); - for (i = 0; i < argc; i++) { - memcpy(bufferp, str[i], len[i]); - bufferp += len[i]; - } - *bufferp = '\0'; - make_string(result, buffer); - return result; -} - -static integer_type Cyc_char2integer(object chr){ - make_int(n, obj_obj2char(chr)); - return n; -} - -static object Cyc_integer2char(object n){ - int val = 0; - - if (!nullp(n)) { - val = ((integer_type *) n)->value; - } - - return obj_char2obj(val); -} - -static void my_exit(closure) never_returns; -static void my_exit(env) closure env; { -#if DEBUG_SHOW_DIAG - printf("my_exit: heap bytes allocated=%d time=%ld ticks no_gcs=%ld no_m_gcs=%ld\n", - allocp-bottom,clock()-start,no_gcs,no_major_gcs); - printf("my_exit: ticks/second=%ld\n",(long) CLOCKS_PER_SEC); -#endif - exit(0);} - -static object __halt(object obj) { -#if DEBUG_SHOW_DIAG - printf("\nhalt: "); - Cyc_display(obj); - printf("\n"); -#endif - my_exit(obj); - return nil; -} - -#define declare_num_op(FUNC, FUNC_OP, FUNC_APPLY, OP) \ -static common_type FUNC_OP(object x, object y) { \ - common_type s; \ - int tx = type_of(x), ty = type_of(y); \ - s.double_t.tag = double_tag; \ - if (tx == integer_tag && ty == integer_tag) { \ - s.integer_t.tag = integer_tag; \ - s.integer_t.value = ((integer_type *)x)->value OP ((integer_type *)y)->value; \ - } else if (tx == double_tag && ty == integer_tag) { \ - s.double_t.value = ((double_type *)x)->value OP ((integer_type *)y)->value; \ - } else if (tx == integer_tag && ty == double_tag) { \ - s.double_t.value = ((integer_type *)x)->value OP ((double_type *)y)->value; \ - } else if (tx == double_tag && ty == double_tag) { \ - s.double_t.value = ((double_type *)x)->value OP ((double_type *)y)->value; \ - } else { \ - make_string(s, "Bad argument type"); \ - make_cons(c1, y, nil); \ - make_cons(c0, &s, &c1); \ - Cyc_rt_raise(&c0); \ - } \ - return s; \ -} \ -static common_type FUNC(int argc, object n, ...) { \ - va_list ap; \ - va_start(ap, n); \ - common_type result = Cyc_num_op_va_list(argc, FUNC_OP, n, ap); \ - va_end(ap); \ - return result; \ -} \ -static void FUNC_APPLY(int argc, object clo, object cont, object n, ...) { \ - va_list ap; \ - va_start(ap, n); \ - common_type result = Cyc_num_op_va_list(argc - 1, FUNC_OP, n, ap); \ - va_end(ap); \ - return_funcall1(cont, &result); \ -} - -declare_num_op(Cyc_sum, Cyc_sum_op, dispatch_sum, +); -declare_num_op(Cyc_sub, Cyc_sub_op, dispatch_sub, -); -declare_num_op(Cyc_mul, Cyc_mul_op, dispatch_mul, *); -// TODO: what about divide-by-zero, and casting to double when -// result contains a decimal component? -declare_num_op(Cyc_div, Cyc_div_op, dispatch_div, /); - -static common_type Cyc_num_op_va_list(int argc, common_type (fn_op(object, object)), object n, va_list ns) { - common_type sum; - int i; - if (argc == 0) { - sum.integer_t.tag = integer_tag; - sum.integer_t.value = 0; - return sum; - } - - if (type_of(n) == integer_tag) { - sum.integer_t.tag = integer_tag; - sum.integer_t.value = ((integer_type *)n)->value; - } else if (type_of(n) == double_tag) { - sum.double_t.tag = double_tag; - sum.double_t.value = ((double_type *)n)->value; - } else { - make_string(s, "Bad argument type"); - make_cons(c1, n, nil); - make_cons(c0, &s, &c1); - Cyc_rt_raise(&c0); - } - - for (i = 1; i < argc; i++) { - common_type result = fn_op(&sum, va_arg(ns, object)); - if (type_of(&result) == integer_tag) { - sum.integer_t.tag = integer_tag; - sum.integer_t.value = ((integer_type *) &result)->value; - } else if (type_of(&result) == double_tag) { - sum.double_t.tag = double_tag; - sum.double_t.value = ((double_type *) &result)->value; - } else { - Cyc_rt_raise_msg("Internal error, invalid tag in Cyc_num_op_va_list"); - } - } - - return sum; -} - -/* I/O functions */ - -static port_type Cyc_io_current_input_port() { - make_port(p, stdin, 0); - return p; -} - -static port_type Cyc_io_open_input_file(object str) { - const char *fname = ((string_type *)str)->str; - make_port(p, NULL, 0); - p.fp = fopen(fname, "r"); - return p; -} - -static object Cyc_io_close_input_port(object port) { - if (port && type_of(port) == port_tag) { - FILE *stream = ((port_type *)port)->fp; - if (stream) fclose(stream); - ((port_type *)port)->fp = NULL; - } - return port; -} - -// TODO: port arg is optional! (maybe handle that in expansion section??) -static object Cyc_io_read_char(object port) { - if (type_of(port) == port_tag) { - int c = fgetc(((port_type *) port)->fp); - if (c != EOF) { - return obj_char2obj(c); - } - } - return Cyc_EOF; -} - -static object Cyc_io_peek_char(object port) { - FILE *stream; - int c; - - if (type_of(port) == port_tag) { - stream = ((port_type *) port)->fp; - c = fgetc(stream); - ungetc(c, stream); - if (c != EOF) { - return obj_char2obj(c); - } - } - return Cyc_EOF; -} - -static void _Cyc_91global_91vars(object cont, object args){ - return_funcall1(cont, Cyc_global_variables); } -static void _car(object cont, object args) { - return_funcall1(cont, car(car(args))); } -static void _cdr(object cont, object args) { - return_funcall1(cont, cdr(car(args))); } -static void _caar(object cont, object args) { - return_funcall1(cont, caar(car(args))); } -static void _cadr(object cont, object args) { - return_funcall1(cont, cadr(car(args))); } -static void _cdar(object cont, object args) { - return_funcall1(cont, cdar(car(args))); } -static void _cddr(object cont, object args) { - return_funcall1(cont, cddr(car(args))); } -static void _caaar(object cont, object args) { - return_funcall1(cont, caaar(car(args))); } -static void _caadr(object cont, object args) { - return_funcall1(cont, caadr(car(args))); } -static void _cadar(object cont, object args) { - return_funcall1(cont, cadar(car(args))); } -static void _caddr(object cont, object args) { - return_funcall1(cont, caddr(car(args))); } -static void _cdaar(object cont, object args) { - return_funcall1(cont, cdaar(car(args))); } -static void _cdadr(object cont, object args) { - return_funcall1(cont, cdadr(car(args))); } -static void _cddar(object cont, object args) { - return_funcall1(cont, cddar(car(args))); } -static void _cdddr(object cont, object args) { - return_funcall1(cont, cdddr(car(args))); } -static void _caaaar(object cont, object args) { - return_funcall1(cont, caaaar(car(args))); } -static void _caaadr(object cont, object args) { - return_funcall1(cont, caaadr(car(args))); } -static void _caadar(object cont, object args) { - return_funcall1(cont, caadar(car(args))); } -static void _caaddr(object cont, object args) { - return_funcall1(cont, caaddr(car(args))); } -static void _cadaar(object cont, object args) { - return_funcall1(cont, cadaar(car(args))); } -static void _cadadr(object cont, object args) { - return_funcall1(cont, cadadr(car(args))); } -static void _caddar(object cont, object args) { - return_funcall1(cont, caddar(car(args))); } -static void _cadddr(object cont, object args) { - return_funcall1(cont, cadddr(car(args))); } -static void _cdaaar(object cont, object args) { - return_funcall1(cont, cdaaar(car(args))); } -static void _cdaadr(object cont, object args) { - return_funcall1(cont, cdaadr(car(args))); } -static void _cdadar(object cont, object args) { - return_funcall1(cont, cdadar(car(args))); } -static void _cdaddr(object cont, object args) { - return_funcall1(cont, cdaddr(car(args))); } -static void _cddaar(object cont, object args) { - return_funcall1(cont, cddaar(car(args))); } -static void _cddadr(object cont, object args) { - return_funcall1(cont, cddadr(car(args))); } -static void _cdddar(object cont, object args) { - return_funcall1(cont, cdddar(car(args))); } -static void _cddddr(object cont, object args) { - return_funcall1(cont, cddddr(car(args))); } -static void _cons(object cont, object args) { - make_cons(c, car(args), cadr(args)); - return_funcall1(cont, &c); } -static void _eq_127(object cont, object args){ - return_funcall1(cont, Cyc_eq(car(args), cadr(args))); } -static void _eqv_127(object cont, object args){ - _eq_127(cont, args); } -static void _equal_127(object cont, object args){ - return_funcall1(cont, equalp(car(args), cadr(args))); } -static void _length(object cont, object args){ - integer_type i = Cyc_length(car(args)); - return_funcall1(cont, &i); } -static void _null_127(object cont, object args) { - return_funcall1(cont, Cyc_is_null(car(args))); } -static void _set_91car_67(object cont, object args) { - return_funcall1(cont, Cyc_set_car(car(args), cadr(args))); } -static void _set_91cdr_67(object cont, object args) { - return_funcall1(cont, Cyc_set_cdr(car(args), cadr(args))); } -static void _Cyc_91has_91cycle_127(object cont, object args) { - return_funcall1(cont, Cyc_has_cycle(car(args))); } -static void __87(object cont, object args) { - integer_type argc = Cyc_length(args); - dispatch(argc.value, (function_type)dispatch_sum, cont, cont, args); } -static void __91(object cont, object args) { - integer_type argc = Cyc_length(args); - dispatch(argc.value, (function_type)dispatch_sub, cont, cont, args); } -static void __85(object cont, object args) { - integer_type argc = Cyc_length(args); - dispatch(argc.value, (function_type)dispatch_mul, cont, cont, args); } -static void __95(object cont, object args) { - integer_type argc = Cyc_length(args); - dispatch(argc.value, (function_type)dispatch_div, cont, cont, args); } -static void _Cyc_91cvar_127(object cont, object args) { - return_funcall1(cont, Cyc_is_cvar(car(args))); } -static void _boolean_127(object cont, object args) { - return_funcall1(cont, Cyc_is_boolean(car(args))); } -static void _char_127(object cont, object args) { - return_funcall1(cont, Cyc_is_char(car(args))); } -static void _eof_91object_127(object cont, object args) { - return_funcall1(cont, Cyc_is_eof_object(car(args))); } -static void _number_127(object cont, object args) { - return_funcall1(cont, Cyc_is_number(car(args))); } -static void _real_127(object cont, object args) { - return_funcall1(cont, Cyc_is_real(car(args))); } -static void _integer_127(object cont, object args) { - return_funcall1(cont, Cyc_is_integer(car(args))); } -static void _pair_127(object cont, object args) { - return_funcall1(cont, Cyc_is_cons(car(args))); } -static void _procedure_127(object cont, object args) { - return_funcall1(cont, Cyc_is_procedure(car(args))); } -static void _string_127(object cont, object args) { - return_funcall1(cont, Cyc_is_string(car(args))); } -static void _symbol_127(object cont, object args) { - return_funcall1(cont, Cyc_is_symbol(car(args))); } - -static void _Cyc_91get_91cvar(object cont, object args) { - printf("not implemented\n"); exit(1); } -static void _Cyc_91set_91cvar_67(object cont, object args) { - printf("not implemented\n"); exit(1); } -/* Note we cannot use _exit (per convention) because it is reserved by C */ -static void _cyc_exit(object cont, object args) { - if(nullp(args)) - __halt(nil); - __halt(car(args)); -} -static void __75halt(object cont, object args) { - exit(0); } -static void _cell_91get(object cont, object args) { - printf("not implemented\n"); exit(1); } -static void _set_91global_67(object cont, object args) { - printf("not implemented\n"); exit(1); } -static void _set_91cell_67(object cont, object args) { - printf("not implemented\n"); exit(1); } -static void _cell(object cont, object args) { - printf("not implemented\n"); exit(1); } - -static void __123(object cont, object args) { - return_funcall1(cont, __num_eq(car(args), cadr(args)));} -static void __125(object cont, object args) { - return_funcall1(cont, __num_gt(car(args), cadr(args)));} -static void __121(object cont, object args) { - return_funcall1(cont, __num_lt(car(args), cadr(args)));} -static void __125_123(object cont, object args) { - return_funcall1(cont, __num_gte(car(args), cadr(args)));} -static void __121_123(object cont, object args) { - return_funcall1(cont, __num_lte(car(args), cadr(args)));} - -static void _apply(object cont, object args) { - apply(cont, car(args), cdr(args)); } -static void _assoc (object cont, object args) { - return_funcall1(cont, assoc(car(args), cadr(args)));} -static void _assq (object cont, object args) { - return_funcall1(cont, assq(car(args), cadr(args)));} -static void _assv (object cont, object args) { - return_funcall1(cont, assq(car(args), cadr(args)));} -static void _member(object cont, object args) { - return_funcall1(cont, memberp(car(args), cadr(args)));} -static void _memq(object cont, object args) { - return_funcall1(cont, memqp(car(args), cadr(args)));} -static void _memv(object cont, object args) { - return_funcall1(cont, memqp(car(args), cadr(args)));} -static void _char_91_125integer(object cont, object args) { - integer_type i = Cyc_char2integer(car(args)); - return_funcall1(cont, &i);} -static void _integer_91_125char(object cont, object args) { - return_funcall1(cont, Cyc_integer2char(car(args)));} -static void _string_91_125number(object cont, object args) { - common_type i = Cyc_string2number(car(args)); - return_funcall1(cont, &i);} -//static void _error(object cont, object args) { -// integer_type argc = Cyc_length(args); -// dispatch_va(argc.value, dispatch_error, cont, cont, args); } -static void _Cyc_91current_91exception_91handler(object cont, object args) { - object handler = Cyc_current_exception_handler(); - return_funcall1(cont, handler); } -static void _Cyc_91default_91exception_91handler(object cont, object args) { - // TODO: this is a quick-and-dirty implementation, may be a better way to write this - Cyc_default_exception_handler(1, args, car(args)); -} -static void _string_91append(object cont, object args) { - integer_type argc = Cyc_length(args); - dispatch(argc.value, (function_type)dispatch_string_91append, cont, cont, args); } -static void _string_91_125list(object cont, object args) { - string2list(lst, car(args)); - return_funcall1(cont, &lst);} -static void _list_91_125string(object cont, object args) { - string_type s = Cyc_list2string(car(args)); - return_funcall1(cont, &s);} -static void _string_91_125symbol(object cont, object args) { - return_funcall1(cont, Cyc_string2symbol(car(args)));} -static void _symbol_91_125string(object cont, object args) { - string_type s = Cyc_symbol2string(car(args)); - return_funcall1(cont, &s);} -static void _number_91_125string(object cont, object args) { - string_type s = Cyc_number2string(car(args)); - return_funcall1(cont, &s);} -static void _current_91input_91port(object cont, object args) { - port_type p = Cyc_io_current_input_port(); - return_funcall1(cont, &p);} -static void _open_91input_91file(object cont, object args) { - port_type p = Cyc_io_open_input_file(car(args)); - return_funcall1(cont, &p);} -static void _close_91input_91port(object cont, object args) { - return_funcall1(cont, Cyc_io_close_input_port(car(args)));} -static void _read_91char(object cont, object args) { - return_funcall1(cont, Cyc_io_read_char(car(args)));} -static void _peek_91char(object cont, object args) { - return_funcall1(cont, Cyc_io_peek_char(car(args)));} -static void _write(object cont, object args) { - return_funcall1(cont, Cyc_write(car(args))); } -static void _display(object cont, object args) { - return_funcall1(cont, Cyc_display(car(args)));} - #ifdef CYC_EVAL static void _call_95cc(object cont, object args){ return_funcall2(__glo_call_95cc, cont, car(args));