1 /* T I N Y S C H E M E 1 . 4 1
2 * Dimitrios Souflis (dsouflis@acm.org)
3 * Based on MiniScheme (original credits follow)
4 * (MINISCM) coded by Atsushi Moriwaki (11/5/1989)
5 * (MINISCM) E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp
6 * (MINISCM) This version has been modified by R.C. Secrist.
8 * (MINISCM) Mini-Scheme is now maintained by Akira KIDA.
10 * (MINISCM) This is a revised and modified version by Akira KIDA.
11 * (MINISCM) current version is 0.85k4 (15 May 1994)
15 #define _SCHEME_SOURCE
16 #include "scheme-private.h"
21 #define snprintf _snprintf
38 # define stricmp strcasecmp
42 /* Used for documentation purposes, to signal functions in 'interface' */
57 #define TOK_SHARP_CONST 11
61 #define DELIMITERS "()\";\f\t\v\n\r "
64 * Basic memory allocation units
67 #define banner "TinyScheme 1.41"
74 static int stricmp(const char *s1, const char *s2)
88 #endif /* __APPLE__ */
91 static const char *strlwr(char *s) {
102 # define prompt "ts> "
106 # define InitFile "init.scm"
109 #ifndef FIRST_CELLSEGS
110 # define FIRST_CELLSEGS 3
133 T_LAST_SYSTEM_TYPE=19
137 type_to_string (enum scheme_types typ)
141 case T_STRING: return "string";
142 case T_NUMBER: return "number";
143 case T_SYMBOL: return "symbol";
144 case T_PROC: return "proc";
145 case T_PAIR: return "pair";
146 case T_CLOSURE: return "closure";
147 case T_CONTINUATION: return "configuration";
148 case T_FOREIGN: return "foreign";
149 case T_CHARACTER: return "character";
150 case T_PORT: return "port";
151 case T_VECTOR: return "vector";
152 case T_MACRO: return "macro";
153 case T_PROMISE: return "promise";
154 case T_ENVIRONMENT: return "environment";
155 case T_FOREIGN_OBJECT: return "foreign object";
156 case T_BOOLEAN: return "boolean";
157 case T_NIL: return "nil";
158 case T_EOF_OBJ: return "eof object";
159 case T_SINK: return "sink";
161 assert (! "not reached");
164 /* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */
167 #define T_MASKTYPE 31 /* 0000000000011111 */
168 #define T_SYNTAX 4096 /* 0001000000000000 */
169 #define T_IMMUTABLE 8192 /* 0010000000000000 */
170 #define T_ATOM 16384 /* 0100000000000000 */ /* only for gc */
171 #define CLRATOM 49151 /* 1011111111111111 */ /* only for gc */
172 #define MARK 32768 /* 1000000000000000 */
173 #define UNMARK 32767 /* 0111111111111111 */
176 static num num_add(num a, num b);
177 static num num_mul(num a, num b);
178 static num num_div(num a, num b);
179 static num num_intdiv(num a, num b);
180 static num num_sub(num a, num b);
181 static num num_rem(num a, num b);
182 static num num_mod(num a, num b);
183 static int num_eq(num a, num b);
184 static int num_gt(num a, num b);
185 static int num_ge(num a, num b);
186 static int num_lt(num a, num b);
187 static int num_le(num a, num b);
190 static double round_per_R5RS(double x);
192 static int is_zero_double(double x);
193 static INLINE int num_is_integer(pointer p) {
194 return ((p)->_object._number.is_fixnum);
200 /* macros for cell operations */
201 #define typeflag(p) ((p)->_flag)
202 #define type(p) (typeflag(p)&T_MASKTYPE)
204 INTERFACE INLINE int is_string(pointer p) { return (type(p)==T_STRING); }
205 #define strvalue(p) ((p)->_object._string._svalue)
206 #define strlength(p) ((p)->_object._string._length)
208 INTERFACE static int is_list(scheme *sc, pointer p);
209 INTERFACE INLINE int is_vector(pointer p) { return (type(p)==T_VECTOR); }
210 INTERFACE static void fill_vector(pointer vec, pointer obj);
211 INTERFACE static pointer vector_elem(pointer vec, int ielem);
212 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a);
213 INTERFACE INLINE int is_number(pointer p) { return (type(p)==T_NUMBER); }
214 INTERFACE INLINE int is_integer(pointer p) {
217 if (num_is_integer(p) || (double)ivalue(p) == rvalue(p))
222 INTERFACE INLINE int is_real(pointer p) {
223 return is_number(p) && (!(p)->_object._number.is_fixnum);
226 INTERFACE INLINE int is_character(pointer p) { return (type(p)==T_CHARACTER); }
227 INTERFACE INLINE char *string_value(pointer p) { return strvalue(p); }
228 INLINE num nvalue(pointer p) { return ((p)->_object._number); }
229 INTERFACE long ivalue(pointer p) { return (num_is_integer(p)?(p)->_object._number.value.ivalue:(long)(p)->_object._number.value.rvalue); }
230 INTERFACE double rvalue(pointer p) { return (!num_is_integer(p)?(p)->_object._number.value.rvalue:(double)(p)->_object._number.value.ivalue); }
231 #define ivalue_unchecked(p) ((p)->_object._number.value.ivalue)
232 #define rvalue_unchecked(p) ((p)->_object._number.value.rvalue)
233 #define set_num_integer(p) (p)->_object._number.is_fixnum=1;
234 #define set_num_real(p) (p)->_object._number.is_fixnum=0;
235 INTERFACE long charvalue(pointer p) { return ivalue_unchecked(p); }
237 INTERFACE INLINE int is_port(pointer p) { return (type(p)==T_PORT); }
238 INTERFACE INLINE int is_inport(pointer p) { return is_port(p) && p->_object._port->kind & port_input; }
239 INTERFACE INLINE int is_outport(pointer p) { return is_port(p) && p->_object._port->kind & port_output; }
241 INTERFACE INLINE int is_pair(pointer p) { return (type(p)==T_PAIR); }
242 #define car(p) ((p)->_object._cons._car)
243 #define cdr(p) ((p)->_object._cons._cdr)
244 INTERFACE pointer pair_car(pointer p) { return car(p); }
245 INTERFACE pointer pair_cdr(pointer p) { return cdr(p); }
246 INTERFACE pointer set_car(pointer p, pointer q) { return car(p)=q; }
247 INTERFACE pointer set_cdr(pointer p, pointer q) { return cdr(p)=q; }
249 INTERFACE INLINE int is_symbol(pointer p) { return (type(p)==T_SYMBOL); }
250 INTERFACE INLINE char *symname(pointer p) { return strvalue(car(p)); }
252 SCHEME_EXPORT INLINE int hasprop(pointer p) { return (typeflag(p)&T_SYMBOL); }
253 #define symprop(p) cdr(p)
256 INTERFACE INLINE int is_syntax(pointer p) { return (typeflag(p)&T_SYNTAX); }
257 INTERFACE INLINE int is_proc(pointer p) { return (type(p)==T_PROC); }
258 INTERFACE INLINE int is_foreign(pointer p) { return (type(p)==T_FOREIGN); }
259 INTERFACE INLINE char *syntaxname(pointer p) { return strvalue(car(p)); }
260 #define procnum(p) ivalue(p)
261 static const char *procname(pointer x);
263 INTERFACE INLINE int is_closure(pointer p) { return (type(p)==T_CLOSURE); }
264 INTERFACE INLINE int is_macro(pointer p) { return (type(p)==T_MACRO); }
265 INTERFACE INLINE pointer closure_code(pointer p) { return car(p); }
266 INTERFACE INLINE pointer closure_env(pointer p) { return cdr(p); }
268 INTERFACE INLINE int is_continuation(pointer p) { return (type(p)==T_CONTINUATION); }
269 #define cont_dump(p) cdr(p)
271 INTERFACE INLINE int is_foreign_object(pointer p) { return (type(p)==T_FOREIGN_OBJECT); }
272 INTERFACE const foreign_object_vtable *get_foreign_object_vtable(pointer p) {
273 return p->_object._foreign_object._vtable;
275 INTERFACE void *get_foreign_object_data(pointer p) {
276 return p->_object._foreign_object._data;
279 /* To do: promise should be forced ONCE only */
280 INTERFACE INLINE int is_promise(pointer p) { return (type(p)==T_PROMISE); }
282 INTERFACE INLINE int is_environment(pointer p) { return (type(p)==T_ENVIRONMENT); }
283 #define setenvironment(p) typeflag(p) = T_ENVIRONMENT
285 #define is_atom(p) (typeflag(p)&T_ATOM)
286 #define setatom(p) typeflag(p) |= T_ATOM
287 #define clratom(p) typeflag(p) &= CLRATOM
289 #define is_mark(p) (typeflag(p)&MARK)
290 #define setmark(p) typeflag(p) |= MARK
291 #define clrmark(p) typeflag(p) &= UNMARK
293 INTERFACE INLINE int is_immutable(pointer p) { return (typeflag(p)&T_IMMUTABLE); }
294 /*#define setimmutable(p) typeflag(p) |= T_IMMUTABLE*/
295 INTERFACE INLINE void setimmutable(pointer p) { typeflag(p) |= T_IMMUTABLE; }
297 #define caar(p) car(car(p))
298 #define cadr(p) car(cdr(p))
299 #define cdar(p) cdr(car(p))
300 #define cddr(p) cdr(cdr(p))
301 #define cadar(p) car(cdr(car(p)))
302 #define caddr(p) car(cdr(cdr(p)))
303 #define cdaar(p) cdr(car(car(p)))
304 #define cadaar(p) car(cdr(car(car(p))))
305 #define cadddr(p) car(cdr(cdr(cdr(p))))
306 #define cddddr(p) cdr(cdr(cdr(cdr(p))))
308 #if USE_CHAR_CLASSIFIERS
309 static INLINE int Cisalpha(int c) { return isascii(c) && isalpha(c); }
310 static INLINE int Cisdigit(int c) { return isascii(c) && isdigit(c); }
311 static INLINE int Cisspace(int c) { return isascii(c) && isspace(c); }
312 static INLINE int Cisupper(int c) { return isascii(c) && isupper(c); }
313 static INLINE int Cislower(int c) { return isascii(c) && islower(c); }
317 static const char *charnames[32]={
352 static int is_ascii_name(const char *name, int *pc) {
354 for(i=0; i<32; i++) {
355 if(stricmp(name,charnames[i])==0) {
360 if(stricmp(name,"del")==0) {
369 static int file_push(scheme *sc, const char *fname);
370 static void file_pop(scheme *sc);
371 static int file_interactive(scheme *sc);
372 static INLINE int is_one_of(char *s, int c);
373 static int alloc_cellseg(scheme *sc, int n);
374 static long binary_decode(const char *s);
375 static INLINE pointer get_cell(scheme *sc, pointer a, pointer b);
376 static pointer _get_cell(scheme *sc, pointer a, pointer b);
377 static pointer reserve_cells(scheme *sc, int n);
378 static pointer get_consecutive_cells(scheme *sc, int n);
379 static pointer find_consecutive_cells(scheme *sc, int n);
380 static void finalize_cell(scheme *sc, pointer a);
381 static int count_consecutive_cells(pointer x, int needed);
382 static pointer find_slot_in_env(scheme *sc, pointer env, pointer sym, int all);
383 static pointer mk_number(scheme *sc, num n);
384 static char *store_string(scheme *sc, int len, const char *str, char fill);
385 static pointer mk_vector(scheme *sc, int len);
386 static pointer mk_atom(scheme *sc, char *q);
387 static pointer mk_sharp_const(scheme *sc, char *name);
388 static pointer mk_port(scheme *sc, port *p);
389 static pointer port_from_filename(scheme *sc, const char *fn, int prop);
390 static pointer port_from_file(scheme *sc, FILE *, int prop);
391 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop);
392 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop);
393 static port *port_rep_from_file(scheme *sc, FILE *, int prop);
394 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop);
395 static void port_close(scheme *sc, pointer p, int flag);
396 static void mark(pointer a);
397 static void gc(scheme *sc, pointer a, pointer b);
398 static int basic_inchar(port *pt);
399 static int inchar(scheme *sc);
400 static void backchar(scheme *sc, int c);
401 static char *readstr_upto(scheme *sc, char *delim);
402 static pointer readstrexp(scheme *sc);
403 static INLINE int skipspace(scheme *sc);
404 static int token(scheme *sc);
405 static void printslashstring(scheme *sc, char *s, int len);
406 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen);
407 static void printatom(scheme *sc, pointer l, int f);
408 static pointer mk_proc(scheme *sc, enum scheme_opcodes op);
409 static pointer mk_closure(scheme *sc, pointer c, pointer e);
410 static pointer mk_continuation(scheme *sc, pointer d);
411 static pointer reverse(scheme *sc, pointer a);
412 static pointer reverse_in_place(scheme *sc, pointer term, pointer list);
413 static pointer revappend(scheme *sc, pointer a, pointer b);
414 static void dump_stack_mark(scheme *);
415 static pointer opexe_0(scheme *sc, enum scheme_opcodes op);
416 static pointer opexe_1(scheme *sc, enum scheme_opcodes op);
417 static pointer opexe_2(scheme *sc, enum scheme_opcodes op);
418 static pointer opexe_3(scheme *sc, enum scheme_opcodes op);
419 static pointer opexe_4(scheme *sc, enum scheme_opcodes op);
420 static pointer opexe_5(scheme *sc, enum scheme_opcodes op);
421 static pointer opexe_6(scheme *sc, enum scheme_opcodes op);
422 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op);
423 static void assign_syntax(scheme *sc, char *name);
424 static int syntaxnum(pointer p);
425 static void assign_proc(scheme *sc, enum scheme_opcodes, char *name);
427 #define num_ivalue(n) (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue)
428 #define num_rvalue(n) (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue)
430 static num num_add(num a, num b) {
432 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
434 ret.value.ivalue= a.value.ivalue+b.value.ivalue;
436 ret.value.rvalue=num_rvalue(a)+num_rvalue(b);
441 static num num_mul(num a, num b) {
443 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
445 ret.value.ivalue= a.value.ivalue*b.value.ivalue;
447 ret.value.rvalue=num_rvalue(a)*num_rvalue(b);
452 static num num_div(num a, num b) {
454 ret.is_fixnum=a.is_fixnum && b.is_fixnum && a.value.ivalue%b.value.ivalue==0;
456 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
458 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
463 static num num_intdiv(num a, num b) {
465 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
467 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
469 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
474 static num num_sub(num a, num b) {
476 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
478 ret.value.ivalue= a.value.ivalue-b.value.ivalue;
480 ret.value.rvalue=num_rvalue(a)-num_rvalue(b);
485 static num num_rem(num a, num b) {
488 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
492 /* remainder should have same sign as second operand */
497 } else if (res < 0) {
502 ret.value.ivalue=res;
506 static num num_mod(num a, num b) {
509 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
513 /* modulo should have same sign as second operand */
517 ret.value.ivalue=res;
521 static int num_eq(num a, num b) {
523 int is_fixnum=a.is_fixnum && b.is_fixnum;
525 ret= a.value.ivalue==b.value.ivalue;
527 ret=num_rvalue(a)==num_rvalue(b);
533 static int num_gt(num a, num b) {
535 int is_fixnum=a.is_fixnum && b.is_fixnum;
537 ret= a.value.ivalue>b.value.ivalue;
539 ret=num_rvalue(a)>num_rvalue(b);
544 static int num_ge(num a, num b) {
548 static int num_lt(num a, num b) {
550 int is_fixnum=a.is_fixnum && b.is_fixnum;
552 ret= a.value.ivalue<b.value.ivalue;
554 ret=num_rvalue(a)<num_rvalue(b);
559 static int num_le(num a, num b) {
564 /* Round to nearest. Round to even if midway */
565 static double round_per_R5RS(double x) {
575 if(fmod(fl,2.0)==0.0) { /* I imagine this holds */
584 static int is_zero_double(double x) {
585 return x<DBL_MIN && x>-DBL_MIN;
588 static long binary_decode(const char *s) {
591 while(*s!=0 && (*s=='1' || *s=='0')) {
600 /* allocate new cell segment */
601 static int alloc_cellseg(scheme *sc, int n) {
610 if(adj<sizeof(struct cell)) {
611 adj=sizeof(struct cell);
614 for (k = 0; k < n; k++) {
615 if (sc->last_cell_seg >= CELL_NSEGMENT - 1)
617 cp = (char*) sc->malloc(CELL_SEGSIZE * sizeof(struct cell)+adj);
620 i = ++sc->last_cell_seg ;
621 sc->alloc_seg[i] = cp;
622 /* adjust in TYPE_BITS-bit boundary */
623 if(((unsigned long)cp)%adj!=0) {
624 cp=(char*)(adj*((unsigned long)cp/adj+1));
626 /* insert new segment in address order */
628 sc->cell_seg[i] = newp;
629 while (i > 0 && sc->cell_seg[i - 1] > sc->cell_seg[i]) {
631 sc->cell_seg[i] = sc->cell_seg[i - 1];
632 sc->cell_seg[--i] = p;
634 sc->fcells += CELL_SEGSIZE;
635 last = newp + CELL_SEGSIZE - 1;
636 for (p = newp; p <= last; p++) {
641 /* insert new cells in address order on free list */
642 if (sc->free_cell == sc->NIL || p < sc->free_cell) {
643 cdr(last) = sc->free_cell;
644 sc->free_cell = newp;
647 while (cdr(p) != sc->NIL && newp > cdr(p))
656 static INLINE pointer get_cell_x(scheme *sc, pointer a, pointer b) {
657 if (sc->free_cell != sc->NIL) {
658 pointer x = sc->free_cell;
659 sc->free_cell = cdr(x);
663 return _get_cell (sc, a, b);
667 /* get new cell. parameter a, b is marked by gc. */
668 static pointer _get_cell(scheme *sc, pointer a, pointer b) {
675 if (sc->free_cell == sc->NIL) {
676 const int min_to_be_recovered = sc->last_cell_seg*8;
678 if (sc->fcells < min_to_be_recovered
679 || sc->free_cell == sc->NIL) {
680 /* if only a few recovered, get more to avoid fruitless gc's */
681 if (!alloc_cellseg(sc,1) && sc->free_cell == sc->NIL) {
688 sc->free_cell = cdr(x);
693 /* make sure that there is a given number of cells free */
694 static pointer reserve_cells(scheme *sc, int n) {
699 /* Are there enough cells available? */
700 if (sc->fcells < n) {
701 /* If not, try gc'ing some */
702 gc(sc, sc->NIL, sc->NIL);
703 if (sc->fcells < n) {
704 /* If there still aren't, try getting more heap */
705 if (!alloc_cellseg(sc,1)) {
710 if (sc->fcells < n) {
711 /* If all fail, report failure */
719 static pointer get_consecutive_cells(scheme *sc, int n) {
722 if(sc->no_memory) { return sc->sink; }
724 /* Are there any cells available? */
725 x=find_consecutive_cells(sc,n);
726 if (x != sc->NIL) { return x; }
728 /* If not, try gc'ing some */
729 gc(sc, sc->NIL, sc->NIL);
730 x=find_consecutive_cells(sc,n);
731 if (x != sc->NIL) { return x; }
733 /* If there still aren't, try getting more heap */
734 if (!alloc_cellseg(sc,1))
740 x=find_consecutive_cells(sc,n);
741 if (x != sc->NIL) { return x; }
743 /* If all fail, report failure */
748 static int count_consecutive_cells(pointer x, int needed) {
753 if(n>needed) return n;
758 static pointer find_consecutive_cells(scheme *sc, int n) {
763 while(*pp!=sc->NIL) {
764 cnt=count_consecutive_cells(*pp,n);
776 /* To retain recent allocs before interpreter knows about them -
779 static void push_recent_alloc(scheme *sc, pointer recent, pointer extra)
781 pointer holder = get_cell_x(sc, recent, extra);
782 typeflag(holder) = T_PAIR | T_IMMUTABLE;
783 car(holder) = recent;
784 cdr(holder) = car(sc->sink);
785 car(sc->sink) = holder;
789 static pointer get_cell(scheme *sc, pointer a, pointer b)
791 pointer cell = get_cell_x(sc, a, b);
792 /* For right now, include "a" and "b" in "cell" so that gc doesn't
793 think they are garbage. */
794 /* Tentatively record it as a pair so gc understands it. */
795 typeflag(cell) = T_PAIR;
798 push_recent_alloc(sc, cell, sc->NIL);
802 static pointer get_vector_object(scheme *sc, int len, pointer init)
804 pointer cells = get_consecutive_cells(sc,len/2+len%2+1);
805 if(sc->no_memory) { return sc->sink; }
806 /* Record it as a vector so that gc understands it. */
807 typeflag(cells) = (T_VECTOR | T_ATOM);
808 ivalue_unchecked(cells)=len;
809 set_num_integer(cells);
810 fill_vector(cells,init);
811 push_recent_alloc(sc, cells, sc->NIL);
815 static INLINE void ok_to_freely_gc(scheme *sc)
817 car(sc->sink) = sc->NIL;
822 static void check_cell_alloced(pointer p, int expect_alloced)
824 /* Can't use putstr(sc,str) because callers have no access to
826 if(typeflag(p) & !expect_alloced)
828 fprintf(stderr,"Cell is already allocated!\n");
830 if(!(typeflag(p)) & expect_alloced)
832 fprintf(stderr,"Cell is not allocated!\n");
836 static void check_range_alloced(pointer p, int n, int expect_alloced)
840 { (void)check_cell_alloced(p+i,expect_alloced); }
845 /* Medium level cell allocation */
847 /* get new cons cell */
848 pointer _cons(scheme *sc, pointer a, pointer b, int immutable) {
849 pointer x = get_cell(sc,a, b);
851 typeflag(x) = T_PAIR;
860 /* ========== oblist implementation ========== */
862 #ifndef USE_OBJECT_LIST
864 static int hash_fn(const char *key, int table_size);
866 static pointer oblist_initial_value(scheme *sc)
868 return mk_vector(sc, 461); /* probably should be bigger */
871 /* returns the new symbol */
872 static pointer oblist_add_by_name(scheme *sc, const char *name)
877 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
878 typeflag(x) = T_SYMBOL;
879 setimmutable(car(x));
881 location = hash_fn(name, ivalue_unchecked(sc->oblist));
882 set_vector_elem(sc->oblist, location,
883 immutable_cons(sc, x, vector_elem(sc->oblist, location)));
887 static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
893 location = hash_fn(name, ivalue_unchecked(sc->oblist));
894 for (x = vector_elem(sc->oblist, location); x != sc->NIL; x = cdr(x)) {
896 /* case-insensitive, per R5RS section 2. */
897 if(stricmp(name, s) == 0) {
904 static pointer oblist_all_symbols(scheme *sc)
908 pointer ob_list = sc->NIL;
910 for (i = 0; i < ivalue_unchecked(sc->oblist); i++) {
911 for (x = vector_elem(sc->oblist, i); x != sc->NIL; x = cdr(x)) {
912 ob_list = cons(sc, x, ob_list);
920 static pointer oblist_initial_value(scheme *sc)
925 static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
930 for (x = sc->oblist; x != sc->NIL; x = cdr(x)) {
932 /* case-insensitive, per R5RS section 2. */
933 if(stricmp(name, s) == 0) {
940 /* returns the new symbol */
941 static pointer oblist_add_by_name(scheme *sc, const char *name)
945 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
946 typeflag(x) = T_SYMBOL;
947 setimmutable(car(x));
948 sc->oblist = immutable_cons(sc, x, sc->oblist);
951 static pointer oblist_all_symbols(scheme *sc)
958 static pointer mk_port(scheme *sc, port *p) {
959 pointer x = get_cell(sc, sc->NIL, sc->NIL);
961 typeflag(x) = T_PORT|T_ATOM;
966 pointer mk_foreign_func(scheme *sc, foreign_func f) {
967 pointer x = get_cell(sc, sc->NIL, sc->NIL);
969 typeflag(x) = (T_FOREIGN | T_ATOM);
974 pointer mk_foreign_object(scheme *sc, const foreign_object_vtable *vtable, void *data) {
975 pointer x = get_cell(sc, sc->NIL, sc->NIL);
977 typeflag(x) = (T_FOREIGN_OBJECT | T_ATOM);
978 x->_object._foreign_object._vtable=vtable;
979 x->_object._foreign_object._data = data;
983 INTERFACE pointer mk_character(scheme *sc, int c) {
984 pointer x = get_cell(sc,sc->NIL, sc->NIL);
986 typeflag(x) = (T_CHARACTER | T_ATOM);
987 ivalue_unchecked(x)= c;
992 /* get number atom (integer) */
993 INTERFACE pointer mk_integer(scheme *sc, long n) {
994 pointer x = get_cell(sc,sc->NIL, sc->NIL);
996 typeflag(x) = (T_NUMBER | T_ATOM);
997 ivalue_unchecked(x)= n;
1002 INTERFACE pointer mk_real(scheme *sc, double n) {
1003 pointer x = get_cell(sc,sc->NIL, sc->NIL);
1005 typeflag(x) = (T_NUMBER | T_ATOM);
1006 rvalue_unchecked(x)= n;
1011 static pointer mk_number(scheme *sc, num n) {
1013 return mk_integer(sc,n.value.ivalue);
1015 return mk_real(sc,n.value.rvalue);
1019 /* allocate name to string area */
1020 static char *store_string(scheme *sc, int len_str, const char *str, char fill) {
1023 q=(char*)sc->malloc(len_str+1);
1029 memcpy (q, str, len_str);
1032 memset(q, fill, len_str);
1038 /* get new string */
1039 INTERFACE pointer mk_string(scheme *sc, const char *str) {
1040 return mk_counted_string(sc,str,strlen(str));
1043 INTERFACE pointer mk_counted_string(scheme *sc, const char *str, int len) {
1044 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1045 typeflag(x) = (T_STRING | T_ATOM);
1046 strvalue(x) = store_string(sc,len,str,0);
1051 INTERFACE pointer mk_empty_string(scheme *sc, int len, char fill) {
1052 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1053 typeflag(x) = (T_STRING | T_ATOM);
1054 strvalue(x) = store_string(sc,len,0,fill);
1059 INTERFACE static pointer mk_vector(scheme *sc, int len)
1060 { return get_vector_object(sc,len,sc->NIL); }
1062 INTERFACE static void fill_vector(pointer vec, pointer obj) {
1064 int n = ivalue(vec)/2+ivalue(vec)%2;
1065 for(i=0; i < n; i++) {
1066 typeflag(vec+1+i) = T_PAIR;
1067 setimmutable(vec+1+i);
1073 INTERFACE static pointer vector_elem(pointer vec, int ielem) {
1076 return car(vec+1+n);
1078 return cdr(vec+1+n);
1082 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a) {
1085 return car(vec+1+n)=a;
1087 return cdr(vec+1+n)=a;
1091 /* get new symbol */
1092 INTERFACE pointer mk_symbol(scheme *sc, const char *name) {
1095 /* first check oblist */
1096 x = oblist_find_by_name(sc, name);
1100 x = oblist_add_by_name(sc, name);
1105 INTERFACE pointer gensym(scheme *sc) {
1109 for(; sc->gensym_cnt<LONG_MAX; sc->gensym_cnt++) {
1110 snprintf(name,40,"gensym-%ld",sc->gensym_cnt);
1112 /* first check oblist */
1113 x = oblist_find_by_name(sc, name);
1118 x = oblist_add_by_name(sc, name);
1126 /* double the size of the string buffer */
1127 static int expand_strbuff(scheme *sc) {
1128 size_t new_size = sc->strbuff_size * 2;
1129 char *new_buffer = sc->malloc(new_size);
1130 if (new_buffer == 0) {
1134 memcpy(new_buffer, sc->strbuff, sc->strbuff_size);
1135 sc->free(sc->strbuff);
1136 sc->strbuff = new_buffer;
1137 sc->strbuff_size = new_size;
1141 /* make symbol or number atom from string */
1142 static pointer mk_atom(scheme *sc, char *q) {
1144 int has_dec_point=0;
1148 if((p=strstr(q,"::"))!=0) {
1150 return cons(sc, sc->COLON_HOOK,
1154 cons(sc, mk_atom(sc,p+2), sc->NIL)),
1155 cons(sc, mk_symbol(sc,strlwr(q)), sc->NIL)));
1161 if ((c == '+') || (c == '-')) {
1168 return (mk_symbol(sc, strlwr(q)));
1170 } else if (c == '.') {
1174 return (mk_symbol(sc, strlwr(q)));
1176 } else if (!isdigit(c)) {
1177 return (mk_symbol(sc, strlwr(q)));
1180 for ( ; (c = *p) != 0; ++p) {
1183 if(!has_dec_point) {
1188 else if ((c == 'e') || (c == 'E')) {
1190 has_dec_point = 1; /* decimal point illegal
1193 if ((*p == '-') || (*p == '+') || isdigit(*p)) {
1198 return (mk_symbol(sc, strlwr(q)));
1202 return mk_real(sc,atof(q));
1204 return (mk_integer(sc, atol(q)));
1208 static pointer mk_sharp_const(scheme *sc, char *name) {
1210 char tmp[STRBUFFSIZE];
1212 if (!strcmp(name, "t"))
1214 else if (!strcmp(name, "f"))
1216 else if (*name == 'o') {/* #o (octal) */
1217 snprintf(tmp, STRBUFFSIZE, "0%s", name+1);
1218 sscanf(tmp, "%lo", (long unsigned *)&x);
1219 return (mk_integer(sc, x));
1220 } else if (*name == 'd') { /* #d (decimal) */
1221 sscanf(name+1, "%ld", (long int *)&x);
1222 return (mk_integer(sc, x));
1223 } else if (*name == 'x') { /* #x (hex) */
1224 snprintf(tmp, STRBUFFSIZE, "0x%s", name+1);
1225 sscanf(tmp, "%lx", (long unsigned *)&x);
1226 return (mk_integer(sc, x));
1227 } else if (*name == 'b') { /* #b (binary) */
1228 x = binary_decode(name+1);
1229 return (mk_integer(sc, x));
1230 } else if (*name == '\\') { /* #\w (character) */
1232 if(stricmp(name+1,"space")==0) {
1234 } else if(stricmp(name+1,"newline")==0) {
1236 } else if(stricmp(name+1,"return")==0) {
1238 } else if(stricmp(name+1,"tab")==0) {
1240 } else if(name[1]=='x' && name[2]!=0) {
1242 if(sscanf(name+2,"%x",(unsigned int *)&c1)==1 && c1 < UCHAR_MAX) {
1248 } else if(is_ascii_name(name+1,&c)) {
1251 } else if(name[2]==0) {
1256 return mk_character(sc,c);
1261 /* ========== garbage collector ========== */
1264 * We use algorithm E (Knuth, The Art of Computer Programming Vol.1,
1265 * sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm,
1268 static void mark(pointer a) {
1276 int n = ivalue_unchecked(p)/2+ivalue_unchecked(p)%2;
1277 for(i=0; i < n; i++) {
1278 /* Vector cells will be treated like ordinary cells */
1286 if (q && !is_mark(q)) {
1287 setatom(p); /* a note that we have moved car */
1293 E5: q = cdr(p); /* down cdr */
1294 if (q && !is_mark(q)) {
1300 E6: /* up. Undo the link switching from steps E4 and E5. */
1318 /* garbage collection. parameter a, b is marked. */
1319 static void gc(scheme *sc, pointer a, pointer b) {
1323 if(sc->gc_verbose) {
1324 putstr(sc, "gc...");
1327 /* mark system globals */
1329 mark(sc->global_env);
1331 /* mark current registers */
1335 dump_stack_mark(sc);
1338 mark(sc->save_inport);
1342 /* Mark recent objects the interpreter doesn't know about yet. */
1343 mark(car(sc->sink));
1344 /* Mark any older stuff above nested C calls */
1347 /* mark variables a, b */
1351 /* garbage collect */
1354 sc->free_cell = sc->NIL;
1355 /* free-list is kept sorted by address so as to maintain consecutive
1356 ranges, if possible, for use with vectors. Here we scan the cells
1357 (which are also kept sorted by address) downwards to build the
1358 free-list in sorted order.
1360 for (i = sc->last_cell_seg; i >= 0; i--) {
1361 p = sc->cell_seg[i] + CELL_SEGSIZE;
1362 while (--p >= sc->cell_seg[i]) {
1367 if (typeflag(p) != 0) {
1368 finalize_cell(sc, p);
1373 cdr(p) = sc->free_cell;
1379 if (sc->gc_verbose) {
1381 snprintf(msg,80,"done: %ld cells were recovered.\n", sc->fcells);
1386 static void finalize_cell(scheme *sc, pointer a) {
1388 sc->free(strvalue(a));
1389 } else if(is_port(a)) {
1390 if(a->_object._port->kind&port_file
1391 && a->_object._port->rep.stdio.closeit) {
1392 port_close(sc,a,port_input|port_output);
1393 } else if (a->_object._port->kind & port_srfi6) {
1394 sc->free(a->_object._port->rep.string.start);
1396 sc->free(a->_object._port);
1397 } else if(is_foreign_object(a)) {
1398 a->_object._foreign_object._vtable->finalize(sc, a->_object._foreign_object._data);
1402 /* ========== Routines for Reading ========== */
1404 static int file_push(scheme *sc, const char *fname) {
1407 if (sc->file_i == MAXFIL-1)
1409 fin=fopen(fname,"r");
1412 sc->load_stack[sc->file_i].kind=port_file|port_input;
1413 sc->load_stack[sc->file_i].rep.stdio.file=fin;
1414 sc->load_stack[sc->file_i].rep.stdio.closeit=1;
1415 sc->nesting_stack[sc->file_i]=0;
1416 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1419 sc->load_stack[sc->file_i].rep.stdio.curr_line = 0;
1421 sc->load_stack[sc->file_i].rep.stdio.filename = store_string(sc, strlen(fname), fname, 0);
1427 static void file_pop(scheme *sc) {
1428 if(sc->file_i != 0) {
1429 sc->nesting=sc->nesting_stack[sc->file_i];
1430 port_close(sc,sc->loadport,port_input);
1432 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1436 static int file_interactive(scheme *sc) {
1437 return sc->file_i==0 && sc->load_stack[0].rep.stdio.file==stdin
1438 && sc->inport->_object._port->kind&port_file;
1441 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop) {
1445 if(prop==(port_input|port_output)) {
1447 } else if(prop==port_output) {
1456 pt=port_rep_from_file(sc,f,prop);
1457 pt->rep.stdio.closeit=1;
1461 pt->rep.stdio.filename = store_string(sc, strlen(fn), fn, 0);
1463 pt->rep.stdio.curr_line = 0;
1468 static pointer port_from_filename(scheme *sc, const char *fn, int prop) {
1470 pt=port_rep_from_filename(sc,fn,prop);
1474 return mk_port(sc,pt);
1477 static port *port_rep_from_file(scheme *sc, FILE *f, int prop)
1481 pt = (port *)sc->malloc(sizeof *pt);
1485 pt->kind = port_file | prop;
1486 pt->rep.stdio.file = f;
1487 pt->rep.stdio.closeit = 0;
1491 static pointer port_from_file(scheme *sc, FILE *f, int prop) {
1493 pt=port_rep_from_file(sc,f,prop);
1497 return mk_port(sc,pt);
1500 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1502 pt=(port*)sc->malloc(sizeof(port));
1506 pt->kind=port_string|prop;
1507 pt->rep.string.start=start;
1508 pt->rep.string.curr=start;
1509 pt->rep.string.past_the_end=past_the_end;
1513 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1515 pt=port_rep_from_string(sc,start,past_the_end,prop);
1519 return mk_port(sc,pt);
1522 #define BLOCK_SIZE 256
1524 static port *port_rep_from_scratch(scheme *sc) {
1527 pt=(port*)sc->malloc(sizeof(port));
1531 start=sc->malloc(BLOCK_SIZE);
1535 memset(start,' ',BLOCK_SIZE-1);
1536 start[BLOCK_SIZE-1]='\0';
1537 pt->kind=port_string|port_output|port_srfi6;
1538 pt->rep.string.start=start;
1539 pt->rep.string.curr=start;
1540 pt->rep.string.past_the_end=start+BLOCK_SIZE-1;
1544 static pointer port_from_scratch(scheme *sc) {
1546 pt=port_rep_from_scratch(sc);
1550 return mk_port(sc,pt);
1553 static void port_close(scheme *sc, pointer p, int flag) {
1554 port *pt=p->_object._port;
1556 if((pt->kind & (port_input|port_output))==0) {
1557 if(pt->kind&port_file) {
1560 /* Cleanup is here so (close-*-port) functions could work too */
1561 pt->rep.stdio.curr_line = 0;
1563 if(pt->rep.stdio.filename)
1564 sc->free(pt->rep.stdio.filename);
1567 fclose(pt->rep.stdio.file);
1573 /* get new character from input file */
1574 static int inchar(scheme *sc) {
1578 pt = sc->inport->_object._port;
1579 if(pt->kind & port_saw_EOF)
1581 c = basic_inchar(pt);
1582 if(c == EOF && sc->inport == sc->loadport) {
1583 /* Instead, set port_saw_EOF */
1584 pt->kind |= port_saw_EOF;
1593 static int basic_inchar(port *pt) {
1594 if(pt->kind & port_file) {
1595 return fgetc(pt->rep.stdio.file);
1597 if(*pt->rep.string.curr == 0 ||
1598 pt->rep.string.curr == pt->rep.string.past_the_end) {
1601 return *pt->rep.string.curr++;
1606 /* back character to input buffer */
1607 static void backchar(scheme *sc, int c) {
1610 pt=sc->inport->_object._port;
1611 if(pt->kind&port_file) {
1612 ungetc(c,pt->rep.stdio.file);
1614 if(pt->rep.string.curr!=pt->rep.string.start) {
1615 --pt->rep.string.curr;
1620 static int realloc_port_string(scheme *sc, port *p)
1622 char *start=p->rep.string.start;
1623 size_t old_size = p->rep.string.past_the_end - start;
1624 size_t new_size=p->rep.string.past_the_end-start+1+BLOCK_SIZE;
1625 char *str=sc->malloc(new_size);
1627 memset(str,' ',new_size-1);
1628 str[new_size-1]='\0';
1629 memcpy(str, start, old_size);
1630 p->rep.string.start=str;
1631 p->rep.string.past_the_end=str+new_size-1;
1632 p->rep.string.curr-=start-str;
1640 INTERFACE void putstr(scheme *sc, const char *s) {
1641 port *pt=sc->outport->_object._port;
1642 if(pt->kind&port_file) {
1643 fputs(s,pt->rep.stdio.file);
1646 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
1647 *pt->rep.string.curr++=*s;
1648 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
1649 *pt->rep.string.curr++=*s;
1655 static void putchars(scheme *sc, const char *s, int len) {
1656 port *pt=sc->outport->_object._port;
1657 if(pt->kind&port_file) {
1658 fwrite(s,1,len,pt->rep.stdio.file);
1661 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
1662 *pt->rep.string.curr++=*s++;
1663 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
1664 *pt->rep.string.curr++=*s++;
1670 INTERFACE void putcharacter(scheme *sc, int c) {
1671 port *pt=sc->outport->_object._port;
1672 if(pt->kind&port_file) {
1673 fputc(c,pt->rep.stdio.file);
1675 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
1676 *pt->rep.string.curr++=c;
1677 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
1678 *pt->rep.string.curr++=c;
1683 /* read characters up to delimiter, but cater to character constants */
1684 static char *readstr_upto(scheme *sc, char *delim) {
1685 char *p = sc->strbuff;
1687 while ((p - sc->strbuff < sc->strbuff_size) &&
1688 !is_one_of(delim, (*p++ = inchar(sc))));
1690 if(p == sc->strbuff+2 && p[-2] == '\\') {
1699 /* read string expression "xxx...xxx" */
1700 static pointer readstrexp(scheme *sc) {
1701 char *p = sc->strbuff;
1704 enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state=st_ok;
1711 if(p-sc->strbuff > (sc->strbuff_size)-1) {
1712 ptrdiff_t offset = p - sc->strbuff;
1713 if (expand_strbuff(sc) != 0) {
1716 p = sc->strbuff + offset;
1726 return mk_counted_string(sc,sc->strbuff,p-sc->strbuff);
1775 if(c>='0' && c<='F') {
1779 c1=(c1<<4)+c-'A'+10;
1793 if (c < '0' || c > '7')
1801 if (state==st_oct2 && c1 >= 32)
1806 if (state == st_oct1)
1820 /* check c is in chars */
1821 static INLINE int is_one_of(char *s, int c) {
1822 if(c==EOF) return 1;
1829 /* skip white characters */
1830 static INLINE int skipspace(scheme *sc) {
1831 int c = 0, curr_line = 0;
1839 } while (isspace(c));
1843 if (sc->load_stack[sc->file_i].kind & port_file)
1844 sc->load_stack[sc->file_i].rep.stdio.curr_line += curr_line;
1856 static int token(scheme *sc) {
1859 if(c == EOF) { return (TOK_EOF); }
1860 switch (c=inchar(sc)) {
1864 return (TOK_LPAREN);
1866 return (TOK_RPAREN);
1869 if(is_one_of(" \n\t",c)) {
1879 while ((c=inchar(sc)) != '\n' && c!=EOF)
1883 if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
1884 sc->load_stack[sc->file_i].rep.stdio.curr_line++;
1888 { return (TOK_EOF); }
1890 { return (token(sc));}
1892 return (TOK_DQUOTE);
1894 return (TOK_BQUOTE);
1896 if ((c=inchar(sc)) == '@') {
1897 return (TOK_ATMARK);
1906 } else if(c == '!') {
1907 while ((c=inchar(sc)) != '\n' && c!=EOF)
1911 if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
1912 sc->load_stack[sc->file_i].rep.stdio.curr_line++;
1916 { return (TOK_EOF); }
1918 { return (token(sc));}
1921 if(is_one_of(" tfodxb\\",c)) {
1922 return TOK_SHARP_CONST;
1933 /* ========== Routines for Printing ========== */
1934 #define ok_abbrev(x) (is_pair(x) && cdr(x) == sc->NIL)
1936 static void printslashstring(scheme *sc, char *p, int len) {
1938 unsigned char *s=(unsigned char*)p;
1939 putcharacter(sc,'"');
1940 for ( i=0; i<len; i++) {
1941 if(*s==0xff || *s=='"' || *s<' ' || *s=='\\') {
1942 putcharacter(sc,'\\');
1945 putcharacter(sc,'"');
1948 putcharacter(sc,'n');
1951 putcharacter(sc,'t');
1954 putcharacter(sc,'r');
1957 putcharacter(sc,'\\');
1961 putcharacter(sc,'x');
1963 putcharacter(sc,d+'0');
1965 putcharacter(sc,d-10+'A');
1969 putcharacter(sc,d+'0');
1971 putcharacter(sc,d-10+'A');
1976 putcharacter(sc,*s);
1980 putcharacter(sc,'"');
1985 static void printatom(scheme *sc, pointer l, int f) {
1988 atom2str(sc,l,f,&p,&len);
1993 /* Uses internal buffer unless string pointer is already available */
1994 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen) {
1999 } else if (l == sc->T) {
2001 } else if (l == sc->F) {
2003 } else if (l == sc->EOF_OBJ) {
2005 } else if (is_port(l)) {
2007 } else if (is_number(l)) {
2009 if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */ {
2010 if(num_is_integer(l)) {
2011 snprintf(p, STRBUFFSIZE, "%ld", ivalue_unchecked(l));
2013 snprintf(p, STRBUFFSIZE, "%.10g", rvalue_unchecked(l));
2014 /* r5rs says there must be a '.' (unless 'e'?) */
2015 f = strcspn(p, ".e");
2017 p[f] = '.'; /* not found, so add '.0' at the end */
2026 snprintf(p, STRBUFFSIZE, "%lx", v);
2028 snprintf(p, STRBUFFSIZE, "-%lx", -v);
2029 } else if (f == 8) {
2031 snprintf(p, STRBUFFSIZE, "%lo", v);
2033 snprintf(p, STRBUFFSIZE, "-%lo", -v);
2034 } else if (f == 2) {
2035 unsigned long b = (v < 0) ? -v : v;
2036 p = &p[STRBUFFSIZE-1];
2038 do { *--p = (b&1) ? '1' : '0'; b >>= 1; } while (b != 0);
2039 if (v < 0) *--p = '-';
2042 } else if (is_string(l)) {
2045 } else { /* Hack, uses the fact that printing is needed */
2048 printslashstring(sc, strvalue(l), strlength(l));
2051 } else if (is_character(l)) {
2077 snprintf(p,STRBUFFSIZE, "#\\%s",charnames[c]);
2082 snprintf(p,STRBUFFSIZE,"#\\x%x",c);
2086 snprintf(p,STRBUFFSIZE,"#\\%c",c);
2090 } else if (is_symbol(l)) {
2092 } else if (is_proc(l)) {
2094 snprintf(p,STRBUFFSIZE,"#<%s PROCEDURE %ld>", procname(l),procnum(l));
2095 } else if (is_macro(l)) {
2097 } else if (is_closure(l)) {
2099 } else if (is_promise(l)) {
2101 } else if (is_foreign(l)) {
2103 snprintf(p,STRBUFFSIZE,"#<FOREIGN PROCEDURE %ld>", procnum(l));
2104 } else if (is_continuation(l)) {
2105 p = "#<CONTINUATION>";
2106 } else if (is_foreign_object(l)) {
2108 l->_object._foreign_object._vtable->to_string(sc, p, STRBUFFSIZE, l->_object._foreign_object._data);
2115 /* ========== Routines for Evaluation Cycle ========== */
2117 /* make closure. c is code. e is environment */
2118 static pointer mk_closure(scheme *sc, pointer c, pointer e) {
2119 pointer x = get_cell(sc, c, e);
2121 typeflag(x) = T_CLOSURE;
2127 /* make continuation. */
2128 static pointer mk_continuation(scheme *sc, pointer d) {
2129 pointer x = get_cell(sc, sc->NIL, d);
2131 typeflag(x) = T_CONTINUATION;
2136 static pointer list_star(scheme *sc, pointer d) {
2138 if(cdr(d)==sc->NIL) {
2141 p=cons(sc,car(d),cdr(d));
2143 while(cdr(cdr(p))!=sc->NIL) {
2144 d=cons(sc,car(p),cdr(p));
2145 if(cdr(cdr(p))!=sc->NIL) {
2153 /* reverse list -- produce new list */
2154 static pointer reverse(scheme *sc, pointer a) {
2155 /* a must be checked by gc */
2156 pointer p = sc->NIL;
2158 for ( ; is_pair(a); a = cdr(a)) {
2159 p = cons(sc, car(a), p);
2164 /* reverse list --- in-place */
2165 static pointer reverse_in_place(scheme *sc, pointer term, pointer list) {
2166 pointer p = list, result = term, q;
2168 while (p != sc->NIL) {
2177 /* append list -- produce new list (in reverse order) */
2178 static pointer revappend(scheme *sc, pointer a, pointer b) {
2182 while (is_pair(p)) {
2183 result = cons(sc, car(p), result);
2191 return sc->F; /* signal an error */
2194 /* equivalence of atoms */
2195 int eqv(pointer a, pointer b) {
2198 return (strvalue(a) == strvalue(b));
2201 } else if (is_number(a)) {
2203 if (num_is_integer(a) == num_is_integer(b))
2204 return num_eq(nvalue(a),nvalue(b));
2207 } else if (is_character(a)) {
2208 if (is_character(b))
2209 return charvalue(a)==charvalue(b);
2212 } else if (is_port(a)) {
2217 } else if (is_proc(a)) {
2219 return procnum(a)==procnum(b);
2227 /* true or false value macro */
2228 /* () is #t in R5RS */
2229 #define is_true(p) ((p) != sc->F)
2230 #define is_false(p) ((p) == sc->F)
2232 /* ========== Environment implementation ========== */
2234 #if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
2236 static int hash_fn(const char *key, int table_size)
2238 unsigned int hashed = 0;
2240 int bits_per_int = sizeof(unsigned int)*8;
2242 for (c = key; *c; c++) {
2243 /* letters have about 5 bits in them */
2244 hashed = (hashed<<5) | (hashed>>(bits_per_int-5));
2247 return hashed % table_size;
2251 #ifndef USE_ALIST_ENV
2254 * In this implementation, each frame of the environment may be
2255 * a hash table: a vector of alists hashed by variable name.
2256 * In practice, we use a vector only for the initial frame;
2257 * subsequent frames are too small and transient for the lookup
2258 * speed to out-weigh the cost of making a new vector.
2261 static void new_frame_in_env(scheme *sc, pointer old_env)
2265 /* The interaction-environment has about 300 variables in it. */
2266 if (old_env == sc->NIL) {
2267 new_frame = mk_vector(sc, 461);
2269 new_frame = sc->NIL;
2272 sc->envir = immutable_cons(sc, new_frame, old_env);
2273 setenvironment(sc->envir);
2276 static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
2277 pointer variable, pointer value)
2279 pointer slot = immutable_cons(sc, variable, value);
2281 if (is_vector(car(env))) {
2282 int location = hash_fn(symname(variable), ivalue_unchecked(car(env)));
2284 set_vector_elem(car(env), location,
2285 immutable_cons(sc, slot, vector_elem(car(env), location)));
2287 car(env) = immutable_cons(sc, slot, car(env));
2291 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
2296 for (x = env; x != sc->NIL; x = cdr(x)) {
2297 if (is_vector(car(x))) {
2298 location = hash_fn(symname(hdl), ivalue_unchecked(car(x)));
2299 y = vector_elem(car(x), location);
2303 for ( ; y != sc->NIL; y = cdr(y)) {
2304 if (caar(y) == hdl) {
2321 #else /* USE_ALIST_ENV */
2323 static INLINE void new_frame_in_env(scheme *sc, pointer old_env)
2325 sc->envir = immutable_cons(sc, sc->NIL, old_env);
2326 setenvironment(sc->envir);
2329 static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
2330 pointer variable, pointer value)
2332 car(env) = immutable_cons(sc, immutable_cons(sc, variable, value), car(env));
2335 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
2338 for (x = env; x != sc->NIL; x = cdr(x)) {
2339 for (y = car(x); y != sc->NIL; y = cdr(y)) {
2340 if (caar(y) == hdl) {
2357 #endif /* USE_ALIST_ENV else */
2359 static INLINE void new_slot_in_env(scheme *sc, pointer variable, pointer value)
2361 new_slot_spec_in_env(sc, sc->envir, variable, value);
2364 static INLINE void set_slot_in_env(scheme *sc, pointer slot, pointer value)
2370 static INLINE pointer slot_value_in_env(pointer slot)
2375 /* ========== Evaluation Cycle ========== */
2378 static pointer _Error_1(scheme *sc, const char *s, pointer a) {
2379 const char *str = s;
2382 pointer hdl=sc->ERROR_HOOK;
2386 char sbuf[STRBUFFSIZE];
2388 /* make sure error is not in REPL */
2389 if (sc->load_stack[sc->file_i].kind & port_file &&
2390 sc->load_stack[sc->file_i].rep.stdio.file != stdin) {
2391 int ln = sc->load_stack[sc->file_i].rep.stdio.curr_line;
2392 const char *fname = sc->load_stack[sc->file_i].rep.stdio.filename;
2394 /* should never happen */
2395 if(!fname) fname = "<unknown>";
2397 /* we started from 0 */
2399 snprintf(sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s);
2401 str = (const char*)sbuf;
2406 x=find_slot_in_env(sc,sc->envir,hdl,1);
2409 sc->code = cons(sc, cons(sc, sc->QUOTE, cons(sc,(a), sc->NIL)), sc->NIL);
2413 sc->code = cons(sc, mk_string(sc, str), sc->code);
2414 setimmutable(car(sc->code));
2415 sc->code = cons(sc, slot_value_in_env(x), sc->code);
2416 sc->op = (int)OP_EVAL;
2422 sc->args = cons(sc, (a), sc->NIL);
2426 sc->args = cons(sc, mk_string(sc, str), sc->args);
2427 setimmutable(car(sc->args));
2428 sc->op = (int)OP_ERR0;
2431 #define Error_1(sc,s, a) return _Error_1(sc,s,a)
2432 #define Error_0(sc,s) return _Error_1(sc,s,0)
2434 /* Too small to turn into function */
2436 # define END } while (0)
2437 #define s_goto(sc,a) BEGIN \
2438 sc->op = (int)(a); \
2441 #define s_return(sc,a) return _s_return(sc,a)
2443 #ifndef USE_SCHEME_STACK
2445 /* this structure holds all the interpreter's registers */
2446 struct dump_stack_frame {
2447 enum scheme_opcodes op;
2453 #define STACK_GROWTH 3
2455 static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code)
2457 int nframes = (int)sc->dump;
2458 struct dump_stack_frame *next_frame;
2460 /* enough room for the next frame? */
2461 if (nframes >= sc->dump_size) {
2462 sc->dump_size += STACK_GROWTH;
2463 /* alas there is no sc->realloc */
2464 sc->dump_base = realloc(sc->dump_base,
2465 sizeof(struct dump_stack_frame) * sc->dump_size);
2467 next_frame = (struct dump_stack_frame *)sc->dump_base + nframes;
2468 next_frame->op = op;
2469 next_frame->args = args;
2470 next_frame->envir = sc->envir;
2471 next_frame->code = code;
2472 sc->dump = (pointer)(nframes+1);
2475 static pointer _s_return(scheme *sc, pointer a)
2477 int nframes = (int)sc->dump;
2478 struct dump_stack_frame *frame;
2485 frame = (struct dump_stack_frame *)sc->dump_base + nframes;
2487 sc->args = frame->args;
2488 sc->envir = frame->envir;
2489 sc->code = frame->code;
2490 sc->dump = (pointer)nframes;
2494 static INLINE void dump_stack_reset(scheme *sc)
2496 /* in this implementation, sc->dump is the number of frames on the stack */
2497 sc->dump = (pointer)0;
2500 static INLINE void dump_stack_initialize(scheme *sc)
2503 sc->dump_base = NULL;
2504 dump_stack_reset(sc);
2507 static void dump_stack_free(scheme *sc)
2509 free(sc->dump_base);
2510 sc->dump_base = NULL;
2511 sc->dump = (pointer)0;
2515 static INLINE void dump_stack_mark(scheme *sc)
2517 int nframes = (int)sc->dump;
2519 for(i=0; i<nframes; i++) {
2520 struct dump_stack_frame *frame;
2521 frame = (struct dump_stack_frame *)sc->dump_base + i;
2530 static INLINE void dump_stack_reset(scheme *sc)
2535 static INLINE void dump_stack_initialize(scheme *sc)
2537 dump_stack_reset(sc);
2540 static void dump_stack_free(scheme *sc)
2545 static pointer _s_return(scheme *sc, pointer a) {
2547 if(sc->dump==sc->NIL) return sc->NIL;
2548 sc->op = ivalue(car(sc->dump));
2549 sc->args = cadr(sc->dump);
2550 sc->envir = caddr(sc->dump);
2551 sc->code = cadddr(sc->dump);
2552 sc->dump = cddddr(sc->dump);
2556 static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) {
2557 sc->dump = cons(sc, sc->envir, cons(sc, (code), sc->dump));
2558 sc->dump = cons(sc, (args), sc->dump);
2559 sc->dump = cons(sc, mk_integer(sc, (long)(op)), sc->dump);
2562 static INLINE void dump_stack_mark(scheme *sc)
2568 #define s_retbool(tf) s_return(sc,(tf) ? sc->T : sc->F)
2570 static pointer opexe_0(scheme *sc, enum scheme_opcodes op) {
2574 case OP_LOAD: /* load */
2575 if(file_interactive(sc)) {
2576 fprintf(sc->outport->_object._port->rep.stdio.file,
2577 "Loading %s\n", strvalue(car(sc->args)));
2579 if (!file_push(sc,strvalue(car(sc->args)))) {
2580 Error_1(sc,"unable to open", car(sc->args));
2584 sc->args = mk_integer(sc,sc->file_i);
2585 s_goto(sc,OP_T0LVL);
2588 case OP_T0LVL: /* top level */
2589 /* If we reached the end of file, this loop is done. */
2590 if(sc->loadport->_object._port->kind & port_saw_EOF)
2600 s_return(sc,sc->value);
2605 /* If interactive, be nice to user. */
2606 if(file_interactive(sc))
2608 sc->envir = sc->global_env;
2609 dump_stack_reset(sc);
2614 /* Set up another iteration of REPL */
2616 sc->save_inport=sc->inport;
2617 sc->inport = sc->loadport;
2618 s_save(sc,OP_T0LVL, sc->NIL, sc->NIL);
2619 s_save(sc,OP_VALUEPRINT, sc->NIL, sc->NIL);
2620 s_save(sc,OP_T1LVL, sc->NIL, sc->NIL);
2621 s_goto(sc,OP_READ_INTERNAL);
2623 case OP_T1LVL: /* top level */
2624 sc->code = sc->value;
2625 sc->inport=sc->save_inport;
2628 case OP_READ_INTERNAL: /* internal read */
2629 sc->tok = token(sc);
2630 if(sc->tok==TOK_EOF)
2631 { s_return(sc,sc->EOF_OBJ); }
2632 s_goto(sc,OP_RDSEXPR);
2635 s_return(sc, gensym(sc));
2637 case OP_VALUEPRINT: /* print evaluation result */
2638 /* OP_VALUEPRINT is always pushed, because when changing from
2639 non-interactive to interactive mode, it needs to be
2640 already on the stack */
2642 putstr(sc,"\nGives: ");
2644 if(file_interactive(sc)) {
2646 sc->args = sc->value;
2647 s_goto(sc,OP_P0LIST);
2649 s_return(sc,sc->value);
2652 case OP_EVAL: /* main part of evaluation */
2655 /*s_save(sc,OP_VALUEPRINT,sc->NIL,sc->NIL);*/
2656 s_save(sc,OP_REAL_EVAL,sc->args,sc->code);
2658 putstr(sc,"\nEval: ");
2659 s_goto(sc,OP_P0LIST);
2664 if (is_symbol(sc->code)) { /* symbol */
2665 x=find_slot_in_env(sc,sc->envir,sc->code,1);
2667 s_return(sc,slot_value_in_env(x));
2669 Error_1(sc,"eval: unbound variable:", sc->code);
2671 } else if (is_pair(sc->code)) {
2672 if (is_syntax(x = car(sc->code))) { /* SYNTAX */
2673 sc->code = cdr(sc->code);
2674 s_goto(sc,syntaxnum(x));
2675 } else {/* first, eval top element and eval arguments */
2676 s_save(sc,OP_E0ARGS, sc->NIL, sc->code);
2677 /* If no macros => s_save(sc,OP_E1ARGS, sc->NIL, cdr(sc->code));*/
2678 sc->code = car(sc->code);
2682 s_return(sc,sc->code);
2685 case OP_E0ARGS: /* eval arguments */
2686 if (is_macro(sc->value)) { /* macro expansion */
2687 s_save(sc,OP_DOMACRO, sc->NIL, sc->NIL);
2688 sc->args = cons(sc,sc->code, sc->NIL);
2689 sc->code = sc->value;
2690 s_goto(sc,OP_APPLY);
2692 sc->code = cdr(sc->code);
2693 s_goto(sc,OP_E1ARGS);
2696 case OP_E1ARGS: /* eval arguments */
2697 sc->args = cons(sc, sc->value, sc->args);
2698 if (is_pair(sc->code)) { /* continue */
2699 s_save(sc,OP_E1ARGS, sc->args, cdr(sc->code));
2700 sc->code = car(sc->code);
2704 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
2705 sc->code = car(sc->args);
2706 sc->args = cdr(sc->args);
2707 s_goto(sc,OP_APPLY);
2713 sc->tracing=ivalue(car(sc->args));
2714 s_return(sc,mk_integer(sc,tr));
2718 case OP_APPLY: /* apply 'code' to 'args' */
2721 s_save(sc,OP_REAL_APPLY,sc->args,sc->code);
2723 /* sc->args=cons(sc,sc->code,sc->args);*/
2724 putstr(sc,"\nApply to: ");
2725 s_goto(sc,OP_P0LIST);
2730 if (is_proc(sc->code)) {
2731 s_goto(sc,procnum(sc->code)); /* PROCEDURE */
2732 } else if (is_foreign(sc->code))
2734 /* Keep nested calls from GC'ing the arglist */
2735 push_recent_alloc(sc,sc->args,sc->NIL);
2736 x=sc->code->_object._ff(sc,sc->args);
2738 } else if (is_closure(sc->code) || is_macro(sc->code)
2739 || is_promise(sc->code)) { /* CLOSURE */
2740 /* Should not accept promise */
2741 /* make environment */
2742 new_frame_in_env(sc, closure_env(sc->code));
2743 for (x = car(closure_code(sc->code)), y = sc->args;
2744 is_pair(x); x = cdr(x), y = cdr(y)) {
2746 Error_0(sc,"not enough arguments");
2748 new_slot_in_env(sc, car(x), car(y));
2753 * if (y != sc->NIL) {
2754 * Error_0(sc,"too many arguments");
2757 } else if (is_symbol(x))
2758 new_slot_in_env(sc, x, y);
2760 Error_1(sc,"syntax error in closure: not a symbol:", x);
2762 sc->code = cdr(closure_code(sc->code));
2764 s_goto(sc,OP_BEGIN);
2765 } else if (is_continuation(sc->code)) { /* CONTINUATION */
2766 sc->dump = cont_dump(sc->code);
2767 s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL);
2769 Error_1(sc,"illegal function",sc->code);
2772 case OP_DOMACRO: /* do macro */
2773 sc->code = sc->value;
2777 case OP_LAMBDA: /* lambda */
2778 /* If the hook is defined, apply it to sc->code, otherwise
2779 set sc->value fall thru */
2781 pointer f=find_slot_in_env(sc,sc->envir,sc->COMPILE_HOOK,1);
2783 sc->value = sc->code;
2786 s_save(sc,OP_LAMBDA1,sc->args,sc->code);
2787 sc->args=cons(sc,sc->code,sc->NIL);
2788 sc->code=slot_value_in_env(f);
2789 s_goto(sc,OP_APPLY);
2794 s_return(sc,mk_closure(sc, sc->value, sc->envir));
2797 case OP_LAMBDA: /* lambda */
2798 s_return(sc,mk_closure(sc, sc->code, sc->envir));
2802 case OP_MKCLOSURE: /* make-closure */
2804 if(car(x)==sc->LAMBDA) {
2807 if(cdr(sc->args)==sc->NIL) {
2812 s_return(sc,mk_closure(sc, x, y));
2814 case OP_QUOTE: /* quote */
2815 s_return(sc,car(sc->code));
2817 case OP_DEF0: /* define */
2818 if(is_immutable(car(sc->code)))
2819 Error_1(sc,"define: unable to alter immutable", car(sc->code));
2821 if (is_pair(car(sc->code))) {
2823 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
2826 sc->code = cadr(sc->code);
2828 if (!is_symbol(x)) {
2829 Error_0(sc,"variable is not a symbol");
2831 s_save(sc,OP_DEF1, sc->NIL, x);
2834 case OP_DEF1: /* define */
2835 x=find_slot_in_env(sc,sc->envir,sc->code,0);
2837 set_slot_in_env(sc, x, sc->value);
2839 new_slot_in_env(sc, sc->code, sc->value);
2841 s_return(sc,sc->code);
2844 case OP_DEFP: /* defined? */
2846 if(cdr(sc->args)!=sc->NIL) {
2849 s_retbool(find_slot_in_env(sc,x,car(sc->args),1)!=sc->NIL);
2851 case OP_SET0: /* set! */
2852 if(is_immutable(car(sc->code)))
2853 Error_1(sc,"set!: unable to alter immutable variable",car(sc->code));
2854 s_save(sc,OP_SET1, sc->NIL, car(sc->code));
2855 sc->code = cadr(sc->code);
2858 case OP_SET1: /* set! */
2859 y=find_slot_in_env(sc,sc->envir,sc->code,1);
2861 set_slot_in_env(sc, y, sc->value);
2862 s_return(sc,sc->value);
2864 Error_1(sc,"set!: unbound variable:", sc->code);
2868 case OP_BEGIN: /* begin */
2869 if (!is_pair(sc->code)) {
2870 s_return(sc,sc->code);
2872 if (cdr(sc->code) != sc->NIL) {
2873 s_save(sc,OP_BEGIN, sc->NIL, cdr(sc->code));
2875 sc->code = car(sc->code);
2878 case OP_IF0: /* if */
2879 s_save(sc,OP_IF1, sc->NIL, cdr(sc->code));
2880 sc->code = car(sc->code);
2883 case OP_IF1: /* if */
2884 if (is_true(sc->value))
2885 sc->code = car(sc->code);
2887 sc->code = cadr(sc->code); /* (if #f 1) ==> () because
2888 * car(sc->NIL) = sc->NIL */
2891 case OP_LET0: /* let */
2893 sc->value = sc->code;
2894 sc->code = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code);
2897 case OP_LET1: /* let (calculate parameters) */
2898 sc->args = cons(sc, sc->value, sc->args);
2899 if (is_pair(sc->code)) { /* continue */
2900 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
2901 Error_1(sc, "Bad syntax of binding spec in let :",
2904 s_save(sc,OP_LET1, sc->args, cdr(sc->code));
2905 sc->code = cadar(sc->code);
2909 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
2910 sc->code = car(sc->args);
2911 sc->args = cdr(sc->args);
2915 case OP_LET2: /* let */
2916 new_frame_in_env(sc, sc->envir);
2917 for (x = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code), y = sc->args;
2918 y != sc->NIL; x = cdr(x), y = cdr(y)) {
2919 new_slot_in_env(sc, caar(x), car(y));
2921 if (is_symbol(car(sc->code))) { /* named let */
2922 for (x = cadr(sc->code), sc->args = sc->NIL; x != sc->NIL; x = cdr(x)) {
2924 Error_1(sc, "Bad syntax of binding in let :", x);
2925 if (!is_list(sc, car(x)))
2926 Error_1(sc, "Bad syntax of binding in let :", car(x));
2927 sc->args = cons(sc, caar(x), sc->args);
2929 x = mk_closure(sc, cons(sc, reverse_in_place(sc, sc->NIL, sc->args), cddr(sc->code)), sc->envir);
2930 new_slot_in_env(sc, car(sc->code), x);
2931 sc->code = cddr(sc->code);
2934 sc->code = cdr(sc->code);
2937 s_goto(sc,OP_BEGIN);
2939 case OP_LET0AST: /* let* */
2940 if (car(sc->code) == sc->NIL) {
2941 new_frame_in_env(sc, sc->envir);
2942 sc->code = cdr(sc->code);
2943 s_goto(sc,OP_BEGIN);
2945 if(!is_pair(car(sc->code)) || !is_pair(caar(sc->code)) || !is_pair(cdaar(sc->code))) {
2946 Error_1(sc,"Bad syntax of binding spec in let* :",car(sc->code));
2948 s_save(sc,OP_LET1AST, cdr(sc->code), car(sc->code));
2949 sc->code = cadaar(sc->code);
2952 case OP_LET1AST: /* let* (make new frame) */
2953 new_frame_in_env(sc, sc->envir);
2954 s_goto(sc,OP_LET2AST);
2956 case OP_LET2AST: /* let* (calculate parameters) */
2957 new_slot_in_env(sc, caar(sc->code), sc->value);
2958 sc->code = cdr(sc->code);
2959 if (is_pair(sc->code)) { /* continue */
2960 s_save(sc,OP_LET2AST, sc->args, sc->code);
2961 sc->code = cadar(sc->code);
2965 sc->code = sc->args;
2967 s_goto(sc,OP_BEGIN);
2970 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
2971 Error_0(sc,sc->strbuff);
2976 static pointer opexe_1(scheme *sc, enum scheme_opcodes op) {
2980 case OP_LET0REC: /* letrec */
2981 new_frame_in_env(sc, sc->envir);
2983 sc->value = sc->code;
2984 sc->code = car(sc->code);
2985 s_goto(sc,OP_LET1REC);
2987 case OP_LET1REC: /* letrec (calculate parameters) */
2988 sc->args = cons(sc, sc->value, sc->args);
2989 if (is_pair(sc->code)) { /* continue */
2990 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
2991 Error_1(sc, "Bad syntax of binding spec in letrec :",
2994 s_save(sc,OP_LET1REC, sc->args, cdr(sc->code));
2995 sc->code = cadar(sc->code);
2999 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3000 sc->code = car(sc->args);
3001 sc->args = cdr(sc->args);
3002 s_goto(sc,OP_LET2REC);
3005 case OP_LET2REC: /* letrec */
3006 for (x = car(sc->code), y = sc->args; y != sc->NIL; x = cdr(x), y = cdr(y)) {
3007 new_slot_in_env(sc, caar(x), car(y));
3009 sc->code = cdr(sc->code);
3011 s_goto(sc,OP_BEGIN);
3013 case OP_COND0: /* cond */
3014 if (!is_pair(sc->code)) {
3015 Error_0(sc,"syntax error in cond");
3017 s_save(sc,OP_COND1, sc->NIL, sc->code);
3018 sc->code = caar(sc->code);
3021 case OP_COND1: /* cond */
3022 if (is_true(sc->value)) {
3023 if ((sc->code = cdar(sc->code)) == sc->NIL) {
3024 s_return(sc,sc->value);
3026 if(!sc->code || car(sc->code)==sc->FEED_TO) {
3027 if(!is_pair(cdr(sc->code))) {
3028 Error_0(sc,"syntax error in cond");
3030 x=cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL));
3031 sc->code=cons(sc,cadr(sc->code),cons(sc,x,sc->NIL));
3034 s_goto(sc,OP_BEGIN);
3036 if ((sc->code = cdr(sc->code)) == sc->NIL) {
3037 s_return(sc,sc->NIL);
3039 s_save(sc,OP_COND1, sc->NIL, sc->code);
3040 sc->code = caar(sc->code);
3045 case OP_DELAY: /* delay */
3046 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
3047 typeflag(x)=T_PROMISE;
3050 case OP_AND0: /* and */
3051 if (sc->code == sc->NIL) {
3054 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
3055 sc->code = car(sc->code);
3058 case OP_AND1: /* and */
3059 if (is_false(sc->value)) {
3060 s_return(sc,sc->value);
3061 } else if (sc->code == sc->NIL) {
3062 s_return(sc,sc->value);
3064 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
3065 sc->code = car(sc->code);
3069 case OP_OR0: /* or */
3070 if (sc->code == sc->NIL) {
3073 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
3074 sc->code = car(sc->code);
3077 case OP_OR1: /* or */
3078 if (is_true(sc->value)) {
3079 s_return(sc,sc->value);
3080 } else if (sc->code == sc->NIL) {
3081 s_return(sc,sc->value);
3083 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
3084 sc->code = car(sc->code);
3088 case OP_C0STREAM: /* cons-stream */
3089 s_save(sc,OP_C1STREAM, sc->NIL, cdr(sc->code));
3090 sc->code = car(sc->code);
3093 case OP_C1STREAM: /* cons-stream */
3094 sc->args = sc->value; /* save sc->value to register sc->args for gc */
3095 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
3096 typeflag(x)=T_PROMISE;
3097 s_return(sc,cons(sc, sc->args, x));
3099 case OP_MACRO0: /* macro */
3100 if (is_pair(car(sc->code))) {
3102 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
3105 sc->code = cadr(sc->code);
3107 if (!is_symbol(x)) {
3108 Error_0(sc,"variable is not a symbol");
3110 s_save(sc,OP_MACRO1, sc->NIL, x);
3113 case OP_MACRO1: /* macro */
3114 typeflag(sc->value) = T_MACRO;
3115 x = find_slot_in_env(sc, sc->envir, sc->code, 0);
3117 set_slot_in_env(sc, x, sc->value);
3119 new_slot_in_env(sc, sc->code, sc->value);
3121 s_return(sc,sc->code);
3123 case OP_CASE0: /* case */
3124 s_save(sc,OP_CASE1, sc->NIL, cdr(sc->code));
3125 sc->code = car(sc->code);
3128 case OP_CASE1: /* case */
3129 for (x = sc->code; x != sc->NIL; x = cdr(x)) {
3130 if (!is_pair(y = caar(x))) {
3133 for ( ; y != sc->NIL; y = cdr(y)) {
3134 if (eqv(car(y), sc->value)) {
3143 if (is_pair(caar(x))) {
3145 s_goto(sc,OP_BEGIN);
3147 s_save(sc,OP_CASE2, sc->NIL, cdar(x));
3152 s_return(sc,sc->NIL);
3155 case OP_CASE2: /* case */
3156 if (is_true(sc->value)) {
3157 s_goto(sc,OP_BEGIN);
3159 s_return(sc,sc->NIL);
3162 case OP_PAPPLY: /* apply */
3163 sc->code = car(sc->args);
3164 sc->args = list_star(sc,cdr(sc->args));
3165 /*sc->args = cadr(sc->args);*/
3166 s_goto(sc,OP_APPLY);
3168 case OP_PEVAL: /* eval */
3169 if(cdr(sc->args)!=sc->NIL) {
3170 sc->envir=cadr(sc->args);
3172 sc->code = car(sc->args);
3175 case OP_CONTINUATION: /* call-with-current-continuation */
3176 sc->code = car(sc->args);
3177 sc->args = cons(sc, mk_continuation(sc, sc->dump), sc->NIL);
3178 s_goto(sc,OP_APPLY);
3181 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3182 Error_0(sc,sc->strbuff);
3187 static pointer opexe_2(scheme *sc, enum scheme_opcodes op) {
3196 case OP_INEX2EX: /* inexact->exact */
3198 if(num_is_integer(x)) {
3200 } else if(modf(rvalue_unchecked(x),&dd)==0.0) {
3201 s_return(sc,mk_integer(sc,ivalue(x)));
3203 Error_1(sc,"inexact->exact: not integral:",x);
3208 s_return(sc, mk_real(sc, exp(rvalue(x))));
3212 s_return(sc, mk_real(sc, log(rvalue(x))));
3216 s_return(sc, mk_real(sc, sin(rvalue(x))));
3220 s_return(sc, mk_real(sc, cos(rvalue(x))));
3224 s_return(sc, mk_real(sc, tan(rvalue(x))));
3228 s_return(sc, mk_real(sc, asin(rvalue(x))));
3232 s_return(sc, mk_real(sc, acos(rvalue(x))));
3236 if(cdr(sc->args)==sc->NIL) {
3237 s_return(sc, mk_real(sc, atan(rvalue(x))));
3239 pointer y=cadr(sc->args);
3240 s_return(sc, mk_real(sc, atan2(rvalue(x),rvalue(y))));
3245 s_return(sc, mk_real(sc, sqrt(rvalue(x))));
3250 pointer y=cadr(sc->args);
3252 if (num_is_integer(x) && num_is_integer(y))
3254 /* This 'if' is an R5RS compatibility fix. */
3255 /* NOTE: Remove this 'if' fix for R6RS. */
3256 if (rvalue(x) == 0 && rvalue(y) < 0) {
3259 result = pow(rvalue(x),rvalue(y));
3261 /* Before returning integer result make sure we can. */
3262 /* If the test fails, result is too big for integer. */
3265 long result_as_long = (long)result;
3266 if (result != (double)result_as_long)
3270 s_return(sc, mk_real(sc, result));
3272 s_return(sc, mk_integer(sc, result));
3278 s_return(sc, mk_real(sc, floor(rvalue(x))));
3282 s_return(sc, mk_real(sc, ceil(rvalue(x))));
3284 case OP_TRUNCATE : {
3285 double rvalue_of_x ;
3287 rvalue_of_x = rvalue(x) ;
3288 if (rvalue_of_x > 0) {
3289 s_return(sc, mk_real(sc, floor(rvalue_of_x)));
3291 s_return(sc, mk_real(sc, ceil(rvalue_of_x)));
3297 if (num_is_integer(x))
3299 s_return(sc, mk_real(sc, round_per_R5RS(rvalue(x))));
3302 case OP_ADD: /* + */
3304 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
3305 v=num_add(v,nvalue(car(x)));
3307 s_return(sc,mk_number(sc, v));
3309 case OP_MUL: /* * */
3311 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
3312 v=num_mul(v,nvalue(car(x)));
3314 s_return(sc,mk_number(sc, v));
3316 case OP_SUB: /* - */
3317 if(cdr(sc->args)==sc->NIL) {
3322 v = nvalue(car(sc->args));
3324 for (; x != sc->NIL; x = cdr(x)) {
3325 v=num_sub(v,nvalue(car(x)));
3327 s_return(sc,mk_number(sc, v));
3329 case OP_DIV: /* / */
3330 if(cdr(sc->args)==sc->NIL) {
3335 v = nvalue(car(sc->args));
3337 for (; x != sc->NIL; x = cdr(x)) {
3338 if (!is_zero_double(rvalue(car(x))))
3339 v=num_div(v,nvalue(car(x)));
3341 Error_0(sc,"/: division by zero");
3344 s_return(sc,mk_number(sc, v));
3346 case OP_INTDIV: /* quotient */
3347 if(cdr(sc->args)==sc->NIL) {
3352 v = nvalue(car(sc->args));
3354 for (; x != sc->NIL; x = cdr(x)) {
3355 if (ivalue(car(x)) != 0)
3356 v=num_intdiv(v,nvalue(car(x)));
3358 Error_0(sc,"quotient: division by zero");
3361 s_return(sc,mk_number(sc, v));
3363 case OP_REM: /* remainder */
3364 v = nvalue(car(sc->args));
3365 if (ivalue(cadr(sc->args)) != 0)
3366 v=num_rem(v,nvalue(cadr(sc->args)));
3368 Error_0(sc,"remainder: division by zero");
3370 s_return(sc,mk_number(sc, v));
3372 case OP_MOD: /* modulo */
3373 v = nvalue(car(sc->args));
3374 if (ivalue(cadr(sc->args)) != 0)
3375 v=num_mod(v,nvalue(cadr(sc->args)));
3377 Error_0(sc,"modulo: division by zero");
3379 s_return(sc,mk_number(sc, v));
3381 case OP_CAR: /* car */
3382 s_return(sc,caar(sc->args));
3384 case OP_CDR: /* cdr */
3385 s_return(sc,cdar(sc->args));
3387 case OP_CONS: /* cons */
3388 cdr(sc->args) = cadr(sc->args);
3389 s_return(sc,sc->args);
3391 case OP_SETCAR: /* set-car! */
3392 if(!is_immutable(car(sc->args))) {
3393 caar(sc->args) = cadr(sc->args);
3394 s_return(sc,car(sc->args));
3396 Error_0(sc,"set-car!: unable to alter immutable pair");
3399 case OP_SETCDR: /* set-cdr! */
3400 if(!is_immutable(car(sc->args))) {
3401 cdar(sc->args) = cadr(sc->args);
3402 s_return(sc,car(sc->args));
3404 Error_0(sc,"set-cdr!: unable to alter immutable pair");
3407 case OP_CHAR2INT: { /* char->integer */
3409 c=(char)ivalue(car(sc->args));
3410 s_return(sc,mk_integer(sc,(unsigned char)c));
3413 case OP_INT2CHAR: { /* integer->char */
3415 c=(unsigned char)ivalue(car(sc->args));
3416 s_return(sc,mk_character(sc,(char)c));
3419 case OP_CHARUPCASE: {
3421 c=(unsigned char)ivalue(car(sc->args));
3423 s_return(sc,mk_character(sc,(char)c));
3426 case OP_CHARDNCASE: {
3428 c=(unsigned char)ivalue(car(sc->args));
3430 s_return(sc,mk_character(sc,(char)c));
3433 case OP_STR2SYM: /* string->symbol */
3434 s_return(sc,mk_symbol(sc,strvalue(car(sc->args))));
3436 case OP_STR2ATOM: /* string->atom */ {
3437 char *s=strvalue(car(sc->args));
3439 if(cdr(sc->args)!=sc->NIL) {
3440 /* we know cadr(sc->args) is a natural number */
3441 /* see if it is 2, 8, 10, or 16, or error */
3442 pf = ivalue_unchecked(cadr(sc->args));
3443 if(pf == 16 || pf == 10 || pf == 8 || pf == 2) {
3451 Error_1(sc, "string->atom: bad base:", cadr(sc->args));
3452 } else if(*s=='#') /* no use of base! */ {
3453 s_return(sc, mk_sharp_const(sc, s+1));
3455 if (pf == 0 || pf == 10) {
3456 s_return(sc, mk_atom(sc, s));
3460 long iv = strtol(s,&ep,(int )pf);
3462 s_return(sc, mk_integer(sc, iv));
3465 s_return(sc, sc->F);
3471 case OP_SYM2STR: /* symbol->string */
3472 x=mk_string(sc,symname(car(sc->args)));
3476 case OP_ATOM2STR: /* atom->string */ {
3479 if(cdr(sc->args)!=sc->NIL) {
3480 /* we know cadr(sc->args) is a natural number */
3481 /* see if it is 2, 8, 10, or 16, or error */
3482 pf = ivalue_unchecked(cadr(sc->args));
3483 if(is_number(x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2)) {
3491 Error_1(sc, "atom->string: bad base:", cadr(sc->args));
3492 } else if(is_number(x) || is_character(x) || is_string(x) || is_symbol(x)) {
3495 atom2str(sc,x,(int )pf,&p,&len);
3496 s_return(sc,mk_counted_string(sc,p,len));
3498 Error_1(sc, "atom->string: not an atom:", x);
3502 case OP_MKSTRING: { /* make-string */
3506 len=ivalue(car(sc->args));
3508 if(cdr(sc->args)!=sc->NIL) {
3509 fill=charvalue(cadr(sc->args));
3511 s_return(sc,mk_empty_string(sc,len,(char)fill));
3514 case OP_STRLEN: /* string-length */
3515 s_return(sc,mk_integer(sc,strlength(car(sc->args))));
3517 case OP_STRREF: { /* string-ref */
3521 str=strvalue(car(sc->args));
3523 index=ivalue(cadr(sc->args));
3525 if(index>=strlength(car(sc->args))) {
3526 Error_1(sc,"string-ref: out of bounds:",cadr(sc->args));
3529 s_return(sc,mk_character(sc,((unsigned char*)str)[index]));
3532 case OP_STRSET: { /* string-set! */
3537 if(is_immutable(car(sc->args))) {
3538 Error_1(sc,"string-set!: unable to alter immutable string:",car(sc->args));
3540 str=strvalue(car(sc->args));
3542 index=ivalue(cadr(sc->args));
3543 if(index>=strlength(car(sc->args))) {
3544 Error_1(sc,"string-set!: out of bounds:",cadr(sc->args));
3547 c=charvalue(caddr(sc->args));
3550 s_return(sc,car(sc->args));
3553 case OP_STRAPPEND: { /* string-append */
3554 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
3559 /* compute needed length for new string */
3560 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
3561 len += strlength(car(x));
3563 newstr = mk_empty_string(sc, len, ' ');
3564 /* store the contents of the argument strings into the new string */
3565 for (pos = strvalue(newstr), x = sc->args; x != sc->NIL;
3566 pos += strlength(car(x)), x = cdr(x)) {
3567 memcpy(pos, strvalue(car(x)), strlength(car(x)));
3569 s_return(sc, newstr);
3572 case OP_SUBSTR: { /* substring */
3578 str=strvalue(car(sc->args));
3580 index0=ivalue(cadr(sc->args));
3582 if(index0>strlength(car(sc->args))) {
3583 Error_1(sc,"substring: start out of bounds:",cadr(sc->args));
3586 if(cddr(sc->args)!=sc->NIL) {
3587 index1=ivalue(caddr(sc->args));
3588 if(index1>strlength(car(sc->args)) || index1<index0) {
3589 Error_1(sc,"substring: end out of bounds:",caddr(sc->args));
3592 index1=strlength(car(sc->args));
3596 x=mk_empty_string(sc,len,' ');
3597 memcpy(strvalue(x),str+index0,len);
3603 case OP_VECTOR: { /* vector */
3606 int len=list_length(sc,sc->args);
3608 Error_1(sc,"vector: not a proper list:",sc->args);
3610 vec=mk_vector(sc,len);
3611 if(sc->no_memory) { s_return(sc, sc->sink); }
3612 for (x = sc->args, i = 0; is_pair(x); x = cdr(x), i++) {
3613 set_vector_elem(vec,i,car(x));
3618 case OP_MKVECTOR: { /* make-vector */
3619 pointer fill=sc->NIL;
3623 len=ivalue(car(sc->args));
3625 if(cdr(sc->args)!=sc->NIL) {
3626 fill=cadr(sc->args);
3628 vec=mk_vector(sc,len);
3629 if(sc->no_memory) { s_return(sc, sc->sink); }
3631 fill_vector(vec,fill);
3636 case OP_VECLEN: /* vector-length */
3637 s_return(sc,mk_integer(sc,ivalue(car(sc->args))));
3639 case OP_VECREF: { /* vector-ref */
3642 index=ivalue(cadr(sc->args));
3644 if(index>=ivalue(car(sc->args))) {
3645 Error_1(sc,"vector-ref: out of bounds:",cadr(sc->args));
3648 s_return(sc,vector_elem(car(sc->args),index));
3651 case OP_VECSET: { /* vector-set! */
3654 if(is_immutable(car(sc->args))) {
3655 Error_1(sc,"vector-set!: unable to alter immutable vector:",car(sc->args));
3658 index=ivalue(cadr(sc->args));
3659 if(index>=ivalue(car(sc->args))) {
3660 Error_1(sc,"vector-set!: out of bounds:",cadr(sc->args));
3663 set_vector_elem(car(sc->args),index,caddr(sc->args));
3664 s_return(sc,car(sc->args));
3668 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3669 Error_0(sc,sc->strbuff);
3674 static int is_list(scheme *sc, pointer a)
3675 { return list_length(sc,a) >= 0; }
3681 dotted list: -2 minus length before dot
3683 int list_length(scheme *sc, pointer a) {
3690 if (fast == sc->NIL)
3696 if (fast == sc->NIL)
3703 /* Safe because we would have already returned if `fast'
3704 encountered a non-pair. */
3708 /* the fast pointer has looped back around and caught up
3709 with the slow pointer, hence the structure is circular,
3710 not of finite length, and therefore not a list */
3716 static pointer opexe_3(scheme *sc, enum scheme_opcodes op) {
3719 int (*comp_func)(num,num)=0;
3722 case OP_NOT: /* not */
3723 s_retbool(is_false(car(sc->args)));
3724 case OP_BOOLP: /* boolean? */
3725 s_retbool(car(sc->args) == sc->F || car(sc->args) == sc->T);
3726 case OP_EOFOBJP: /* boolean? */
3727 s_retbool(car(sc->args) == sc->EOF_OBJ);
3728 case OP_NULLP: /* null? */
3729 s_retbool(car(sc->args) == sc->NIL);
3730 case OP_NUMEQ: /* = */
3731 case OP_LESS: /* < */
3732 case OP_GRE: /* > */
3733 case OP_LEQ: /* <= */
3734 case OP_GEQ: /* >= */
3736 case OP_NUMEQ: comp_func=num_eq; break;
3737 case OP_LESS: comp_func=num_lt; break;
3738 case OP_GRE: comp_func=num_gt; break;
3739 case OP_LEQ: comp_func=num_le; break;
3740 case OP_GEQ: comp_func=num_ge; break;
3741 default: assert (! "reached");
3747 for (; x != sc->NIL; x = cdr(x)) {
3748 if(!comp_func(v,nvalue(car(x)))) {
3754 case OP_SYMBOLP: /* symbol? */
3755 s_retbool(is_symbol(car(sc->args)));
3756 case OP_NUMBERP: /* number? */
3757 s_retbool(is_number(car(sc->args)));
3758 case OP_STRINGP: /* string? */
3759 s_retbool(is_string(car(sc->args)));
3760 case OP_INTEGERP: /* integer? */
3761 s_retbool(is_integer(car(sc->args)));
3762 case OP_REALP: /* real? */
3763 s_retbool(is_number(car(sc->args))); /* All numbers are real */
3764 case OP_CHARP: /* char? */
3765 s_retbool(is_character(car(sc->args)));
3766 #if USE_CHAR_CLASSIFIERS
3767 case OP_CHARAP: /* char-alphabetic? */
3768 s_retbool(Cisalpha(ivalue(car(sc->args))));
3769 case OP_CHARNP: /* char-numeric? */
3770 s_retbool(Cisdigit(ivalue(car(sc->args))));
3771 case OP_CHARWP: /* char-whitespace? */
3772 s_retbool(Cisspace(ivalue(car(sc->args))));
3773 case OP_CHARUP: /* char-upper-case? */
3774 s_retbool(Cisupper(ivalue(car(sc->args))));
3775 case OP_CHARLP: /* char-lower-case? */
3776 s_retbool(Cislower(ivalue(car(sc->args))));
3778 case OP_PORTP: /* port? */
3779 s_retbool(is_port(car(sc->args)));
3780 case OP_INPORTP: /* input-port? */
3781 s_retbool(is_inport(car(sc->args)));
3782 case OP_OUTPORTP: /* output-port? */
3783 s_retbool(is_outport(car(sc->args)));
3784 case OP_PROCP: /* procedure? */
3786 * continuation should be procedure by the example
3787 * (call-with-current-continuation procedure?) ==> #t
3788 * in R^3 report sec. 6.9
3790 s_retbool(is_proc(car(sc->args)) || is_closure(car(sc->args))
3791 || is_continuation(car(sc->args)) || is_foreign(car(sc->args)));
3792 case OP_PAIRP: /* pair? */
3793 s_retbool(is_pair(car(sc->args)));
3794 case OP_LISTP: /* list? */
3795 s_retbool(list_length(sc,car(sc->args)) >= 0);
3797 case OP_ENVP: /* environment? */
3798 s_retbool(is_environment(car(sc->args)));
3799 case OP_VECTORP: /* vector? */
3800 s_retbool(is_vector(car(sc->args)));
3801 case OP_EQ: /* eq? */
3802 s_retbool(car(sc->args) == cadr(sc->args));
3803 case OP_EQV: /* eqv? */
3804 s_retbool(eqv(car(sc->args), cadr(sc->args)));
3806 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3807 Error_0(sc,sc->strbuff);
3812 static pointer opexe_4(scheme *sc, enum scheme_opcodes op) {
3816 case OP_FORCE: /* force */
3817 sc->code = car(sc->args);
3818 if (is_promise(sc->code)) {
3819 /* Should change type to closure here */
3820 s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code);
3822 s_goto(sc,OP_APPLY);
3824 s_return(sc,sc->code);
3827 case OP_SAVE_FORCED: /* Save forced value replacing promise */
3828 memcpy(sc->code,sc->value,sizeof(struct cell));
3829 s_return(sc,sc->value);
3831 case OP_WRITE: /* write */
3832 case OP_DISPLAY: /* display */
3833 case OP_WRITE_CHAR: /* write-char */
3834 if(is_pair(cdr(sc->args))) {
3835 if(cadr(sc->args)!=sc->outport) {
3836 x=cons(sc,sc->outport,sc->NIL);
3837 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
3838 sc->outport=cadr(sc->args);
3841 sc->args = car(sc->args);
3847 s_goto(sc,OP_P0LIST);
3849 case OP_NEWLINE: /* newline */
3850 if(is_pair(sc->args)) {
3851 if(car(sc->args)!=sc->outport) {
3852 x=cons(sc,sc->outport,sc->NIL);
3853 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
3854 sc->outport=car(sc->args);
3860 case OP_ERR0: /* error */
3862 if (!is_string(car(sc->args))) {
3863 sc->args=cons(sc,mk_string(sc," -- "),sc->args);
3864 setimmutable(car(sc->args));
3866 putstr(sc, "Error: ");
3867 putstr(sc, strvalue(car(sc->args)));
3868 sc->args = cdr(sc->args);
3871 case OP_ERR1: /* error */
3873 if (sc->args != sc->NIL) {
3874 s_save(sc,OP_ERR1, cdr(sc->args), sc->NIL);
3875 sc->args = car(sc->args);
3877 s_goto(sc,OP_P0LIST);
3880 if(sc->interactive_repl) {
3881 s_goto(sc,OP_T0LVL);
3887 case OP_REVERSE: /* reverse */
3888 s_return(sc,reverse(sc, car(sc->args)));
3890 case OP_LIST_STAR: /* list* */
3891 s_return(sc,list_star(sc,sc->args));
3893 case OP_APPEND: /* append */
3900 /* cdr() in the while condition is not a typo. If car() */
3901 /* is used (append '() 'a) will return the wrong result.*/
3902 while (cdr(y) != sc->NIL) {
3903 x = revappend(sc, x, car(y));
3906 Error_0(sc, "non-list argument to append");
3910 s_return(sc, reverse_in_place(sc, car(y), x));
3913 case OP_PUT: /* put */
3914 if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) {
3915 Error_0(sc,"illegal use of put");
3917 for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) {
3923 cdar(x) = caddr(sc->args);
3925 symprop(car(sc->args)) = cons(sc, cons(sc, y, caddr(sc->args)),
3926 symprop(car(sc->args)));
3929 case OP_GET: /* get */
3930 if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) {
3931 Error_0(sc,"illegal use of get");
3933 for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) {
3939 s_return(sc,cdar(x));
3941 s_return(sc,sc->NIL);
3943 #endif /* USE_PLIST */
3944 case OP_QUIT: /* quit */
3945 if(is_pair(sc->args)) {
3946 sc->retcode=ivalue(car(sc->args));
3950 case OP_GC: /* gc */
3951 gc(sc, sc->NIL, sc->NIL);
3954 case OP_GCVERB: /* gc-verbose */
3955 { int was = sc->gc_verbose;
3957 sc->gc_verbose = (car(sc->args) != sc->F);
3961 case OP_NEWSEGMENT: /* new-segment */
3962 if (!is_pair(sc->args) || !is_number(car(sc->args))) {
3963 Error_0(sc,"new-segment: argument must be a number");
3965 alloc_cellseg(sc, (int) ivalue(car(sc->args)));
3968 case OP_OBLIST: /* oblist */
3969 s_return(sc, oblist_all_symbols(sc));
3971 case OP_CURR_INPORT: /* current-input-port */
3972 s_return(sc,sc->inport);
3974 case OP_CURR_OUTPORT: /* current-output-port */
3975 s_return(sc,sc->outport);
3977 case OP_OPEN_INFILE: /* open-input-file */
3978 case OP_OPEN_OUTFILE: /* open-output-file */
3979 case OP_OPEN_INOUTFILE: /* open-input-output-file */ {
3983 case OP_OPEN_INFILE: prop=port_input; break;
3984 case OP_OPEN_OUTFILE: prop=port_output; break;
3985 case OP_OPEN_INOUTFILE: prop=port_input|port_output; break;
3986 default: assert (! "reached");
3988 p=port_from_filename(sc,strvalue(car(sc->args)),prop);
3994 default: assert (! "reached");
3997 #if USE_STRING_PORTS
3998 case OP_OPEN_INSTRING: /* open-input-string */
3999 case OP_OPEN_INOUTSTRING: /* open-input-output-string */ {
4003 case OP_OPEN_INSTRING: prop=port_input; break;
4004 case OP_OPEN_INOUTSTRING: prop=port_input|port_output; break;
4005 default: assert (! "reached");
4007 p=port_from_string(sc, strvalue(car(sc->args)),
4008 strvalue(car(sc->args))+strlength(car(sc->args)), prop);
4014 case OP_OPEN_OUTSTRING: /* open-output-string */ {
4016 if(car(sc->args)==sc->NIL) {
4017 p=port_from_scratch(sc);
4022 p=port_from_string(sc, strvalue(car(sc->args)),
4023 strvalue(car(sc->args))+strlength(car(sc->args)),
4031 case OP_GET_OUTSTRING: /* get-output-string */ {
4034 if ((p=car(sc->args)->_object._port)->kind&port_string) {
4038 size=p->rep.string.curr-p->rep.string.start+1;
4039 str=sc->malloc(size);
4043 memcpy(str,p->rep.string.start,size-1);
4045 s=mk_string(sc,str);
4054 case OP_CLOSE_INPORT: /* close-input-port */
4055 port_close(sc,car(sc->args),port_input);
4058 case OP_CLOSE_OUTPORT: /* close-output-port */
4059 port_close(sc,car(sc->args),port_output);
4062 case OP_INT_ENV: /* interaction-environment */
4063 s_return(sc,sc->global_env);
4065 case OP_CURR_ENV: /* current-environment */
4066 s_return(sc,sc->envir);
4072 static pointer opexe_5(scheme *sc, enum scheme_opcodes op) {
4075 if(sc->nesting!=0) {
4079 Error_1(sc,"unmatched parentheses:",mk_integer(sc,n));
4083 /* ========== reading part ========== */
4085 if(!is_pair(sc->args)) {
4086 s_goto(sc,OP_READ_INTERNAL);
4088 if(!is_inport(car(sc->args))) {
4089 Error_1(sc,"read: not an input port:",car(sc->args));
4091 if(car(sc->args)==sc->inport) {
4092 s_goto(sc,OP_READ_INTERNAL);
4095 sc->inport=car(sc->args);
4096 x=cons(sc,x,sc->NIL);
4097 s_save(sc,OP_SET_INPORT, x, sc->NIL);
4098 s_goto(sc,OP_READ_INTERNAL);
4100 case OP_READ_CHAR: /* read-char */
4101 case OP_PEEK_CHAR: /* peek-char */ {
4103 if(is_pair(sc->args)) {
4104 if(car(sc->args)!=sc->inport) {
4106 x=cons(sc,x,sc->NIL);
4107 s_save(sc,OP_SET_INPORT, x, sc->NIL);
4108 sc->inport=car(sc->args);
4113 s_return(sc,sc->EOF_OBJ);
4115 if(sc->op==OP_PEEK_CHAR) {
4118 s_return(sc,mk_character(sc,c));
4121 case OP_CHAR_READY: /* char-ready? */ {
4122 pointer p=sc->inport;
4124 if(is_pair(sc->args)) {
4127 res=p->_object._port->kind&port_string;
4131 case OP_SET_INPORT: /* set-input-port */
4132 sc->inport=car(sc->args);
4133 s_return(sc,sc->value);
4135 case OP_SET_OUTPORT: /* set-output-port */
4136 sc->outport=car(sc->args);
4137 s_return(sc,sc->value);
4142 s_return(sc,sc->EOF_OBJ);
4145 * Commented out because we now skip comments in the scanner
4149 while ((c=inchar(sc)) != '\n' && c!=EOF)
4151 sc->tok = token(sc);
4152 s_goto(sc,OP_RDSEXPR);
4156 s_save(sc,OP_RDVEC,sc->NIL,sc->NIL);
4159 sc->tok = token(sc);
4160 if (sc->tok == TOK_RPAREN) {
4161 s_return(sc,sc->NIL);
4162 } else if (sc->tok == TOK_DOT) {
4163 Error_0(sc,"syntax error: illegal dot expression");
4165 sc->nesting_stack[sc->file_i]++;
4166 s_save(sc,OP_RDLIST, sc->NIL, sc->NIL);
4167 s_goto(sc,OP_RDSEXPR);
4170 s_save(sc,OP_RDQUOTE, sc->NIL, sc->NIL);
4171 sc->tok = token(sc);
4172 s_goto(sc,OP_RDSEXPR);
4174 sc->tok = token(sc);
4175 if(sc->tok==TOK_VEC) {
4176 s_save(sc,OP_RDQQUOTEVEC, sc->NIL, sc->NIL);
4178 s_goto(sc,OP_RDSEXPR);
4180 s_save(sc,OP_RDQQUOTE, sc->NIL, sc->NIL);
4182 s_goto(sc,OP_RDSEXPR);
4184 s_save(sc,OP_RDUNQUOTE, sc->NIL, sc->NIL);
4185 sc->tok = token(sc);
4186 s_goto(sc,OP_RDSEXPR);
4188 s_save(sc,OP_RDUQTSP, sc->NIL, sc->NIL);
4189 sc->tok = token(sc);
4190 s_goto(sc,OP_RDSEXPR);
4192 s_return(sc,mk_atom(sc, readstr_upto(sc, DELIMITERS)));
4196 Error_0(sc,"Error reading string");
4201 pointer f=find_slot_in_env(sc,sc->envir,sc->SHARP_HOOK,1);
4203 Error_0(sc,"undefined sharp expression");
4205 sc->code=cons(sc,slot_value_in_env(f),sc->NIL);
4209 case TOK_SHARP_CONST:
4210 if ((x = mk_sharp_const(sc, readstr_upto(sc, DELIMITERS))) == sc->NIL) {
4211 Error_0(sc,"undefined sharp expression");
4216 Error_0(sc,"syntax error: illegal token");
4221 sc->args = cons(sc, sc->value, sc->args);
4222 sc->tok = token(sc);
4223 /* We now skip comments in the scanner
4224 while (sc->tok == TOK_COMMENT) {
4226 while ((c=inchar(sc)) != '\n' && c!=EOF)
4228 sc->tok = token(sc);
4231 if (sc->tok == TOK_EOF)
4232 { s_return(sc,sc->EOF_OBJ); }
4233 else if (sc->tok == TOK_RPAREN) {
4238 else if (sc->load_stack[sc->file_i].kind & port_file)
4239 sc->load_stack[sc->file_i].rep.stdio.curr_line++;
4241 sc->nesting_stack[sc->file_i]--;
4242 s_return(sc,reverse_in_place(sc, sc->NIL, sc->args));
4243 } else if (sc->tok == TOK_DOT) {
4244 s_save(sc,OP_RDDOT, sc->args, sc->NIL);
4245 sc->tok = token(sc);
4246 s_goto(sc,OP_RDSEXPR);
4248 s_save(sc,OP_RDLIST, sc->args, sc->NIL);;
4249 s_goto(sc,OP_RDSEXPR);
4254 if (token(sc) != TOK_RPAREN) {
4255 Error_0(sc,"syntax error: illegal dot expression");
4257 sc->nesting_stack[sc->file_i]--;
4258 s_return(sc,reverse_in_place(sc, sc->value, sc->args));
4262 s_return(sc,cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL)));
4265 s_return(sc,cons(sc, sc->QQUOTE, cons(sc, sc->value, sc->NIL)));
4267 case OP_RDQQUOTEVEC:
4268 s_return(sc,cons(sc, mk_symbol(sc,"apply"),
4269 cons(sc, mk_symbol(sc,"vector"),
4270 cons(sc,cons(sc, sc->QQUOTE,
4271 cons(sc,sc->value,sc->NIL)),
4275 s_return(sc,cons(sc, sc->UNQUOTE, cons(sc, sc->value, sc->NIL)));
4278 s_return(sc,cons(sc, sc->UNQUOTESP, cons(sc, sc->value, sc->NIL)));
4281 /*sc->code=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
4282 s_goto(sc,OP_EVAL); Cannot be quoted*/
4283 /*x=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
4284 s_return(sc,x); Cannot be part of pairs*/
4285 /*sc->code=mk_proc(sc,OP_VECTOR);
4287 s_goto(sc,OP_APPLY);*/
4289 s_goto(sc,OP_VECTOR);
4291 /* ========== printing part ========== */
4293 if(is_vector(sc->args)) {
4295 sc->args=cons(sc,sc->args,mk_integer(sc,0));
4296 s_goto(sc,OP_PVECFROM);
4297 } else if(is_environment(sc->args)) {
4298 putstr(sc,"#<ENVIRONMENT>");
4300 } else if (!is_pair(sc->args)) {
4301 printatom(sc, sc->args, sc->print_flag);
4303 } else if (car(sc->args) == sc->QUOTE && ok_abbrev(cdr(sc->args))) {
4305 sc->args = cadr(sc->args);
4306 s_goto(sc,OP_P0LIST);
4307 } else if (car(sc->args) == sc->QQUOTE && ok_abbrev(cdr(sc->args))) {
4309 sc->args = cadr(sc->args);
4310 s_goto(sc,OP_P0LIST);
4311 } else if (car(sc->args) == sc->UNQUOTE && ok_abbrev(cdr(sc->args))) {
4313 sc->args = cadr(sc->args);
4314 s_goto(sc,OP_P0LIST);
4315 } else if (car(sc->args) == sc->UNQUOTESP && ok_abbrev(cdr(sc->args))) {
4317 sc->args = cadr(sc->args);
4318 s_goto(sc,OP_P0LIST);
4321 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
4322 sc->args = car(sc->args);
4323 s_goto(sc,OP_P0LIST);
4327 if (is_pair(sc->args)) {
4328 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
4330 sc->args = car(sc->args);
4331 s_goto(sc,OP_P0LIST);
4332 } else if(is_vector(sc->args)) {
4333 s_save(sc,OP_P1LIST,sc->NIL,sc->NIL);
4335 s_goto(sc,OP_P0LIST);
4337 if (sc->args != sc->NIL) {
4339 printatom(sc, sc->args, sc->print_flag);
4345 int i=ivalue_unchecked(cdr(sc->args));
4346 pointer vec=car(sc->args);
4347 int len=ivalue_unchecked(vec);
4352 pointer elem=vector_elem(vec,i);
4353 ivalue_unchecked(cdr(sc->args))=i+1;
4354 s_save(sc,OP_PVECFROM, sc->args, sc->NIL);
4358 s_goto(sc,OP_P0LIST);
4363 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
4364 Error_0(sc,sc->strbuff);
4370 static pointer opexe_6(scheme *sc, enum scheme_opcodes op) {
4375 case OP_LIST_LENGTH: /* length */ /* a.k */
4376 v=list_length(sc,car(sc->args));
4378 Error_1(sc,"length: not a list:",car(sc->args));
4380 s_return(sc,mk_integer(sc, v));
4382 case OP_ASSQ: /* assq */ /* a.k */
4384 for (y = cadr(sc->args); is_pair(y); y = cdr(y)) {
4385 if (!is_pair(car(y))) {
4386 Error_0(sc,"unable to handle non pair element");
4392 s_return(sc,car(y));
4398 case OP_GET_CLOSURE: /* get-closure-code */ /* a.k */
4399 sc->args = car(sc->args);
4400 if (sc->args == sc->NIL) {
4402 } else if (is_closure(sc->args)) {
4403 s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value)));
4404 } else if (is_macro(sc->args)) {
4405 s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value)));
4409 case OP_CLOSUREP: /* closure? */
4411 * Note, macro object is also a closure.
4412 * Therefore, (closure? <#MACRO>) ==> #t
4414 s_retbool(is_closure(car(sc->args)));
4415 case OP_MACROP: /* macro? */
4416 s_retbool(is_macro(car(sc->args)));
4418 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
4419 Error_0(sc,sc->strbuff);
4421 return sc->T; /* NOTREACHED */
4424 typedef pointer (*dispatch_func)(scheme *, enum scheme_opcodes);
4426 typedef int (*test_predicate)(pointer);
4428 static int is_any(pointer p) {
4433 static int is_nonneg(pointer p) {
4434 return ivalue(p)>=0 && is_integer(p);
4437 /* Correspond carefully with following defines! */
4444 {is_string, "string"},
4445 {is_symbol, "symbol"},
4447 {is_inport,"input port"},
4448 {is_outport,"output port"},
4449 {is_environment, "environment"},
4452 {is_character, "character"},
4453 {is_vector, "vector"},
4454 {is_number, "number"},
4455 {is_integer, "integer"},
4456 {is_nonneg, "non-negative integer"}
4460 #define TST_ANY "\001"
4461 #define TST_STRING "\002"
4462 #define TST_SYMBOL "\003"
4463 #define TST_PORT "\004"
4464 #define TST_INPORT "\005"
4465 #define TST_OUTPORT "\006"
4466 #define TST_ENVIRONMENT "\007"
4467 #define TST_PAIR "\010"
4468 #define TST_LIST "\011"
4469 #define TST_CHAR "\012"
4470 #define TST_VECTOR "\013"
4471 #define TST_NUMBER "\014"
4472 #define TST_INTEGER "\015"
4473 #define TST_NATURAL "\016"
4480 char *arg_tests_encoding;
4483 #define INF_ARG 0xffff
4485 static op_code_info dispatch_table[]= {
4486 #define _OP_DEF(A,B,C,D,E,OP) {A,B,C,D,E},
4487 #include "opdefines.h"
4491 static const char *procname(pointer x) {
4493 const char *name=dispatch_table[n].name;
4500 /* kernel of this interpreter */
4501 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op) {
4504 op_code_info *pcd=dispatch_table+sc->op;
4505 if (pcd->name!=0) { /* if built-in function, check arguments */
4506 char msg[STRBUFFSIZE];
4508 int n=list_length(sc,sc->args);
4510 /* Check number of arguments */
4511 if(n<pcd->min_arity) {
4513 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
4515 pcd->min_arity==pcd->max_arity?"":" at least",
4518 if(ok && n>pcd->max_arity) {
4520 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
4522 pcd->min_arity==pcd->max_arity?"":" at most",
4526 if(pcd->arg_tests_encoding!=0) {
4529 const char *t=pcd->arg_tests_encoding;
4530 pointer arglist=sc->args;
4532 pointer arg=car(arglist);
4534 if(j==TST_LIST[0]) {
4535 if(arg!=sc->NIL && !is_pair(arg)) break;
4537 if(!tests[j].fct(arg)) break;
4540 if(t[1]!=0) {/* last test is replicated as necessary */
4543 arglist=cdr(arglist);
4548 snprintf(msg, STRBUFFSIZE, "%s: argument %d must be: %s, got: %s",
4552 type_to_string(type(car(arglist))));
4557 if(_Error_1(sc,msg,0)==sc->NIL) {
4560 pcd=dispatch_table+sc->op;
4563 ok_to_freely_gc(sc);
4564 if (pcd->func(sc, (enum scheme_opcodes)sc->op) == sc->NIL) {
4568 fprintf(stderr,"No memory!\n");
4574 /* ========== Initialization of internal keywords ========== */
4576 static void assign_syntax(scheme *sc, char *name) {
4579 x = oblist_add_by_name(sc, name);
4580 typeflag(x) |= T_SYNTAX;
4583 static void assign_proc(scheme *sc, enum scheme_opcodes op, char *name) {
4586 x = mk_symbol(sc, name);
4588 new_slot_in_env(sc, x, y);
4591 static pointer mk_proc(scheme *sc, enum scheme_opcodes op) {
4594 y = get_cell(sc, sc->NIL, sc->NIL);
4595 typeflag(y) = (T_PROC | T_ATOM);
4596 ivalue_unchecked(y) = (long) op;
4601 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
4602 static int syntaxnum(pointer p) {
4603 const char *s=strvalue(car(p));
4604 switch(strlength(car(p))) {
4606 if(s[0]=='i') return OP_IF0; /* if */
4607 else return OP_OR0; /* or */
4609 if(s[0]=='a') return OP_AND0; /* and */
4610 else return OP_LET0; /* let */
4613 case 'e': return OP_CASE0; /* case */
4614 case 'd': return OP_COND0; /* cond */
4615 case '*': return OP_LET0AST; /* let* */
4616 default: return OP_SET0; /* set! */
4620 case 'g': return OP_BEGIN; /* begin */
4621 case 'l': return OP_DELAY; /* delay */
4622 case 'c': return OP_MACRO0; /* macro */
4623 default: return OP_QUOTE; /* quote */
4627 case 'm': return OP_LAMBDA; /* lambda */
4628 case 'f': return OP_DEF0; /* define */
4629 default: return OP_LET0REC; /* letrec */
4632 return OP_C0STREAM; /* cons-stream */
4636 /* initialization of TinyScheme */
4638 INTERFACE static pointer s_cons(scheme *sc, pointer a, pointer b) {
4639 return cons(sc,a,b);
4641 INTERFACE static pointer s_immutable_cons(scheme *sc, pointer a, pointer b) {
4642 return immutable_cons(sc,a,b);
4645 static struct scheme_interface vtbl ={
4660 get_foreign_object_vtable,
4661 get_foreign_object_data,
4713 scheme *scheme_init_new() {
4714 scheme *sc=(scheme*)malloc(sizeof(scheme));
4715 if(!scheme_init(sc)) {
4723 scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free) {
4724 scheme *sc=(scheme*)malloc(sizeof(scheme));
4725 if(!scheme_init_custom_alloc(sc,malloc,free)) {
4734 int scheme_init(scheme *sc) {
4735 return scheme_init_custom_alloc(sc,malloc,free);
4738 int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
4739 int i, n=sizeof(dispatch_table)/sizeof(dispatch_table[0]);
4742 num_zero.is_fixnum=1;
4743 num_zero.value.ivalue=0;
4744 num_one.is_fixnum=1;
4745 num_one.value.ivalue=1;
4753 sc->last_cell_seg = -1;
4754 sc->sink = &sc->_sink;
4755 sc->NIL = &sc->_NIL;
4756 sc->T = &sc->_HASHT;
4757 sc->F = &sc->_HASHF;
4758 sc->EOF_OBJ=&sc->_EOF_OBJ;
4759 sc->free_cell = &sc->_NIL;
4763 sc->outport=sc->NIL;
4764 sc->save_inport=sc->NIL;
4765 sc->loadport=sc->NIL;
4767 sc->interactive_repl=0;
4768 sc->strbuff = sc->malloc(STRBUFFSIZE);
4769 if (sc->strbuff == 0) {
4773 sc->strbuff_size = STRBUFFSIZE;
4775 if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
4780 dump_stack_initialize(sc);
4785 typeflag(sc->NIL) = (T_NIL | T_ATOM | MARK);
4786 car(sc->NIL) = cdr(sc->NIL) = sc->NIL;
4788 typeflag(sc->T) = (T_BOOLEAN | T_ATOM | MARK);
4789 car(sc->T) = cdr(sc->T) = sc->T;
4791 typeflag(sc->F) = (T_BOOLEAN | T_ATOM | MARK);
4792 car(sc->F) = cdr(sc->F) = sc->F;
4794 typeflag(sc->EOF_OBJ) = (T_EOF_OBJ | T_ATOM | MARK);
4795 car(sc->EOF_OBJ) = cdr(sc->EOF_OBJ) = sc->EOF_OBJ;
4797 typeflag(sc->sink) = (T_SINK | T_PAIR | MARK);
4798 car(sc->sink) = sc->NIL;
4800 sc->c_nest = sc->NIL;
4802 sc->oblist = oblist_initial_value(sc);
4803 /* init global_env */
4804 new_frame_in_env(sc, sc->NIL);
4805 sc->global_env = sc->envir;
4807 x = mk_symbol(sc,"else");
4808 new_slot_in_env(sc, x, sc->T);
4810 assign_syntax(sc, "lambda");
4811 assign_syntax(sc, "quote");
4812 assign_syntax(sc, "define");
4813 assign_syntax(sc, "if");
4814 assign_syntax(sc, "begin");
4815 assign_syntax(sc, "set!");
4816 assign_syntax(sc, "let");
4817 assign_syntax(sc, "let*");
4818 assign_syntax(sc, "letrec");
4819 assign_syntax(sc, "cond");
4820 assign_syntax(sc, "delay");
4821 assign_syntax(sc, "and");
4822 assign_syntax(sc, "or");
4823 assign_syntax(sc, "cons-stream");
4824 assign_syntax(sc, "macro");
4825 assign_syntax(sc, "case");
4827 for(i=0; i<n; i++) {
4828 if(dispatch_table[i].name!=0) {
4829 assign_proc(sc, (enum scheme_opcodes)i, dispatch_table[i].name);
4833 /* initialization of global pointers to special symbols */
4834 sc->LAMBDA = mk_symbol(sc, "lambda");
4835 sc->QUOTE = mk_symbol(sc, "quote");
4836 sc->QQUOTE = mk_symbol(sc, "quasiquote");
4837 sc->UNQUOTE = mk_symbol(sc, "unquote");
4838 sc->UNQUOTESP = mk_symbol(sc, "unquote-splicing");
4839 sc->FEED_TO = mk_symbol(sc, "=>");
4840 sc->COLON_HOOK = mk_symbol(sc,"*colon-hook*");
4841 sc->ERROR_HOOK = mk_symbol(sc, "*error-hook*");
4842 sc->SHARP_HOOK = mk_symbol(sc, "*sharp-hook*");
4843 sc->COMPILE_HOOK = mk_symbol(sc, "*compile-hook*");
4845 return !sc->no_memory;
4848 void scheme_set_input_port_file(scheme *sc, FILE *fin) {
4849 sc->inport=port_from_file(sc,fin,port_input);
4852 void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end) {
4853 sc->inport=port_from_string(sc,start,past_the_end,port_input);
4856 void scheme_set_output_port_file(scheme *sc, FILE *fout) {
4857 sc->outport=port_from_file(sc,fout,port_output);
4860 void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end) {
4861 sc->outport=port_from_string(sc,start,past_the_end,port_output);
4864 void scheme_set_external_data(scheme *sc, void *p) {
4868 void scheme_deinit(scheme *sc) {
4876 sc->global_env=sc->NIL;
4877 dump_stack_free(sc);
4882 if(is_port(sc->inport)) {
4883 typeflag(sc->inport) = T_ATOM;
4886 sc->outport=sc->NIL;
4887 if(is_port(sc->save_inport)) {
4888 typeflag(sc->save_inport) = T_ATOM;
4890 sc->save_inport=sc->NIL;
4891 if(is_port(sc->loadport)) {
4892 typeflag(sc->loadport) = T_ATOM;
4894 sc->loadport=sc->NIL;
4896 gc(sc,sc->NIL,sc->NIL);
4898 for(i=0; i<=sc->last_cell_seg; i++) {
4899 sc->free(sc->alloc_seg[i]);
4901 sc->free(sc->strbuff);
4904 for(i=0; i<=sc->file_i; i++) {
4905 if (sc->load_stack[i].kind & port_file) {
4906 fname = sc->load_stack[i].rep.stdio.filename;
4914 void scheme_load_file(scheme *sc, FILE *fin)
4915 { scheme_load_named_file(sc,fin,0); }
4917 void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename) {
4918 dump_stack_reset(sc);
4919 sc->envir = sc->global_env;
4921 sc->load_stack[0].kind=port_input|port_file;
4922 sc->load_stack[0].rep.stdio.file=fin;
4923 sc->loadport=mk_port(sc,sc->load_stack);
4926 sc->interactive_repl=1;
4930 sc->load_stack[0].rep.stdio.curr_line = 0;
4931 if(fin!=stdin && filename)
4932 sc->load_stack[0].rep.stdio.filename = store_string(sc, strlen(filename), filename, 0);
4934 sc->load_stack[0].rep.stdio.filename = NULL;
4937 sc->inport=sc->loadport;
4938 sc->args = mk_integer(sc,sc->file_i);
4939 Eval_Cycle(sc, OP_T0LVL);
4940 typeflag(sc->loadport)=T_ATOM;
4941 if(sc->retcode==0) {
4942 sc->retcode=sc->nesting!=0;
4946 sc->free(sc->load_stack[0].rep.stdio.filename);
4947 sc->load_stack[0].rep.stdio.filename = NULL;
4951 void scheme_load_string(scheme *sc, const char *cmd) {
4952 dump_stack_reset(sc);
4953 sc->envir = sc->global_env;
4955 sc->load_stack[0].kind=port_input|port_string;
4956 sc->load_stack[0].rep.string.start=(char*)cmd; /* This func respects const */
4957 sc->load_stack[0].rep.string.past_the_end=(char*)cmd+strlen(cmd);
4958 sc->load_stack[0].rep.string.curr=(char*)cmd;
4959 sc->loadport=mk_port(sc,sc->load_stack);
4961 sc->interactive_repl=0;
4962 sc->inport=sc->loadport;
4963 sc->args = mk_integer(sc,sc->file_i);
4964 Eval_Cycle(sc, OP_T0LVL);
4965 typeflag(sc->loadport)=T_ATOM;
4966 if(sc->retcode==0) {
4967 sc->retcode=sc->nesting!=0;
4971 void scheme_define(scheme *sc, pointer envir, pointer symbol, pointer value) {
4974 x=find_slot_in_env(sc,envir,symbol,0);
4976 set_slot_in_env(sc, x, value);
4978 new_slot_spec_in_env(sc, envir, symbol, value);
4983 void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr)
4987 mk_symbol(sc,sr->name),
4988 mk_foreign_func(sc, sr->f));
4991 void scheme_register_foreign_func_list(scheme * sc,
4992 scheme_registerable * list,
4996 for(i = 0; i < count; i++)
4998 scheme_register_foreign_func(sc, list + i);
5002 pointer scheme_apply0(scheme *sc, const char *procname)
5003 { return scheme_eval(sc, cons(sc,mk_symbol(sc,procname),sc->NIL)); }
5005 void save_from_C_call(scheme *sc)
5007 pointer saved_data =
5014 sc->c_nest = cons(sc, saved_data, sc->c_nest);
5015 /* Truncate the dump stack so TS will return here when done, not
5016 directly resume pre-C-call operations. */
5017 dump_stack_reset(sc);
5019 void restore_from_C_call(scheme *sc)
5021 car(sc->sink) = caar(sc->c_nest);
5022 sc->envir = cadar(sc->c_nest);
5023 sc->dump = cdr(cdar(sc->c_nest));
5025 sc->c_nest = cdr(sc->c_nest);
5028 /* "func" and "args" are assumed to be already eval'ed. */
5029 pointer scheme_call(scheme *sc, pointer func, pointer args)
5031 int old_repl = sc->interactive_repl;
5032 sc->interactive_repl = 0;
5033 save_from_C_call(sc);
5034 sc->envir = sc->global_env;
5038 Eval_Cycle(sc, OP_APPLY);
5039 sc->interactive_repl = old_repl;
5040 restore_from_C_call(sc);
5044 pointer scheme_eval(scheme *sc, pointer obj)
5046 int old_repl = sc->interactive_repl;
5047 sc->interactive_repl = 0;
5048 save_from_C_call(sc);
5052 Eval_Cycle(sc, OP_EVAL);
5053 sc->interactive_repl = old_repl;
5054 restore_from_C_call(sc);
5061 /* ========== Main ========== */
5065 #if defined(__APPLE__) && !defined (OSX)
5068 extern MacTS_main(int argc, char **argv);
5070 int argc = ccommand(&argv);
5071 MacTS_main(argc,argv);
5074 int MacTS_main(int argc, char **argv) {
5076 int main(int argc, char **argv) {
5080 char *file_name=InitFile;
5087 if(argc==2 && strcmp(argv[1],"-?")==0) {
5088 printf("Usage: tinyscheme -?\n");
5089 printf("or: tinyscheme [<file1> <file2> ...]\n");
5090 printf("followed by\n");
5091 printf(" -1 <file> [<arg1> <arg2> ...]\n");
5092 printf(" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5093 printf("assuming that the executable is named tinyscheme.\n");
5094 printf("Use - as filename for stdin.\n");
5097 if(!scheme_init(&sc)) {
5098 fprintf(stderr,"Could not initialize!\n");
5101 scheme_set_input_port_file(&sc, stdin);
5102 scheme_set_output_port_file(&sc, stdout);
5104 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"load-extension"),mk_foreign_func(&sc, scm_load_ext));
5107 if(access(file_name,0)!=0) {
5108 char *p=getenv("TINYSCHEMEINIT");
5114 if(strcmp(file_name,"-")==0) {
5116 } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0) {
5117 pointer args=sc.NIL;
5118 isfile=file_name[1]=='1';
5120 if(strcmp(file_name,"-")==0) {
5123 fin=fopen(file_name,"r");
5125 for(;*argv;argv++) {
5126 pointer value=mk_string(&sc,*argv);
5127 args=cons(&sc,value,args);
5129 args=reverse_in_place(&sc,sc.NIL,args);
5130 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args);
5133 fin=fopen(file_name,"r");
5135 if(isfile && fin==0) {
5136 fprintf(stderr,"Could not open file %s\n",file_name);
5139 scheme_load_named_file(&sc,fin,file_name);
5141 scheme_load_string(&sc,file_name);
5143 if(!isfile || fin!=stdin) {
5145 fprintf(stderr,"Errors encountered reading %s\n",file_name);
5153 } while(file_name!=0);
5155 scheme_load_named_file(&sc,stdin,0);