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
39 # define stricmp strcasecmp
43 /* Used for documentation purposes, to signal functions in 'interface' */
58 #define TOK_SHARP_CONST 11
62 #define DELIMITERS "()\";\f\t\v\n\r "
65 * Basic memory allocation units
68 #define banner "TinyScheme 1.41"
75 static int stricmp(const char *s1, const char *s2)
89 #endif /* __APPLE__ */
92 static const char *strlwr(char *s) {
103 # define prompt "ts> "
107 # define InitFile "init.scm"
110 #ifndef FIRST_CELLSEGS
111 # define FIRST_CELLSEGS 3
116 /* Support for immediate values.
118 * Immediate values are tagged with IMMEDIATE_TAG, which is neither
119 * used in types, nor in pointer values.
121 * XXX: Currently, we only use this to tag pointers in vectors. */
122 #define IMMEDIATE_TAG 1
123 #define is_immediate(p) ((pointer) ((uintptr_t) (p) & IMMEDIATE_TAG))
124 #define set_immediate(p) ((pointer) ((uintptr_t) (p) | IMMEDIATE_TAG))
125 #define clr_immediate(p) ((pointer) ((uintptr_t) (p) & ~IMMEDIATE_TAG))
130 T_STRING=1 << 1, /* Do not use the lsb, it is used for
131 * immediate values. */
137 T_CONTINUATION=7 << 1,
144 T_ENVIRONMENT=14 << 1,
145 T_FOREIGN_OBJECT=15 << 1,
150 T_LAST_SYSTEM_TYPE=19 << 1
154 type_to_string (enum scheme_types typ)
158 case T_STRING: return "string";
159 case T_NUMBER: return "number";
160 case T_SYMBOL: return "symbol";
161 case T_PROC: return "proc";
162 case T_PAIR: return "pair";
163 case T_CLOSURE: return "closure";
164 case T_CONTINUATION: return "continuation";
165 case T_FOREIGN: return "foreign";
166 case T_CHARACTER: return "character";
167 case T_PORT: return "port";
168 case T_VECTOR: return "vector";
169 case T_MACRO: return "macro";
170 case T_PROMISE: return "promise";
171 case T_ENVIRONMENT: return "environment";
172 case T_FOREIGN_OBJECT: return "foreign object";
173 case T_BOOLEAN: return "boolean";
174 case T_NIL: return "nil";
175 case T_EOF_OBJ: return "eof object";
176 case T_SINK: return "sink";
178 assert (! "not reached");
181 /* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */
183 #define ADJ (1 << TYPE_BITS)
184 #define T_MASKTYPE (ADJ - 1)
185 #define T_TAGGED 1024 /* 0000010000000000 */
186 #define T_FINALIZE 2048 /* 0000100000000000 */
187 #define T_SYNTAX 4096 /* 0001000000000000 */
188 #define T_IMMUTABLE 8192 /* 0010000000000000 */
189 #define T_ATOM 16384 /* 0100000000000000 */ /* only for gc */
190 #define CLRATOM 49151 /* 1011111111111111 */ /* only for gc */
191 #define MARK 32768 /* 1000000000000000 */
192 #define UNMARK 32767 /* 0111111111111111 */
195 static num num_add(num a, num b);
196 static num num_mul(num a, num b);
197 static num num_div(num a, num b);
198 static num num_intdiv(num a, num b);
199 static num num_sub(num a, num b);
200 static num num_rem(num a, num b);
201 static num num_mod(num a, num b);
202 static int num_eq(num a, num b);
203 static int num_gt(num a, num b);
204 static int num_ge(num a, num b);
205 static int num_lt(num a, num b);
206 static int num_le(num a, num b);
209 static double round_per_R5RS(double x);
211 static int is_zero_double(double x);
212 static INLINE int num_is_integer(pointer p) {
213 return ((p)->_object._number.is_fixnum);
219 /* macros for cell operations */
220 #define typeflag(p) ((p)->_flag)
221 #define type(p) (typeflag(p)&T_MASKTYPE)
223 INTERFACE INLINE int is_string(pointer p) { return (type(p)==T_STRING); }
224 #define strvalue(p) ((p)->_object._string._svalue)
225 #define strlength(p) ((p)->_object._string._length)
227 INTERFACE static int is_list(scheme *sc, pointer p);
228 INTERFACE INLINE int is_vector(pointer p) { return (type(p)==T_VECTOR); }
229 /* Given a vector, return it's length. */
230 #define vector_length(v) (v)->_object._vector._length
231 /* Given a vector length, compute the amount of cells required to
233 #define vector_size(len) (1 + ((len) - 1 + 2) / 3)
234 INTERFACE static void fill_vector(pointer vec, pointer obj);
235 INTERFACE static pointer vector_elem(pointer vec, int ielem);
236 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a);
237 INTERFACE INLINE int is_number(pointer p) { return (type(p)==T_NUMBER); }
238 INTERFACE INLINE int is_integer(pointer p) {
241 if (num_is_integer(p) || (double)ivalue(p) == rvalue(p))
246 INTERFACE INLINE int is_real(pointer p) {
247 return is_number(p) && (!(p)->_object._number.is_fixnum);
250 INTERFACE INLINE int is_character(pointer p) { return (type(p)==T_CHARACTER); }
251 INTERFACE INLINE char *string_value(pointer p) { return strvalue(p); }
252 INLINE num nvalue(pointer p) { return ((p)->_object._number); }
253 INTERFACE long ivalue(pointer p) { return (num_is_integer(p)?(p)->_object._number.value.ivalue:(long)(p)->_object._number.value.rvalue); }
254 INTERFACE double rvalue(pointer p) { return (!num_is_integer(p)?(p)->_object._number.value.rvalue:(double)(p)->_object._number.value.ivalue); }
255 #define ivalue_unchecked(p) ((p)->_object._number.value.ivalue)
256 #define rvalue_unchecked(p) ((p)->_object._number.value.rvalue)
257 #define set_num_integer(p) (p)->_object._number.is_fixnum=1;
258 #define set_num_real(p) (p)->_object._number.is_fixnum=0;
259 INTERFACE long charvalue(pointer p) { return ivalue_unchecked(p); }
261 INTERFACE INLINE int is_port(pointer p) { return (type(p)==T_PORT); }
262 INTERFACE INLINE int is_inport(pointer p) { return is_port(p) && p->_object._port->kind & port_input; }
263 INTERFACE INLINE int is_outport(pointer p) { return is_port(p) && p->_object._port->kind & port_output; }
265 INTERFACE INLINE int is_pair(pointer p) { return (type(p)==T_PAIR); }
266 #define car(p) ((p)->_object._cons._car)
267 #define cdr(p) ((p)->_object._cons._cdr)
268 INTERFACE pointer pair_car(pointer p) { return car(p); }
269 INTERFACE pointer pair_cdr(pointer p) { return cdr(p); }
270 INTERFACE pointer set_car(pointer p, pointer q) { return car(p)=q; }
271 INTERFACE pointer set_cdr(pointer p, pointer q) { return cdr(p)=q; }
273 INTERFACE INLINE int is_symbol(pointer p) { return (type(p)==T_SYMBOL); }
274 INTERFACE INLINE char *symname(pointer p) { return strvalue(car(p)); }
276 SCHEME_EXPORT INLINE int hasprop(pointer p) { return (is_symbol(p)); }
277 #define symprop(p) cdr(p)
280 INTERFACE INLINE int is_syntax(pointer p) { return (typeflag(p)&T_SYNTAX); }
281 INTERFACE INLINE int is_proc(pointer p) { return (type(p)==T_PROC); }
282 INTERFACE INLINE int is_foreign(pointer p) { return (type(p)==T_FOREIGN); }
283 INTERFACE INLINE char *syntaxname(pointer p) { return strvalue(car(p)); }
284 #define procnum(p) ivalue(p)
285 static const char *procname(pointer x);
287 INTERFACE INLINE int is_closure(pointer p) { return (type(p)==T_CLOSURE); }
288 INTERFACE INLINE int is_macro(pointer p) { return (type(p)==T_MACRO); }
289 INTERFACE INLINE pointer closure_code(pointer p) { return car(p); }
290 INTERFACE INLINE pointer closure_env(pointer p) { return cdr(p); }
292 INTERFACE INLINE int is_continuation(pointer p) { return (type(p)==T_CONTINUATION); }
293 #define cont_dump(p) cdr(p)
295 INTERFACE INLINE int is_foreign_object(pointer p) { return (type(p)==T_FOREIGN_OBJECT); }
296 INTERFACE const foreign_object_vtable *get_foreign_object_vtable(pointer p) {
297 return p->_object._foreign_object._vtable;
299 INTERFACE void *get_foreign_object_data(pointer p) {
300 return p->_object._foreign_object._data;
303 /* To do: promise should be forced ONCE only */
304 INTERFACE INLINE int is_promise(pointer p) { return (type(p)==T_PROMISE); }
306 INTERFACE INLINE int is_environment(pointer p) { return (type(p)==T_ENVIRONMENT); }
307 #define setenvironment(p) typeflag(p) = T_ENVIRONMENT
309 #define is_atom(p) (typeflag(p)&T_ATOM)
310 #define setatom(p) typeflag(p) |= T_ATOM
311 #define clratom(p) typeflag(p) &= CLRATOM
313 #define is_mark(p) (typeflag(p)&MARK)
314 #define setmark(p) typeflag(p) |= MARK
315 #define clrmark(p) typeflag(p) &= UNMARK
317 INTERFACE INLINE int is_immutable(pointer p) { return (typeflag(p)&T_IMMUTABLE); }
318 /*#define setimmutable(p) typeflag(p) |= T_IMMUTABLE*/
319 INTERFACE INLINE void setimmutable(pointer p) { typeflag(p) |= T_IMMUTABLE; }
321 #define caar(p) car(car(p))
322 #define cadr(p) car(cdr(p))
323 #define cdar(p) cdr(car(p))
324 #define cddr(p) cdr(cdr(p))
325 #define cadar(p) car(cdr(car(p)))
326 #define caddr(p) car(cdr(cdr(p)))
327 #define cdaar(p) cdr(car(car(p)))
328 #define cadaar(p) car(cdr(car(car(p))))
329 #define cadddr(p) car(cdr(cdr(cdr(p))))
330 #define cddddr(p) cdr(cdr(cdr(cdr(p))))
333 static pointer history_flatten(scheme *sc);
334 static void history_mark(scheme *sc);
336 # define history_mark(SC) (void) 0
337 # define history_flatten(SC) (SC)->NIL
340 #if USE_CHAR_CLASSIFIERS
341 static INLINE int Cisalpha(int c) { return isascii(c) && isalpha(c); }
342 static INLINE int Cisdigit(int c) { return isascii(c) && isdigit(c); }
343 static INLINE int Cisspace(int c) { return isascii(c) && isspace(c); }
344 static INLINE int Cisupper(int c) { return isascii(c) && isupper(c); }
345 static INLINE int Cislower(int c) { return isascii(c) && islower(c); }
349 static const char *charnames[32]={
384 static int is_ascii_name(const char *name, int *pc) {
386 for(i=0; i<32; i++) {
387 if(stricmp(name,charnames[i])==0) {
392 if(stricmp(name,"del")==0) {
401 static int file_push(scheme *sc, pointer fname);
402 static void file_pop(scheme *sc);
403 static int file_interactive(scheme *sc);
404 static INLINE int is_one_of(char *s, int c);
405 static int alloc_cellseg(scheme *sc, int n);
406 static long binary_decode(const char *s);
407 static INLINE pointer get_cell(scheme *sc, pointer a, pointer b);
408 static pointer _get_cell(scheme *sc, pointer a, pointer b);
409 static pointer reserve_cells(scheme *sc, int n);
410 static pointer get_consecutive_cells(scheme *sc, int n);
411 static pointer find_consecutive_cells(scheme *sc, int n);
412 static void finalize_cell(scheme *sc, pointer a);
413 static int count_consecutive_cells(pointer x, int needed);
414 static pointer find_slot_in_env(scheme *sc, pointer env, pointer sym, int all);
415 static pointer mk_number(scheme *sc, num n);
416 static char *store_string(scheme *sc, int len, const char *str, char fill);
417 static pointer mk_vector(scheme *sc, int len);
418 static pointer mk_atom(scheme *sc, char *q);
419 static pointer mk_sharp_const(scheme *sc, char *name);
420 static pointer mk_port(scheme *sc, port *p);
421 static pointer port_from_filename(scheme *sc, const char *fn, int prop);
422 static pointer port_from_file(scheme *sc, FILE *, int prop);
423 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop);
424 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop);
425 static port *port_rep_from_file(scheme *sc, FILE *, int prop);
426 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop);
427 static void port_close(scheme *sc, pointer p, int flag);
428 static void mark(pointer a);
429 static void gc(scheme *sc, pointer a, pointer b);
430 static int basic_inchar(port *pt);
431 static int inchar(scheme *sc);
432 static void backchar(scheme *sc, int c);
433 static char *readstr_upto(scheme *sc, char *delim);
434 static pointer readstrexp(scheme *sc);
435 static INLINE int skipspace(scheme *sc);
436 static int token(scheme *sc);
437 static void printslashstring(scheme *sc, char *s, int len);
438 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen);
439 static void printatom(scheme *sc, pointer l, int f);
440 static pointer mk_proc(scheme *sc, enum scheme_opcodes op);
441 static pointer mk_closure(scheme *sc, pointer c, pointer e);
442 static pointer mk_continuation(scheme *sc, pointer d);
443 static pointer reverse(scheme *sc, pointer term, pointer list);
444 static pointer reverse_in_place(scheme *sc, pointer term, pointer list);
445 static pointer revappend(scheme *sc, pointer a, pointer b);
446 static void dump_stack_mark(scheme *);
447 static pointer opexe_0(scheme *sc, enum scheme_opcodes op);
448 static pointer opexe_1(scheme *sc, enum scheme_opcodes op);
449 static pointer opexe_2(scheme *sc, enum scheme_opcodes op);
450 static pointer opexe_3(scheme *sc, enum scheme_opcodes op);
451 static pointer opexe_4(scheme *sc, enum scheme_opcodes op);
452 static pointer opexe_5(scheme *sc, enum scheme_opcodes op);
453 static pointer opexe_6(scheme *sc, enum scheme_opcodes op);
454 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op);
455 static void assign_syntax(scheme *sc, char *name);
456 static int syntaxnum(pointer p);
457 static void assign_proc(scheme *sc, enum scheme_opcodes, char *name);
459 #define num_ivalue(n) (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue)
460 #define num_rvalue(n) (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue)
462 static num num_add(num a, num b) {
464 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
466 ret.value.ivalue= a.value.ivalue+b.value.ivalue;
468 ret.value.rvalue=num_rvalue(a)+num_rvalue(b);
473 static num num_mul(num a, num b) {
475 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
477 ret.value.ivalue= a.value.ivalue*b.value.ivalue;
479 ret.value.rvalue=num_rvalue(a)*num_rvalue(b);
484 static num num_div(num a, num b) {
486 ret.is_fixnum=a.is_fixnum && b.is_fixnum && a.value.ivalue%b.value.ivalue==0;
488 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
490 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
495 static num num_intdiv(num a, num b) {
497 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
499 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
501 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
506 static num num_sub(num a, num b) {
508 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
510 ret.value.ivalue= a.value.ivalue-b.value.ivalue;
512 ret.value.rvalue=num_rvalue(a)-num_rvalue(b);
517 static num num_rem(num a, num b) {
520 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
524 /* remainder should have same sign as second operand */
529 } else if (res < 0) {
534 ret.value.ivalue=res;
538 static num num_mod(num a, num b) {
541 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
545 /* modulo should have same sign as second operand */
549 ret.value.ivalue=res;
553 static int num_eq(num a, num b) {
555 int is_fixnum=a.is_fixnum && b.is_fixnum;
557 ret= a.value.ivalue==b.value.ivalue;
559 ret=num_rvalue(a)==num_rvalue(b);
565 static int num_gt(num a, num b) {
567 int is_fixnum=a.is_fixnum && b.is_fixnum;
569 ret= a.value.ivalue>b.value.ivalue;
571 ret=num_rvalue(a)>num_rvalue(b);
576 static int num_ge(num a, num b) {
580 static int num_lt(num a, num b) {
582 int is_fixnum=a.is_fixnum && b.is_fixnum;
584 ret= a.value.ivalue<b.value.ivalue;
586 ret=num_rvalue(a)<num_rvalue(b);
591 static int num_le(num a, num b) {
596 /* Round to nearest. Round to even if midway */
597 static double round_per_R5RS(double x) {
607 if(fmod(fl,2.0)==0.0) { /* I imagine this holds */
616 static int is_zero_double(double x) {
617 return x<DBL_MIN && x>-DBL_MIN;
620 static long binary_decode(const char *s) {
623 while(*s!=0 && (*s=='1' || *s=='0')) {
634 /* Tags are like property lists, but can be attached to arbitrary
640 mk_tagged_value(scheme *sc, pointer v, pointer tag_car, pointer tag_cdr)
644 assert(! is_vector(v));
646 r = get_consecutive_cells(sc, 2);
650 memcpy(r, v, sizeof *v);
651 typeflag(r) |= T_TAGGED;
654 typeflag(t) = T_PAIR;
664 return !! (typeflag(v) & T_TAGGED);
667 static INLINE pointer
668 get_tag(scheme *sc, pointer v)
677 #define mk_tagged_value(SC, X, A, B) (X)
679 #define get_tag(SC, V) (SC)->NIL
685 /* Allocate a new cell segment but do not make it available yet. */
687 _alloc_cellseg(scheme *sc, size_t len, void **alloc, pointer *cells)
692 if (adj < sizeof(struct cell))
693 adj = sizeof(struct cell);
695 cp = sc->malloc(len * sizeof(struct cell) + adj);
701 /* adjust in TYPE_BITS-bit boundary */
702 if (((uintptr_t) cp) % adj != 0)
703 cp = (void *) (adj * ((uintptr_t) cp / adj + 1));
709 /* allocate new cell segment */
710 static int alloc_cellseg(scheme *sc, int n) {
717 for (k = 0; k < n; k++) {
718 if (sc->last_cell_seg >= CELL_NSEGMENT - 1)
720 i = ++sc->last_cell_seg;
721 if (_alloc_cellseg(sc, CELL_SEGSIZE, &sc->alloc_seg[i], &newp)) {
725 /* insert new segment in address order */
726 sc->cell_seg[i] = newp;
727 while (i > 0 && sc->cell_seg[i - 1] > sc->cell_seg[i]) {
729 sc->cell_seg[i] = sc->cell_seg[i - 1];
730 sc->cell_seg[--i] = p;
732 sc->fcells += CELL_SEGSIZE;
733 last = newp + CELL_SEGSIZE - 1;
734 for (p = newp; p <= last; p++) {
739 /* insert new cells in address order on free list */
740 if (sc->free_cell == sc->NIL || p < sc->free_cell) {
741 cdr(last) = sc->free_cell;
742 sc->free_cell = newp;
745 while (cdr(p) != sc->NIL && newp > cdr(p))
756 /* Controlling the garbage collector.
758 * Every time a cell is allocated, the interpreter may run out of free
759 * cells and do a garbage collection. This is problematic because it
760 * might garbage collect objects that have been allocated, but are not
761 * yet made available to the interpreter.
763 * Previously, we would plug such newly allocated cells into the list
764 * of newly allocated objects rooted at car(sc->sink), but that
765 * requires allocating yet another cell increasing pressure on the
766 * memory management system.
768 * A faster alternative is to preallocate the cells needed for an
769 * operation and make sure the garbage collection is not run until all
770 * allocated objects are plugged in. This can be done with gc_disable
774 /* The garbage collector is enabled if the inhibit counter is
778 /* For now we provide a way to disable this optimization for
779 * benchmarking and because it produces slightly smaller code. */
780 #ifndef USE_GC_LOCKING
781 # define USE_GC_LOCKING 1
784 /* To facilitate nested calls to gc_disable, functions that allocate
785 * more than one cell may define a macro, e.g. foo_allocates. This
786 * macro can be used to compute the amount of preallocation at the
787 * call site with the help of this macro. */
788 #define gc_reservations(fn) fn ## _allocates
792 /* Report a shortage in reserved cells, and terminate the program. */
794 gc_reservation_failure(struct scheme *sc)
798 "insufficient reservation\n")
801 "insufficient reservation in line %d\n",
802 sc->reserved_lineno);
807 /* Disable the garbage collection and reserve the given number of
808 * cells. gc_disable may be nested, but the enclosing reservation
809 * must include the reservations of all nested calls. Note: You must
810 * re-enable the gc before calling Error_X. */
812 _gc_disable(struct scheme *sc, size_t reserve, int lineno)
814 if (sc->inhibit_gc == 0) {
815 reserve_cells(sc, (reserve));
816 sc->reserved_cells = (reserve);
820 sc->reserved_lineno = lineno;
822 } else if (sc->reserved_cells < (reserve))
823 gc_reservation_failure (sc);
826 #define gc_disable(sc, reserve) \
827 _gc_disable (sc, reserve, __LINE__)
829 /* Enable the garbage collector. */
830 #define gc_enable(sc) \
832 assert(sc->inhibit_gc); \
833 sc->inhibit_gc -= 1; \
836 /* Test whether the garbage collector is enabled. */
837 #define gc_enabled(sc) \
838 (sc->inhibit_gc == GC_ENABLED)
840 /* Consume a reserved cell. */
841 #define gc_consume(sc) \
843 assert(! gc_enabled (sc)); \
844 if (sc->reserved_cells == 0) \
845 gc_reservation_failure (sc); \
846 sc->reserved_cells -= 1; \
849 #else /* USE_GC_LOCKING */
851 #define gc_disable(sc, reserve) (void) 0
852 #define gc_enable(sc) (void) 0
853 #define gc_enabled(sc) 1
854 #define gc_consume(sc) (void) 0
856 #endif /* USE_GC_LOCKING */
858 static INLINE pointer get_cell_x(scheme *sc, pointer a, pointer b) {
859 if (! gc_enabled (sc) || sc->free_cell != sc->NIL) {
860 pointer x = sc->free_cell;
861 if (! gc_enabled (sc))
863 sc->free_cell = cdr(x);
867 assert (gc_enabled (sc));
868 return _get_cell (sc, a, b);
872 /* get new cell. parameter a, b is marked by gc. */
873 static pointer _get_cell(scheme *sc, pointer a, pointer b) {
880 assert (gc_enabled (sc));
881 if (sc->free_cell == sc->NIL) {
882 const int min_to_be_recovered = sc->last_cell_seg*8;
884 if (sc->fcells < min_to_be_recovered
885 || sc->free_cell == sc->NIL) {
886 /* if only a few recovered, get more to avoid fruitless gc's */
887 if (!alloc_cellseg(sc,1) && sc->free_cell == sc->NIL) {
894 sc->free_cell = cdr(x);
899 /* make sure that there is a given number of cells free */
900 static pointer reserve_cells(scheme *sc, int n) {
905 /* Are there enough cells available? */
906 if (sc->fcells < n) {
907 /* If not, try gc'ing some */
908 gc(sc, sc->NIL, sc->NIL);
909 if (sc->fcells < n) {
910 /* If there still aren't, try getting more heap */
911 if (!alloc_cellseg(sc,1)) {
916 if (sc->fcells < n) {
917 /* If all fail, report failure */
925 static pointer get_consecutive_cells(scheme *sc, int n) {
928 if(sc->no_memory) { return sc->sink; }
930 /* Are there any cells available? */
931 x=find_consecutive_cells(sc,n);
932 if (x != sc->NIL) { return x; }
934 /* If not, try gc'ing some */
935 gc(sc, sc->NIL, sc->NIL);
936 x=find_consecutive_cells(sc,n);
937 if (x != sc->NIL) { return x; }
939 /* If there still aren't, try getting more heap */
940 if (!alloc_cellseg(sc,1))
946 x=find_consecutive_cells(sc,n);
947 if (x != sc->NIL) { return x; }
949 /* If all fail, report failure */
954 static int count_consecutive_cells(pointer x, int needed) {
959 if(n>needed) return n;
964 static pointer find_consecutive_cells(scheme *sc, int n) {
969 while(*pp!=sc->NIL) {
970 cnt=count_consecutive_cells(*pp,n);
982 /* Free a cell. This is dangerous. Only free cells that are not
985 free_cell(scheme *sc, pointer a)
987 cdr(a) = sc->free_cell;
992 /* Free a cell and retrieve its content. This is dangerous. Only
993 * free cells that are not referenced. */
995 free_cons(scheme *sc, pointer a, pointer *r_car, pointer *r_cdr)
1002 /* To retain recent allocs before interpreter knows about them -
1005 static void push_recent_alloc(scheme *sc, pointer recent, pointer extra)
1007 pointer holder = get_cell_x(sc, recent, extra);
1008 typeflag(holder) = T_PAIR | T_IMMUTABLE;
1009 car(holder) = recent;
1010 cdr(holder) = car(sc->sink);
1011 car(sc->sink) = holder;
1014 static INLINE void ok_to_freely_gc(scheme *sc)
1016 pointer a = car(sc->sink), next;
1017 car(sc->sink) = sc->NIL;
1018 while (a != sc->NIL)
1026 static pointer get_cell(scheme *sc, pointer a, pointer b)
1028 pointer cell = get_cell_x(sc, a, b);
1029 /* For right now, include "a" and "b" in "cell" so that gc doesn't
1030 think they are garbage. */
1031 /* Tentatively record it as a pair so gc understands it. */
1032 typeflag(cell) = T_PAIR;
1035 if (gc_enabled (sc))
1036 push_recent_alloc(sc, cell, sc->NIL);
1040 static pointer get_vector_object(scheme *sc, int len, pointer init)
1042 pointer cells = get_consecutive_cells(sc, vector_size(len));
1043 if(sc->no_memory) { return sc->sink; }
1044 /* Record it as a vector so that gc understands it. */
1045 typeflag(cells) = (T_VECTOR | T_ATOM | T_FINALIZE);
1046 vector_length(cells) = len;
1047 fill_vector(cells,init);
1048 if (gc_enabled (sc))
1049 push_recent_alloc(sc, cells, sc->NIL);
1053 /* Medium level cell allocation */
1055 /* get new cons cell */
1056 pointer _cons(scheme *sc, pointer a, pointer b, int immutable) {
1057 pointer x = get_cell(sc,a, b);
1059 typeflag(x) = T_PAIR;
1068 /* ========== oblist implementation ========== */
1070 #ifndef USE_OBJECT_LIST
1072 static int hash_fn(const char *key, int table_size);
1074 static pointer oblist_initial_value(scheme *sc)
1076 /* There are about 768 symbols used after loading the
1078 return mk_vector(sc, 1009);
1081 /* Add a new symbol NAME at SLOT. SLOT must be obtained using
1082 * oblist_find_by_name, and no insertion must be done between
1083 * obtaining the SLOT and calling this function. Returns the new
1086 * If SLOT is NULL, the new symbol is be placed at the appropriate
1087 * place in the vector. */
1088 static pointer oblist_add_by_name(scheme *sc, const char *name, pointer *slot)
1090 #define oblist_add_by_name_allocates 3
1094 gc_disable(sc, gc_reservations (oblist_add_by_name));
1095 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
1096 typeflag(x) = T_SYMBOL;
1097 setimmutable(car(x));
1100 location = hash_fn(name, vector_length(sc->oblist));
1101 set_vector_elem(sc->oblist, location,
1102 immutable_cons(sc, x, vector_elem(sc->oblist, location)));
1104 *slot = immutable_cons(sc, x, *slot);
1111 /* Lookup the symbol NAME. Returns the symbol, or NIL if it does not
1112 * exist. In that case, SLOT points to the point where the new symbol
1113 * is to be inserted.
1115 * SLOT may be set to NULL if the new symbol should be placed at the
1116 * appropriate place in the vector. */
1117 static INLINE pointer
1118 oblist_find_by_name(scheme *sc, const char *name, pointer **slot)
1125 location = hash_fn(name, vector_length(sc->oblist));
1126 for (*slot = NULL, x = vector_elem(sc->oblist, location);
1127 x != sc->NIL; *slot = &cdr(x), x = **slot) {
1128 s = symname(car(x));
1129 /* case-insensitive, per R5RS section 2. */
1130 d = stricmp(name, s);
1132 return car(x); /* Hit. */
1139 static pointer oblist_all_symbols(scheme *sc)
1143 pointer ob_list = sc->NIL;
1145 for (i = 0; i < vector_length(sc->oblist); i++) {
1146 for (x = vector_elem(sc->oblist, i); x != sc->NIL; x = cdr(x)) {
1147 ob_list = cons(sc, x, ob_list);
1155 static pointer oblist_initial_value(scheme *sc)
1160 /* Lookup the symbol NAME. Returns the symbol, or NIL if it does not
1161 * exist. In that case, SLOT points to the point where the new symbol
1162 * is to be inserted. */
1163 static INLINE pointer
1164 oblist_find_by_name(scheme *sc, const char *name, pointer **slot)
1170 for (*slot = &sc->oblist, x = **slot; x != sc->NIL; *slot = &cdr(x), x = **slot) {
1171 s = symname(car(x));
1172 /* case-insensitive, per R5RS section 2. */
1173 d = stricmp(name, s);
1175 return car(x); /* Hit. */
1182 /* Add a new symbol NAME at SLOT. SLOT must be obtained using
1183 * oblist_find_by_name, and no insertion must be done between
1184 * obtaining the SLOT and calling this function. Returns the new
1186 static pointer oblist_add_by_name(scheme *sc, const char *name, pointer *slot)
1188 #define oblist_add_by_name_allocates 3
1191 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
1192 typeflag(x) = T_SYMBOL;
1193 setimmutable(car(x));
1194 *slot = immutable_cons(sc, x, *slot);
1197 static pointer oblist_all_symbols(scheme *sc)
1204 static pointer mk_port(scheme *sc, port *p) {
1205 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1207 typeflag(x) = T_PORT|T_ATOM|T_FINALIZE;
1212 pointer mk_foreign_func(scheme *sc, foreign_func f) {
1213 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1215 typeflag(x) = (T_FOREIGN | T_ATOM);
1220 pointer mk_foreign_object(scheme *sc, const foreign_object_vtable *vtable, void *data) {
1221 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1223 typeflag(x) = (T_FOREIGN_OBJECT | T_ATOM | T_FINALIZE);
1224 x->_object._foreign_object._vtable=vtable;
1225 x->_object._foreign_object._data = data;
1229 INTERFACE pointer mk_character(scheme *sc, int c) {
1230 pointer x = get_cell(sc,sc->NIL, sc->NIL);
1232 typeflag(x) = (T_CHARACTER | T_ATOM);
1233 ivalue_unchecked(x)= c;
1240 #if USE_SMALL_INTEGERS
1242 /* s_save assumes that all opcodes can be expressed as a small
1244 #define MAX_SMALL_INTEGER OP_MAXDEFINED
1247 initialize_small_integers(scheme *sc)
1250 if (_alloc_cellseg(sc, MAX_SMALL_INTEGER, &sc->integer_alloc,
1251 &sc->integer_cells))
1254 for (i = 0; i < MAX_SMALL_INTEGER; i++) {
1255 pointer x = &sc->integer_cells[i];
1256 typeflag(x) = T_NUMBER | T_ATOM | MARK;
1257 ivalue_unchecked(x) = i;
1264 static INLINE pointer
1265 mk_small_integer(scheme *sc, long n)
1267 #define mk_small_integer_allocates 0
1268 assert(0 <= n && n < MAX_SMALL_INTEGER);
1269 return &sc->integer_cells[n];
1273 #define mk_small_integer_allocates 1
1274 #define mk_small_integer mk_integer
1278 /* get number atom (integer) */
1279 INTERFACE pointer mk_integer(scheme *sc, long n) {
1282 #if USE_SMALL_INTEGERS
1283 if (0 <= n && n < MAX_SMALL_INTEGER)
1284 return mk_small_integer(sc, n);
1287 x = get_cell(sc,sc->NIL, sc->NIL);
1288 typeflag(x) = (T_NUMBER | T_ATOM);
1289 ivalue_unchecked(x)= n;
1296 INTERFACE pointer mk_real(scheme *sc, double n) {
1297 pointer x = get_cell(sc,sc->NIL, sc->NIL);
1299 typeflag(x) = (T_NUMBER | T_ATOM);
1300 rvalue_unchecked(x)= n;
1305 static pointer mk_number(scheme *sc, num n) {
1307 return mk_integer(sc,n.value.ivalue);
1309 return mk_real(sc,n.value.rvalue);
1313 /* allocate name to string area */
1314 static char *store_string(scheme *sc, int len_str, const char *str, char fill) {
1317 q=(char*)sc->malloc(len_str+1);
1323 memcpy (q, str, len_str);
1326 memset(q, fill, len_str);
1332 /* get new string */
1333 INTERFACE pointer mk_string(scheme *sc, const char *str) {
1334 return mk_counted_string(sc,str,strlen(str));
1337 INTERFACE pointer mk_counted_string(scheme *sc, const char *str, int len) {
1338 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1339 typeflag(x) = (T_STRING | T_ATOM | T_FINALIZE);
1340 strvalue(x) = store_string(sc,len,str,0);
1345 INTERFACE pointer mk_empty_string(scheme *sc, int len, char fill) {
1346 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1347 typeflag(x) = (T_STRING | T_ATOM | T_FINALIZE);
1348 strvalue(x) = store_string(sc,len,0,fill);
1353 INTERFACE static pointer mk_vector(scheme *sc, int len)
1354 { return get_vector_object(sc,len,sc->NIL); }
1356 INTERFACE static void fill_vector(pointer vec, pointer obj) {
1358 assert (is_vector (vec));
1359 for(i = 0; i < vector_length(vec); i++) {
1360 vec->_object._vector._elements[i] = set_immediate(obj);
1364 INTERFACE static pointer vector_elem(pointer vec, int ielem) {
1365 assert (is_vector (vec));
1366 assert (ielem < vector_length(vec));
1367 return clr_immediate(vec->_object._vector._elements[ielem]);
1370 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a) {
1371 assert (is_vector (vec));
1372 assert (ielem < vector_length(vec));
1373 vec->_object._vector._elements[ielem] = set_immediate(a);
1377 /* get new symbol */
1378 INTERFACE pointer mk_symbol(scheme *sc, const char *name) {
1379 #define mk_symbol_allocates oblist_add_by_name_allocates
1383 /* first check oblist */
1384 x = oblist_find_by_name(sc, name, &slot);
1388 x = oblist_add_by_name(sc, name, slot);
1393 INTERFACE pointer gensym(scheme *sc) {
1398 for(; sc->gensym_cnt<LONG_MAX; sc->gensym_cnt++) {
1399 snprintf(name,40,"gensym-%ld",sc->gensym_cnt);
1401 /* first check oblist */
1402 x = oblist_find_by_name(sc, name, &slot);
1407 x = oblist_add_by_name(sc, name, slot);
1415 /* double the size of the string buffer */
1416 static int expand_strbuff(scheme *sc) {
1417 size_t new_size = sc->strbuff_size * 2;
1418 char *new_buffer = sc->malloc(new_size);
1419 if (new_buffer == 0) {
1423 memcpy(new_buffer, sc->strbuff, sc->strbuff_size);
1424 sc->free(sc->strbuff);
1425 sc->strbuff = new_buffer;
1426 sc->strbuff_size = new_size;
1430 /* make symbol or number atom from string */
1431 static pointer mk_atom(scheme *sc, char *q) {
1433 int has_dec_point=0;
1439 while ((next = strstr(next, "::")) != 0) {
1440 /* Keep looking for the last occurrence. */
1447 return cons(sc, sc->COLON_HOOK,
1451 cons(sc, mk_symbol(sc, strlwr(p + 2)),
1453 cons(sc, mk_atom(sc, q), sc->NIL)));
1459 if ((c == '+') || (c == '-')) {
1466 return (mk_symbol(sc, strlwr(q)));
1468 } else if (c == '.') {
1472 return (mk_symbol(sc, strlwr(q)));
1474 } else if (!isdigit(c)) {
1475 return (mk_symbol(sc, strlwr(q)));
1478 for ( ; (c = *p) != 0; ++p) {
1481 if(!has_dec_point) {
1486 else if ((c == 'e') || (c == 'E')) {
1488 has_dec_point = 1; /* decimal point illegal
1491 if ((*p == '-') || (*p == '+') || isdigit(*p)) {
1496 return (mk_symbol(sc, strlwr(q)));
1500 return mk_real(sc,atof(q));
1502 return (mk_integer(sc, atol(q)));
1506 static pointer mk_sharp_const(scheme *sc, char *name) {
1508 char tmp[STRBUFFSIZE];
1510 if (!strcmp(name, "t"))
1512 else if (!strcmp(name, "f"))
1514 else if (*name == 'o') {/* #o (octal) */
1515 snprintf(tmp, STRBUFFSIZE, "0%s", name+1);
1516 sscanf(tmp, "%lo", (long unsigned *)&x);
1517 return (mk_integer(sc, x));
1518 } else if (*name == 'd') { /* #d (decimal) */
1519 sscanf(name+1, "%ld", (long int *)&x);
1520 return (mk_integer(sc, x));
1521 } else if (*name == 'x') { /* #x (hex) */
1522 snprintf(tmp, STRBUFFSIZE, "0x%s", name+1);
1523 sscanf(tmp, "%lx", (long unsigned *)&x);
1524 return (mk_integer(sc, x));
1525 } else if (*name == 'b') { /* #b (binary) */
1526 x = binary_decode(name+1);
1527 return (mk_integer(sc, x));
1528 } else if (*name == '\\') { /* #\w (character) */
1530 if(stricmp(name+1,"space")==0) {
1532 } else if(stricmp(name+1,"newline")==0) {
1534 } else if(stricmp(name+1,"return")==0) {
1536 } else if(stricmp(name+1,"tab")==0) {
1538 } else if(name[1]=='x' && name[2]!=0) {
1540 if(sscanf(name+2,"%x",(unsigned int *)&c1)==1 && c1 < UCHAR_MAX) {
1546 } else if(is_ascii_name(name+1,&c)) {
1549 } else if(name[2]==0) {
1554 return mk_character(sc,c);
1559 /* ========== garbage collector ========== */
1562 * We use algorithm E (Knuth, The Art of Computer Programming Vol.1,
1563 * sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm,
1566 static void mark(pointer a) {
1574 for (i = 0; i < vector_length(p); i++) {
1575 mark(clr_immediate(p->_object._vector._elements[i]));
1579 else if (is_port(p)) {
1580 port *pt = p->_object._port;
1581 mark(pt->curr_line);
1585 /* Mark tag if p has one. */
1592 if (q && !is_mark(q)) {
1593 setatom(p); /* a note that we have moved car */
1599 E5: q = cdr(p); /* down cdr */
1600 if (q && !is_mark(q)) {
1606 E6: /* up. Undo the link switching from steps E4 and E5. */
1624 /* garbage collection. parameter a, b is marked. */
1625 static void gc(scheme *sc, pointer a, pointer b) {
1629 assert (gc_enabled (sc));
1631 if(sc->gc_verbose) {
1632 putstr(sc, "gc...");
1635 /* mark system globals */
1637 mark(sc->global_env);
1639 /* mark current registers */
1644 dump_stack_mark(sc);
1647 mark(sc->save_inport);
1650 for (i = 0; i <= sc->file_i; i++) {
1651 mark(sc->load_stack[i].filename);
1652 mark(sc->load_stack[i].curr_line);
1655 /* Mark recent objects the interpreter doesn't know about yet. */
1656 mark(car(sc->sink));
1657 /* Mark any older stuff above nested C calls */
1660 /* mark variables a, b */
1664 /* garbage collect */
1667 sc->free_cell = sc->NIL;
1668 /* free-list is kept sorted by address so as to maintain consecutive
1669 ranges, if possible, for use with vectors. Here we scan the cells
1670 (which are also kept sorted by address) downwards to build the
1671 free-list in sorted order.
1673 for (i = sc->last_cell_seg; i >= 0; i--) {
1674 p = sc->cell_seg[i] + CELL_SEGSIZE;
1675 while (--p >= sc->cell_seg[i]) {
1676 if (typeflag(p) & IMMEDIATE_TAG)
1682 if (typeflag(p) & T_FINALIZE) {
1683 finalize_cell(sc, p);
1688 cdr(p) = sc->free_cell;
1694 if (sc->gc_verbose) {
1696 snprintf(msg,80,"done: %ld cells were recovered.\n", sc->fcells);
1701 static void finalize_cell(scheme *sc, pointer a) {
1703 sc->free(strvalue(a));
1704 } else if(is_port(a)) {
1705 if(a->_object._port->kind&port_file
1706 && a->_object._port->rep.stdio.closeit) {
1707 port_close(sc,a,port_input|port_output);
1708 } else if (a->_object._port->kind & port_srfi6) {
1709 sc->free(a->_object._port->rep.string.start);
1711 sc->free(a->_object._port);
1712 } else if(is_foreign_object(a)) {
1713 a->_object._foreign_object._vtable->finalize(sc, a->_object._foreign_object._data);
1714 } else if (is_vector(a)) {
1716 for (i = vector_size(vector_length(a)) - 1; i > 0; i--) {
1720 cdr(p) = sc->free_cell;
1729 port_clear_location (scheme *sc, port *p)
1731 p->curr_line = sc->NIL;
1732 p->filename = sc->NIL;
1736 port_increment_current_line (scheme *sc, port *p, long delta)
1742 mk_integer(sc, ivalue_unchecked(p->curr_line) + delta);
1746 port_init_location (scheme *sc, port *p, pointer name)
1748 p->curr_line = mk_integer(sc, 0);
1749 p->filename = name ? name : mk_string(sc, "<unknown>");
1755 port_clear_location (scheme *sc, port *p)
1760 port_increment_current_line (scheme *sc, port *p, long delta)
1765 port_init_location (scheme *sc, port *p, pointer name)
1771 /* ========== Routines for Reading ========== */
1773 static int file_push(scheme *sc, pointer fname) {
1776 if (sc->file_i == MAXFIL-1)
1778 fin = fopen(string_value(fname), "r");
1781 sc->load_stack[sc->file_i].kind=port_file|port_input;
1782 sc->load_stack[sc->file_i].rep.stdio.file=fin;
1783 sc->load_stack[sc->file_i].rep.stdio.closeit=1;
1784 sc->nesting_stack[sc->file_i]=0;
1785 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1786 port_init_location(sc, &sc->load_stack[sc->file_i], fname);
1791 static void file_pop(scheme *sc) {
1792 if(sc->file_i != 0) {
1793 sc->nesting=sc->nesting_stack[sc->file_i];
1794 port_close(sc,sc->loadport,port_input);
1795 port_clear_location(sc, &sc->load_stack[sc->file_i]);
1797 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1801 static int file_interactive(scheme *sc) {
1802 return sc->file_i==0 && sc->load_stack[0].rep.stdio.file==stdin
1803 && sc->inport->_object._port->kind&port_file;
1806 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop) {
1810 if(prop==(port_input|port_output)) {
1812 } else if(prop==port_output) {
1821 pt=port_rep_from_file(sc,f,prop);
1822 pt->rep.stdio.closeit=1;
1823 port_init_location(sc, pt, mk_string(sc, fn));
1827 static pointer port_from_filename(scheme *sc, const char *fn, int prop) {
1829 pt=port_rep_from_filename(sc,fn,prop);
1833 return mk_port(sc,pt);
1836 static port *port_rep_from_file(scheme *sc, FILE *f, int prop)
1840 pt = (port *)sc->malloc(sizeof *pt);
1844 pt->kind = port_file | prop;
1845 pt->rep.stdio.file = f;
1846 pt->rep.stdio.closeit = 0;
1847 port_init_location(sc, pt, NULL);
1851 static pointer port_from_file(scheme *sc, FILE *f, int prop) {
1853 pt=port_rep_from_file(sc,f,prop);
1857 return mk_port(sc,pt);
1860 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1862 pt=(port*)sc->malloc(sizeof(port));
1866 pt->kind=port_string|prop;
1867 pt->rep.string.start=start;
1868 pt->rep.string.curr=start;
1869 pt->rep.string.past_the_end=past_the_end;
1870 port_init_location(sc, pt, NULL);
1874 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1876 pt=port_rep_from_string(sc,start,past_the_end,prop);
1880 return mk_port(sc,pt);
1883 #define BLOCK_SIZE 256
1885 static port *port_rep_from_scratch(scheme *sc) {
1888 pt=(port*)sc->malloc(sizeof(port));
1892 start=sc->malloc(BLOCK_SIZE);
1896 memset(start,' ',BLOCK_SIZE-1);
1897 start[BLOCK_SIZE-1]='\0';
1898 pt->kind=port_string|port_output|port_srfi6;
1899 pt->rep.string.start=start;
1900 pt->rep.string.curr=start;
1901 pt->rep.string.past_the_end=start+BLOCK_SIZE-1;
1902 port_init_location(sc, pt, NULL);
1906 static pointer port_from_scratch(scheme *sc) {
1908 pt=port_rep_from_scratch(sc);
1912 return mk_port(sc,pt);
1915 static void port_close(scheme *sc, pointer p, int flag) {
1916 port *pt=p->_object._port;
1918 if((pt->kind & (port_input|port_output))==0) {
1919 /* Cleanup is here so (close-*-port) functions could work too */
1920 port_clear_location(sc, pt);
1921 if(pt->kind&port_file) {
1922 fclose(pt->rep.stdio.file);
1928 /* get new character from input file */
1929 static int inchar(scheme *sc) {
1933 pt = sc->inport->_object._port;
1934 if(pt->kind & port_saw_EOF)
1936 c = basic_inchar(pt);
1937 if(c == EOF && sc->inport == sc->loadport) {
1938 /* Instead, set port_saw_EOF */
1939 pt->kind |= port_saw_EOF;
1948 static int basic_inchar(port *pt) {
1949 if(pt->kind & port_file) {
1950 return fgetc(pt->rep.stdio.file);
1952 if(*pt->rep.string.curr == 0 ||
1953 pt->rep.string.curr == pt->rep.string.past_the_end) {
1956 return *pt->rep.string.curr++;
1961 /* back character to input buffer */
1962 static void backchar(scheme *sc, int c) {
1965 pt=sc->inport->_object._port;
1966 if(pt->kind&port_file) {
1967 ungetc(c,pt->rep.stdio.file);
1969 if(pt->rep.string.curr!=pt->rep.string.start) {
1970 --pt->rep.string.curr;
1975 static int realloc_port_string(scheme *sc, port *p)
1977 char *start=p->rep.string.start;
1978 size_t old_size = p->rep.string.past_the_end - start;
1979 size_t new_size=p->rep.string.past_the_end-start+1+BLOCK_SIZE;
1980 char *str=sc->malloc(new_size);
1982 memset(str,' ',new_size-1);
1983 str[new_size-1]='\0';
1984 memcpy(str, start, old_size);
1985 p->rep.string.start=str;
1986 p->rep.string.past_the_end=str+new_size-1;
1987 p->rep.string.curr-=start-str;
1995 INTERFACE void putstr(scheme *sc, const char *s) {
1996 port *pt=sc->outport->_object._port;
1997 if(pt->kind&port_file) {
1998 fputs(s,pt->rep.stdio.file);
2001 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
2002 *pt->rep.string.curr++=*s;
2003 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
2004 *pt->rep.string.curr++=*s;
2010 static void putchars(scheme *sc, const char *s, int len) {
2011 port *pt=sc->outport->_object._port;
2012 if(pt->kind&port_file) {
2013 fwrite(s,1,len,pt->rep.stdio.file);
2016 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
2017 *pt->rep.string.curr++=*s++;
2018 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
2019 *pt->rep.string.curr++=*s++;
2025 INTERFACE void putcharacter(scheme *sc, int c) {
2026 port *pt=sc->outport->_object._port;
2027 if(pt->kind&port_file) {
2028 fputc(c,pt->rep.stdio.file);
2030 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
2031 *pt->rep.string.curr++=c;
2032 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
2033 *pt->rep.string.curr++=c;
2038 /* read characters up to delimiter, but cater to character constants */
2039 static char *readstr_upto(scheme *sc, char *delim) {
2040 char *p = sc->strbuff;
2042 while ((p - sc->strbuff < sc->strbuff_size) &&
2043 !is_one_of(delim, (*p++ = inchar(sc))));
2045 if(p == sc->strbuff+2 && p[-2] == '\\') {
2054 /* read string expression "xxx...xxx" */
2055 static pointer readstrexp(scheme *sc) {
2056 char *p = sc->strbuff;
2059 enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state=st_ok;
2066 if(p-sc->strbuff > (sc->strbuff_size)-1) {
2067 ptrdiff_t offset = p - sc->strbuff;
2068 if (expand_strbuff(sc) != 0) {
2071 p = sc->strbuff + offset;
2081 return mk_counted_string(sc,sc->strbuff,p-sc->strbuff);
2130 if(c>='0' && c<='F') {
2134 c1=(c1<<4)+c-'A'+10;
2148 if (c < '0' || c > '7')
2156 if (state==st_oct2 && c1 >= 32)
2161 if (state == st_oct1)
2175 /* check c is in chars */
2176 static INLINE int is_one_of(char *s, int c) {
2177 if(c==EOF) return 1;
2184 /* skip white characters */
2185 static INLINE int skipspace(scheme *sc) {
2186 int c = 0, curr_line = 0;
2194 } while (isspace(c));
2197 port_increment_current_line(sc, &sc->load_stack[sc->file_i], curr_line);
2208 static int token(scheme *sc) {
2211 if(c == EOF) { return (TOK_EOF); }
2212 switch (c=inchar(sc)) {
2216 return (TOK_LPAREN);
2218 return (TOK_RPAREN);
2221 if(is_one_of(" \n\t",c)) {
2231 while ((c=inchar(sc)) != '\n' && c!=EOF)
2235 port_increment_current_line(sc, &sc->load_stack[sc->file_i], 1);
2238 { return (TOK_EOF); }
2240 { return (token(sc));}
2242 return (TOK_DQUOTE);
2244 return (TOK_BQUOTE);
2246 if ((c=inchar(sc)) == '@') {
2247 return (TOK_ATMARK);
2256 } else if(c == '!') {
2257 while ((c=inchar(sc)) != '\n' && c!=EOF)
2261 port_increment_current_line(sc, &sc->load_stack[sc->file_i], 1);
2264 { return (TOK_EOF); }
2266 { return (token(sc));}
2269 if(is_one_of(" tfodxb\\",c)) {
2270 return TOK_SHARP_CONST;
2281 /* ========== Routines for Printing ========== */
2282 #define ok_abbrev(x) (is_pair(x) && cdr(x) == sc->NIL)
2284 static void printslashstring(scheme *sc, char *p, int len) {
2286 unsigned char *s=(unsigned char*)p;
2287 putcharacter(sc,'"');
2288 for ( i=0; i<len; i++) {
2289 if(*s==0xff || *s=='"' || *s<' ' || *s=='\\') {
2290 putcharacter(sc,'\\');
2293 putcharacter(sc,'"');
2296 putcharacter(sc,'n');
2299 putcharacter(sc,'t');
2302 putcharacter(sc,'r');
2305 putcharacter(sc,'\\');
2309 putcharacter(sc,'x');
2311 putcharacter(sc,d+'0');
2313 putcharacter(sc,d-10+'A');
2317 putcharacter(sc,d+'0');
2319 putcharacter(sc,d-10+'A');
2324 putcharacter(sc,*s);
2328 putcharacter(sc,'"');
2333 static void printatom(scheme *sc, pointer l, int f) {
2336 atom2str(sc,l,f,&p,&len);
2341 /* Uses internal buffer unless string pointer is already available */
2342 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen) {
2347 } else if (l == sc->T) {
2349 } else if (l == sc->F) {
2351 } else if (l == sc->EOF_OBJ) {
2353 } else if (is_port(l)) {
2355 } else if (is_number(l)) {
2357 if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */ {
2358 if(num_is_integer(l)) {
2359 snprintf(p, STRBUFFSIZE, "%ld", ivalue_unchecked(l));
2361 snprintf(p, STRBUFFSIZE, "%.10g", rvalue_unchecked(l));
2362 /* r5rs says there must be a '.' (unless 'e'?) */
2363 f = strcspn(p, ".e");
2365 p[f] = '.'; /* not found, so add '.0' at the end */
2374 snprintf(p, STRBUFFSIZE, "%lx", v);
2376 snprintf(p, STRBUFFSIZE, "-%lx", -v);
2377 } else if (f == 8) {
2379 snprintf(p, STRBUFFSIZE, "%lo", v);
2381 snprintf(p, STRBUFFSIZE, "-%lo", -v);
2382 } else if (f == 2) {
2383 unsigned long b = (v < 0) ? -v : v;
2384 p = &p[STRBUFFSIZE-1];
2386 do { *--p = (b&1) ? '1' : '0'; b >>= 1; } while (b != 0);
2387 if (v < 0) *--p = '-';
2390 } else if (is_string(l)) {
2393 *plen = strlength(l);
2395 } else { /* Hack, uses the fact that printing is needed */
2398 printslashstring(sc, strvalue(l), strlength(l));
2401 } else if (is_character(l)) {
2427 snprintf(p,STRBUFFSIZE, "#\\%s",charnames[c]);
2432 snprintf(p,STRBUFFSIZE,"#\\x%x",c);
2436 snprintf(p,STRBUFFSIZE,"#\\%c",c);
2440 } else if (is_symbol(l)) {
2442 } else if (is_proc(l)) {
2444 snprintf(p,STRBUFFSIZE,"#<%s PROCEDURE %ld>", procname(l),procnum(l));
2445 } else if (is_macro(l)) {
2447 } else if (is_closure(l)) {
2449 } else if (is_promise(l)) {
2451 } else if (is_foreign(l)) {
2453 snprintf(p,STRBUFFSIZE,"#<FOREIGN PROCEDURE %ld>", procnum(l));
2454 } else if (is_continuation(l)) {
2455 p = "#<CONTINUATION>";
2456 } else if (is_foreign_object(l)) {
2458 l->_object._foreign_object._vtable->to_string(sc, p, STRBUFFSIZE, l->_object._foreign_object._data);
2465 /* ========== Routines for Evaluation Cycle ========== */
2467 /* make closure. c is code. e is environment */
2468 static pointer mk_closure(scheme *sc, pointer c, pointer e) {
2469 pointer x = get_cell(sc, c, e);
2471 typeflag(x) = T_CLOSURE;
2477 /* make continuation. */
2478 static pointer mk_continuation(scheme *sc, pointer d) {
2479 pointer x = get_cell(sc, sc->NIL, d);
2481 typeflag(x) = T_CONTINUATION;
2486 static pointer list_star(scheme *sc, pointer d) {
2488 if(cdr(d)==sc->NIL) {
2491 p=cons(sc,car(d),cdr(d));
2493 while(cdr(cdr(p))!=sc->NIL) {
2494 d=cons(sc,car(p),cdr(p));
2495 if(cdr(cdr(p))!=sc->NIL) {
2503 /* reverse list -- produce new list */
2504 static pointer reverse(scheme *sc, pointer term, pointer list) {
2505 /* a must be checked by gc */
2506 pointer a = list, p = term;
2508 for ( ; is_pair(a); a = cdr(a)) {
2509 p = cons(sc, car(a), p);
2514 /* reverse list --- in-place */
2515 static pointer reverse_in_place(scheme *sc, pointer term, pointer list) {
2516 pointer p = list, result = term, q;
2518 while (p != sc->NIL) {
2527 /* append list -- produce new list (in reverse order) */
2528 static pointer revappend(scheme *sc, pointer a, pointer b) {
2532 while (is_pair(p)) {
2533 result = cons(sc, car(p), result);
2541 return sc->F; /* signal an error */
2544 /* equivalence of atoms */
2545 int eqv(pointer a, pointer b) {
2548 return (strvalue(a) == strvalue(b));
2551 } else if (is_number(a)) {
2553 if (num_is_integer(a) == num_is_integer(b))
2554 return num_eq(nvalue(a),nvalue(b));
2557 } else if (is_character(a)) {
2558 if (is_character(b))
2559 return charvalue(a)==charvalue(b);
2562 } else if (is_port(a)) {
2567 } else if (is_proc(a)) {
2569 return procnum(a)==procnum(b);
2577 /* true or false value macro */
2578 /* () is #t in R5RS */
2579 #define is_true(p) ((p) != sc->F)
2580 #define is_false(p) ((p) == sc->F)
2582 /* ========== Environment implementation ========== */
2584 #if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
2586 static int hash_fn(const char *key, int table_size)
2588 unsigned int hashed = 0;
2590 int bits_per_int = sizeof(unsigned int)*8;
2592 for (c = key; *c; c++) {
2593 /* letters have about 5 bits in them */
2594 hashed = (hashed<<5) | (hashed>>(bits_per_int-5));
2597 return hashed % table_size;
2601 /* Compares A and B. Returns an integer less than, equal to, or
2602 * greater than zero if A is stored at a memory location that is
2603 * numerical less than, equal to, or greater than that of B. */
2605 pointercmp(pointer a, pointer b)
2607 uintptr_t a_n = (uintptr_t) a;
2608 uintptr_t b_n = (uintptr_t) b;
2617 #ifndef USE_ALIST_ENV
2620 * In this implementation, each frame of the environment may be
2621 * a hash table: a vector of alists hashed by variable name.
2622 * In practice, we use a vector only for the initial frame;
2623 * subsequent frames are too small and transient for the lookup
2624 * speed to out-weigh the cost of making a new vector.
2627 static void new_frame_in_env(scheme *sc, pointer old_env)
2631 /* The interaction-environment has about 480 variables in it. */
2632 if (old_env == sc->NIL) {
2633 new_frame = mk_vector(sc, 751);
2635 new_frame = sc->NIL;
2639 sc->envir = immutable_cons(sc, new_frame, old_env);
2641 setenvironment(sc->envir);
2644 /* Insert (VARIABLE, VALUE) at SSLOT. SSLOT must be obtained using
2645 * find_slot_spec_in_env, and no insertion must be done between
2646 * obtaining SSLOT and the call to this function.
2648 * If SSLOT is NULL, the new slot is put into the appropriate place in
2649 * the environment vector. */
2650 static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
2651 pointer variable, pointer value,
2654 #define new_slot_spec_in_env_allocates 2
2656 gc_disable(sc, gc_reservations (new_slot_spec_in_env));
2657 slot = immutable_cons(sc, variable, value);
2659 if (sslot == NULL) {
2661 assert(is_vector(car(env)));
2662 location = hash_fn(symname(variable), vector_length(car(env)));
2664 set_vector_elem(car(env), location,
2665 immutable_cons(sc, slot, vector_elem(car(env), location)));
2667 *sslot = immutable_cons(sc, slot, *sslot);
2672 /* Find the slot in ENV under the key HDL. If ALL is given, look in
2673 * all environments enclosing ENV. If the lookup fails, and SSLOT is
2674 * given, the position where the new slot has to be inserted is stored
2677 * SSLOT may be set to NULL if the new symbol should be placed at the
2678 * appropriate place in the vector. */
2680 find_slot_spec_in_env(scheme *sc, pointer env, pointer hdl, int all, pointer **sslot)
2686 assert(is_symbol(hdl));
2688 for (x = env; x != sc->NIL; x = cdr(x)) {
2689 if (is_vector(car(x))) {
2690 location = hash_fn(symname(hdl), vector_length(car(x)));
2692 y = vector_elem(car(x), location);
2697 for ( ; y != sc->NIL; sl = &cdr(y), y = *sl) {
2698 d = pointercmp(caar(y), hdl);
2700 return car(y); /* Hit. */
2705 if (x == env && sslot)
2706 *sslot = sl; /* Insert here. */
2709 return sc->NIL; /* Miss, and stop looking. */
2712 return sc->NIL; /* Not found in any environment. */
2715 #else /* USE_ALIST_ENV */
2717 static INLINE void new_frame_in_env(scheme *sc, pointer old_env)
2719 sc->envir = immutable_cons(sc, sc->NIL, old_env);
2720 setenvironment(sc->envir);
2723 /* Insert (VARIABLE, VALUE) at SSLOT. SSLOT must be obtained using
2724 * find_slot_spec_in_env, and no insertion must be done between
2725 * obtaining SSLOT and the call to this function. */
2726 static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
2727 pointer variable, pointer value,
2730 #define new_slot_spec_in_env_allocates 2
2732 assert(is_symbol(variable));
2733 *sslot = immutable_cons(sc, immutable_cons(sc, variable, value), *sslot);
2736 /* Find the slot in ENV under the key HDL. If ALL is given, look in
2737 * all environments enclosing ENV. If the lookup fails, and SSLOT is
2738 * given, the position where the new slot has to be inserted is stored
2741 find_slot_spec_in_env(scheme *sc, pointer env, pointer hdl, int all, pointer **sslot)
2746 assert(is_symbol(hdl));
2748 for (x = env; x != sc->NIL; x = cdr(x)) {
2749 for (sl = &car(x), y = *sl; y != sc->NIL; sl = &cdr(y), y = *sl) {
2750 d = pointercmp(caar(y), hdl);
2752 return car(y); /* Hit. */
2757 if (x == env && sslot)
2758 *sslot = sl; /* Insert here. */
2761 return sc->NIL; /* Miss, and stop looking. */
2764 return sc->NIL; /* Not found in any environment. */
2767 #endif /* USE_ALIST_ENV else */
2769 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
2771 return find_slot_spec_in_env(sc, env, hdl, all, NULL);
2774 static INLINE void new_slot_in_env(scheme *sc, pointer variable, pointer value)
2776 #define new_slot_in_env_allocates new_slot_spec_in_env_allocates
2779 assert(is_symbol(variable));
2780 slot = find_slot_spec_in_env(sc, sc->envir, variable, 0, &sslot);
2781 assert(slot == sc->NIL);
2782 new_slot_spec_in_env(sc, sc->envir, variable, value, sslot);
2785 static INLINE void set_slot_in_env(scheme *sc, pointer slot, pointer value)
2791 static INLINE pointer slot_value_in_env(pointer slot)
2796 /* ========== Evaluation Cycle ========== */
2799 static pointer _Error_1(scheme *sc, const char *s, pointer a) {
2800 const char *str = s;
2804 pointer hdl=sc->ERROR_HOOK;
2808 char sbuf[STRBUFFSIZE];
2811 history = history_flatten(sc);
2814 /* make sure error is not in REPL */
2815 if (((sc->load_stack[sc->file_i].kind & port_file) == 0
2816 || sc->load_stack[sc->file_i].rep.stdio.file != stdin)) {
2821 if (history != sc->NIL && has_tag(car(history))
2822 && (tag = get_tag(sc, car(history)))
2823 && is_string(car(tag)) && is_integer(cdr(tag))) {
2824 fname = string_value(car(tag));
2825 ln = ivalue_unchecked(cdr(tag));
2827 fname = string_value(sc->load_stack[sc->file_i].filename);
2828 ln = ivalue_unchecked(sc->load_stack[sc->file_i].curr_line);
2831 /* should never happen */
2832 if(!fname) fname = "<unknown>";
2834 /* we started from 0 */
2836 snprintf(sbuf, STRBUFFSIZE, "%s:%i: %s", fname, ln, s);
2838 str = (const char*)sbuf;
2843 x=find_slot_in_env(sc,sc->envir,hdl,1);
2845 sc->code = cons(sc, cons(sc, sc->QUOTE,
2846 cons(sc, history, sc->NIL)),
2849 sc->code = cons(sc, cons(sc, sc->QUOTE, cons(sc, a, sc->NIL)),
2852 sc->code = cons(sc, sc->F, sc->code);
2854 sc->code = cons(sc, mk_string(sc, str), sc->code);
2855 setimmutable(car(sc->code));
2856 sc->code = cons(sc, slot_value_in_env(x), sc->code);
2857 sc->op = (int)OP_EVAL;
2863 sc->args = cons(sc, (a), sc->NIL);
2867 sc->args = cons(sc, mk_string(sc, str), sc->args);
2868 setimmutable(car(sc->args));
2869 sc->op = (int)OP_ERR0;
2872 #define Error_1(sc,s, a) return _Error_1(sc,s,a)
2873 #define Error_0(sc,s) return _Error_1(sc,s,0)
2875 /* Too small to turn into function */
2877 # define END } while (0)
2881 /* Flags. The interpreter has a flags field. When the interpreter
2882 * pushes a frame to the dump stack, it is encoded with the opcode.
2883 * Therefore, we do not use the least significant byte. */
2885 /* Masks used to encode and decode opcode and flags. */
2886 #define S_OP_MASK 0x000000ff
2887 #define S_FLAG_MASK 0xffffff00
2889 /* Set if the interpreter evaluates an expression in a tail context
2890 * (see R5RS, section 3.5). If a function, procedure, or continuation
2891 * is invoked while this flag is set, the call is recorded as tail
2892 * call in the history buffer. */
2893 #define S_FLAG_TAIL_CONTEXT 0x00000100
2896 #define s_set_flag(sc, f) \
2898 (sc)->flags |= S_FLAG_ ## f; \
2902 #define s_clear_flag(sc, f) \
2904 (sc)->flags &= ~ S_FLAG_ ## f; \
2907 /* Check if flag F is set. */
2908 #define s_get_flag(sc, f) \
2909 !!((sc)->flags & S_FLAG_ ## f)
2913 /* Bounce back to Eval_Cycle and execute A. */
2914 #define s_goto(sc,a) BEGIN \
2915 sc->op = (int)(a); \
2918 #if USE_THREADED_CODE
2920 /* Do not bounce back to Eval_Cycle but execute A by jumping directly
2921 * to it. Only applicable if A is part of the same dispatch
2923 #define s_thread_to(sc, a) \
2929 /* Define a label OP and emit a case statement for OP. For use in the
2930 * dispatch functions. The slightly peculiar goto that is never
2931 * executed avoids warnings about unused labels. */
2932 #define CASE(OP) if (0) goto OP; OP: case OP
2934 #else /* USE_THREADED_CODE */
2935 #define s_thread_to(sc, a) s_goto(sc, a)
2936 #define CASE(OP) case OP
2937 #endif /* USE_THREADED_CODE */
2939 /* Return to the previous frame on the dump stack, setting the current
2941 #define s_return(sc, a) return _s_return(sc, a, 0)
2943 /* Return to the previous frame on the dump stack, setting the current
2944 * value to A, and re-enable the garbage collector. */
2945 #define s_return_enable_gc(sc, a) return _s_return(sc, a, 1)
2947 static INLINE void dump_stack_reset(scheme *sc)
2952 static INLINE void dump_stack_initialize(scheme *sc)
2954 dump_stack_reset(sc);
2957 static void dump_stack_free(scheme *sc)
2962 static pointer _s_return(scheme *sc, pointer a, int enable_gc) {
2963 pointer dump = sc->dump;
2969 if (dump == sc->NIL)
2971 free_cons(sc, dump, &op, &dump);
2972 v = (unsigned long) ivalue_unchecked(op);
2973 sc->op = (int) (v & S_OP_MASK);
2974 sc->flags = v & S_FLAG_MASK;
2975 #ifdef USE_SMALL_INTEGERS
2976 if (v < MAX_SMALL_INTEGER) {
2977 /* This is a small integer, we must not free it. */
2979 /* Normal integer. Recover the cell. */
2982 free_cons(sc, dump, &sc->args, &dump);
2983 free_cons(sc, dump, &sc->envir, &dump);
2984 free_cons(sc, dump, &sc->code, &sc->dump);
2988 static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) {
2989 #define s_save_allocates 5
2991 unsigned long v = sc->flags | ((unsigned long) op);
2992 gc_disable(sc, gc_reservations (s_save));
2993 dump = cons(sc, sc->envir, cons(sc, (code), sc->dump));
2994 dump = cons(sc, (args), dump);
2995 sc->dump = cons(sc, mk_integer(sc, (long) v), dump);
2999 static INLINE void dump_stack_mark(scheme *sc)
3009 history_free(scheme *sc)
3011 sc->free(sc->history.m);
3012 sc->history.tailstacks = sc->NIL;
3013 sc->history.callstack = sc->NIL;
3017 history_init(scheme *sc, size_t N, size_t M)
3020 struct history *h = &sc->history;
3025 assert ((N & h->mask_N) == 0);
3029 assert ((M & h->mask_M) == 0);
3031 h->callstack = mk_vector(sc, N);
3032 if (h->callstack == sc->sink)
3035 h->tailstacks = mk_vector(sc, N);
3036 for (i = 0; i < N; i++) {
3037 pointer tailstack = mk_vector(sc, M);
3038 if (tailstack == sc->sink)
3040 set_vector_elem(h->tailstacks, i, tailstack);
3043 h->m = sc->malloc(N * sizeof *h->m);
3047 for (i = 0; i < N; i++)
3058 history_mark(scheme *sc)
3060 struct history *h = &sc->history;
3062 mark(h->tailstacks);
3065 #define add_mod(a, b, mask) (((a) + (b)) & (mask))
3066 #define sub_mod(a, b, mask) add_mod(a, (mask) + 1 - (b), mask)
3069 tailstack_clear(scheme *sc, pointer v)
3071 assert(is_vector(v));
3073 fill_vector(v, sc->NIL);
3077 callstack_pop(scheme *sc)
3079 struct history *h = &sc->history;
3083 if (h->callstack == sc->NIL)
3086 item = vector_elem(h->callstack, n);
3087 /* Clear our frame so that it can be gc'ed and we don't run into it
3088 * when walking the history. */
3089 set_vector_elem(h->callstack, n, sc->NIL);
3090 tailstack_clear(sc, vector_elem(h->tailstacks, n));
3092 /* Exit from the frame. */
3093 h->n = sub_mod(h->n, 1, h->mask_N);
3099 callstack_push(scheme *sc, pointer item)
3101 struct history *h = &sc->history;
3104 if (h->callstack == sc->NIL)
3107 /* Enter a new frame. */
3108 n = h->n = add_mod(n, 1, h->mask_N);
3110 /* Initialize tail stack. */
3111 tailstack_clear(sc, vector_elem(h->tailstacks, n));
3112 h->m[n] = h->mask_M;
3114 set_vector_elem(h->callstack, n, item);
3118 tailstack_push(scheme *sc, pointer item)
3120 struct history *h = &sc->history;
3124 if (h->callstack == sc->NIL)
3127 /* Enter a new tail frame. */
3128 m = h->m[n] = add_mod(m, 1, h->mask_M);
3129 set_vector_elem(vector_elem(h->tailstacks, n), m, item);
3133 tailstack_flatten(scheme *sc, pointer tailstack, size_t i, size_t n,
3136 struct history *h = &sc->history;
3142 if (acc == sc->sink)
3146 /* We reached the end, but we did not see a unused frame. Signal
3147 this using '... . */
3148 return cons(sc, mk_symbol(sc, "..."), acc);
3151 frame = vector_elem(tailstack, n);
3152 if (frame == sc->NIL) {
3153 /* A unused frame. We reached the end of the history. */
3158 acc = cons(sc, frame, acc);
3160 return tailstack_flatten(sc, tailstack, i - 1, sub_mod(n, 1, h->mask_M),
3165 callstack_flatten(scheme *sc, size_t i, size_t n, pointer acc)
3167 struct history *h = &sc->history;
3173 if (acc == sc->sink)
3177 /* We reached the end, but we did not see a unused frame. Signal
3178 this using '... . */
3179 return cons(sc, mk_symbol(sc, "..."), acc);
3182 frame = vector_elem(h->callstack, n);
3183 if (frame == sc->NIL) {
3184 /* A unused frame. We reached the end of the history. */
3188 /* First, emit the tail calls. */
3189 acc = tailstack_flatten(sc, vector_elem(h->tailstacks, n), h->M, h->m[n],
3193 acc = cons(sc, frame, acc);
3195 return callstack_flatten(sc, i - 1, sub_mod(n, 1, h->mask_N), acc);
3199 history_flatten(scheme *sc)
3201 struct history *h = &sc->history;
3204 if (h->callstack == sc->NIL)
3207 history = callstack_flatten(sc, h->N, h->n, sc->NIL);
3208 if (history == sc->sink)
3211 return reverse_in_place(sc, sc->NIL, history);
3217 #else /* USE_HISTORY */
3219 #define history_init(SC, A, B) (void) 0
3220 #define history_free(SC) (void) 0
3221 #define callstack_pop(SC) (void) 0
3222 #define callstack_push(SC, X) (void) 0
3223 #define tailstack_push(SC, X) (void) 0
3225 #endif /* USE_HISTORY */
3229 #define s_retbool(tf) s_return(sc,(tf) ? sc->T : sc->F)
3231 static pointer opexe_0(scheme *sc, enum scheme_opcodes op) {
3236 CASE(OP_LOAD): /* load */
3237 if(file_interactive(sc)) {
3238 fprintf(sc->outport->_object._port->rep.stdio.file,
3239 "Loading %s\n", strvalue(car(sc->args)));
3241 if (!file_push(sc, car(sc->args))) {
3242 Error_1(sc,"unable to open", car(sc->args));
3246 sc->args = mk_integer(sc,sc->file_i);
3247 s_thread_to(sc,OP_T0LVL);
3250 CASE(OP_T0LVL): /* top level */
3251 /* If we reached the end of file, this loop is done. */
3252 if(sc->loadport->_object._port->kind & port_saw_EOF)
3257 sc->nesting = sc->nesting_stack[0];
3263 s_return(sc,sc->value);
3268 /* If interactive, be nice to user. */
3269 if(file_interactive(sc))
3271 sc->envir = sc->global_env;
3272 dump_stack_reset(sc);
3277 /* Set up another iteration of REPL */
3279 sc->save_inport=sc->inport;
3280 sc->inport = sc->loadport;
3281 s_save(sc,OP_T0LVL, sc->NIL, sc->NIL);
3282 s_save(sc,OP_VALUEPRINT, sc->NIL, sc->NIL);
3283 s_save(sc,OP_T1LVL, sc->NIL, sc->NIL);
3284 s_thread_to(sc,OP_READ_INTERNAL);
3286 CASE(OP_T1LVL): /* top level */
3287 sc->code = sc->value;
3288 sc->inport=sc->save_inport;
3289 s_thread_to(sc,OP_EVAL);
3291 CASE(OP_READ_INTERNAL): /* internal read */
3292 sc->tok = token(sc);
3293 if(sc->tok==TOK_EOF)
3294 { s_return(sc,sc->EOF_OBJ); }
3295 s_goto(sc,OP_RDSEXPR);
3298 s_return(sc, gensym(sc));
3300 CASE(OP_VALUEPRINT): /* print evaluation result */
3301 /* OP_VALUEPRINT is always pushed, because when changing from
3302 non-interactive to interactive mode, it needs to be
3303 already on the stack */
3305 putstr(sc,"\nGives: ");
3307 if(file_interactive(sc)) {
3309 sc->args = sc->value;
3310 s_goto(sc,OP_P0LIST);
3312 s_return(sc,sc->value);
3315 CASE(OP_EVAL): /* main part of evaluation */
3318 /*s_save(sc,OP_VALUEPRINT,sc->NIL,sc->NIL);*/
3319 s_save(sc,OP_REAL_EVAL,sc->args,sc->code);
3321 putstr(sc,"\nEval: ");
3322 s_goto(sc,OP_P0LIST);
3327 if (is_symbol(sc->code)) { /* symbol */
3328 x=find_slot_in_env(sc,sc->envir,sc->code,1);
3330 s_return(sc,slot_value_in_env(x));
3332 Error_1(sc,"eval: unbound variable:", sc->code);
3334 } else if (is_pair(sc->code)) {
3335 if (is_syntax(x = car(sc->code))) { /* SYNTAX */
3336 sc->code = cdr(sc->code);
3337 s_goto(sc,syntaxnum(x));
3338 } else {/* first, eval top element and eval arguments */
3339 s_save(sc,OP_E0ARGS, sc->NIL, sc->code);
3340 /* If no macros => s_save(sc,OP_E1ARGS, sc->NIL, cdr(sc->code));*/
3341 sc->code = car(sc->code);
3342 s_clear_flag(sc, TAIL_CONTEXT);
3343 s_thread_to(sc,OP_EVAL);
3346 s_return(sc,sc->code);
3349 CASE(OP_E0ARGS): /* eval arguments */
3350 if (is_macro(sc->value)) { /* macro expansion */
3351 gc_disable(sc, 1 + gc_reservations (s_save));
3352 s_save(sc,OP_DOMACRO, sc->NIL, sc->NIL);
3353 sc->args = cons(sc,sc->code, sc->NIL);
3355 sc->code = sc->value;
3356 s_clear_flag(sc, TAIL_CONTEXT);
3357 s_thread_to(sc,OP_APPLY);
3360 sc->args = cons(sc, sc->code, sc->NIL);
3362 sc->code = cdr(sc->code);
3363 s_thread_to(sc,OP_E1ARGS);
3366 CASE(OP_E1ARGS): /* eval arguments */
3368 sc->args = cons(sc, sc->value, sc->args);
3370 if (is_pair(sc->code)) { /* continue */
3371 s_save(sc,OP_E1ARGS, sc->args, cdr(sc->code));
3372 sc->code = car(sc->code);
3374 s_clear_flag(sc, TAIL_CONTEXT);
3375 s_thread_to(sc,OP_EVAL);
3377 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3378 s_thread_to(sc,OP_APPLY_CODE);
3384 sc->tracing=ivalue(car(sc->args));
3386 s_return_enable_gc(sc, mk_integer(sc, tr));
3391 CASE(OP_CALLSTACK_POP): /* pop the call stack */
3393 s_return(sc, sc->value);
3396 CASE(OP_APPLY_CODE): /* apply 'cadr(args)' to 'cddr(args)',
3397 * record in the history as invoked from
3399 free_cons(sc, sc->args, &callsite, &sc->args);
3400 sc->code = car(sc->args);
3401 sc->args = cdr(sc->args);
3404 CASE(OP_APPLY): /* apply 'code' to 'args' */
3407 s_save(sc,OP_REAL_APPLY,sc->args,sc->code);
3409 /* sc->args=cons(sc,sc->code,sc->args);*/
3410 putstr(sc,"\nApply to: ");
3411 s_goto(sc,OP_P0LIST);
3414 CASE(OP_REAL_APPLY):
3417 if (op != OP_APPLY_CODE)
3418 callsite = sc->code;
3419 if (s_get_flag(sc, TAIL_CONTEXT)) {
3420 /* We are evaluating a tail call. */
3421 tailstack_push(sc, callsite);
3423 callstack_push(sc, callsite);
3424 s_save(sc, OP_CALLSTACK_POP, sc->NIL, sc->NIL);
3428 if (is_proc(sc->code)) {
3429 s_goto(sc,procnum(sc->code)); /* PROCEDURE */
3430 } else if (is_foreign(sc->code))
3432 /* Keep nested calls from GC'ing the arglist */
3433 push_recent_alloc(sc,sc->args,sc->NIL);
3434 x=sc->code->_object._ff(sc,sc->args);
3436 } else if (is_closure(sc->code) || is_macro(sc->code)
3437 || is_promise(sc->code)) { /* CLOSURE */
3438 /* Should not accept promise */
3439 /* make environment */
3440 new_frame_in_env(sc, closure_env(sc->code));
3441 for (x = car(closure_code(sc->code)), y = sc->args;
3442 is_pair(x); x = cdr(x), y = cdr(y)) {
3444 Error_1(sc, "not enough arguments, missing:", x);
3446 new_slot_in_env(sc, car(x), car(y));
3451 Error_0(sc, "too many arguments");
3453 } else if (is_symbol(x))
3454 new_slot_in_env(sc, x, y);
3456 Error_1(sc,"syntax error in closure: not a symbol:", x);
3458 sc->code = cdr(closure_code(sc->code));
3460 s_set_flag(sc, TAIL_CONTEXT);
3461 s_thread_to(sc,OP_BEGIN);
3462 } else if (is_continuation(sc->code)) { /* CONTINUATION */
3463 sc->dump = cont_dump(sc->code);
3464 s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL);
3466 Error_1(sc,"illegal function",sc->code);
3469 CASE(OP_DOMACRO): /* do macro */
3470 sc->code = sc->value;
3471 s_thread_to(sc,OP_EVAL);
3473 #if USE_COMPILE_HOOK
3474 CASE(OP_LAMBDA): /* lambda */
3475 /* If the hook is defined, apply it to sc->code, otherwise
3476 set sc->value fall through */
3478 pointer f=find_slot_in_env(sc,sc->envir,sc->COMPILE_HOOK,1);
3480 sc->value = sc->code;
3483 gc_disable(sc, 1 + gc_reservations (s_save));
3484 s_save(sc,OP_LAMBDA1,sc->args,sc->code);
3485 sc->args=cons(sc,sc->code,sc->NIL);
3487 sc->code=slot_value_in_env(f);
3488 s_thread_to(sc,OP_APPLY);
3493 CASE(OP_LAMBDA): /* lambda */
3494 sc->value = sc->code;
3500 s_return_enable_gc(sc, mk_closure(sc, sc->value, sc->envir));
3503 CASE(OP_MKCLOSURE): /* make-closure */
3505 if(car(x)==sc->LAMBDA) {
3508 if(cdr(sc->args)==sc->NIL) {
3514 s_return_enable_gc(sc, mk_closure(sc, x, y));
3516 CASE(OP_QUOTE): /* quote */
3517 s_return(sc,car(sc->code));
3519 CASE(OP_DEF0): /* define */
3520 if(is_immutable(car(sc->code)))
3521 Error_1(sc,"define: unable to alter immutable", car(sc->code));
3523 if (is_pair(car(sc->code))) {
3526 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
3530 sc->code = cadr(sc->code);
3532 if (!is_symbol(x)) {
3533 Error_0(sc,"variable is not a symbol");
3535 s_save(sc,OP_DEF1, sc->NIL, x);
3536 s_thread_to(sc,OP_EVAL);
3538 CASE(OP_DEF1): { /* define */
3540 x = find_slot_spec_in_env(sc, sc->envir, sc->code, 0, &sslot);
3542 set_slot_in_env(sc, x, sc->value);
3544 new_slot_spec_in_env(sc, sc->envir, sc->code, sc->value, sslot);
3546 s_return(sc,sc->code);
3549 CASE(OP_DEFP): /* defined? */
3551 if(cdr(sc->args)!=sc->NIL) {
3554 s_retbool(find_slot_in_env(sc,x,car(sc->args),1)!=sc->NIL);
3556 CASE(OP_SET0): /* set! */
3557 if(is_immutable(car(sc->code)))
3558 Error_1(sc,"set!: unable to alter immutable variable",car(sc->code));
3559 s_save(sc,OP_SET1, sc->NIL, car(sc->code));
3560 sc->code = cadr(sc->code);
3561 s_thread_to(sc,OP_EVAL);
3563 CASE(OP_SET1): /* set! */
3564 y=find_slot_in_env(sc,sc->envir,sc->code,1);
3566 set_slot_in_env(sc, y, sc->value);
3567 s_return(sc,sc->value);
3569 Error_1(sc,"set!: unbound variable:", sc->code);
3573 CASE(OP_BEGIN): /* begin */
3577 if (!is_pair(sc->code)) {
3578 s_return(sc,sc->code);
3581 last = cdr(sc->code) == sc->NIL;
3583 s_save(sc,OP_BEGIN, sc->NIL, cdr(sc->code));
3585 sc->code = car(sc->code);
3587 /* This is not the end of the list. This is not a tail
3589 s_clear_flag(sc, TAIL_CONTEXT);
3590 s_thread_to(sc,OP_EVAL);
3593 CASE(OP_IF0): /* if */
3594 s_save(sc,OP_IF1, sc->NIL, cdr(sc->code));
3595 sc->code = car(sc->code);
3596 s_clear_flag(sc, TAIL_CONTEXT);
3597 s_thread_to(sc,OP_EVAL);
3599 CASE(OP_IF1): /* if */
3600 if (is_true(sc->value))
3601 sc->code = car(sc->code);
3603 sc->code = cadr(sc->code); /* (if #f 1) ==> () because
3604 * car(sc->NIL) = sc->NIL */
3605 s_thread_to(sc,OP_EVAL);
3607 CASE(OP_LET0): /* let */
3609 sc->value = sc->code;
3610 sc->code = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code);
3611 s_thread_to(sc,OP_LET1);
3613 CASE(OP_LET1): /* let (calculate parameters) */
3614 gc_disable(sc, 1 + (is_pair(sc->code) ? gc_reservations (s_save) : 0));
3615 sc->args = cons(sc, sc->value, sc->args);
3616 if (is_pair(sc->code)) { /* continue */
3617 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
3619 Error_1(sc, "Bad syntax of binding spec in let :",
3622 s_save(sc,OP_LET1, sc->args, cdr(sc->code));
3624 sc->code = cadar(sc->code);
3626 s_clear_flag(sc, TAIL_CONTEXT);
3627 s_thread_to(sc,OP_EVAL);
3630 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3631 sc->code = car(sc->args);
3632 sc->args = cdr(sc->args);
3633 s_thread_to(sc,OP_LET2);
3636 CASE(OP_LET2): /* let */
3637 new_frame_in_env(sc, sc->envir);
3638 for (x = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code), y = sc->args;
3639 y != sc->NIL; x = cdr(x), y = cdr(y)) {
3640 new_slot_in_env(sc, caar(x), car(y));
3642 if (is_symbol(car(sc->code))) { /* named let */
3643 for (x = cadr(sc->code), sc->args = sc->NIL; x != sc->NIL; x = cdr(x)) {
3645 Error_1(sc, "Bad syntax of binding in let :", x);
3646 if (!is_list(sc, car(x)))
3647 Error_1(sc, "Bad syntax of binding in let :", car(x));
3649 sc->args = cons(sc, caar(x), sc->args);
3652 gc_disable(sc, 2 + gc_reservations (new_slot_in_env));
3653 x = mk_closure(sc, cons(sc, reverse_in_place(sc, sc->NIL, sc->args), cddr(sc->code)), sc->envir);
3654 new_slot_in_env(sc, car(sc->code), x);
3656 sc->code = cddr(sc->code);
3659 sc->code = cdr(sc->code);
3662 s_thread_to(sc,OP_BEGIN);
3664 CASE(OP_LET0AST): /* let* */
3665 if (car(sc->code) == sc->NIL) {
3666 new_frame_in_env(sc, sc->envir);
3667 sc->code = cdr(sc->code);
3668 s_thread_to(sc,OP_BEGIN);
3670 if(!is_pair(car(sc->code)) || !is_pair(caar(sc->code)) || !is_pair(cdaar(sc->code))) {
3671 Error_1(sc,"Bad syntax of binding spec in let* :",car(sc->code));
3673 s_save(sc,OP_LET1AST, cdr(sc->code), car(sc->code));
3674 sc->code = cadaar(sc->code);
3675 s_clear_flag(sc, TAIL_CONTEXT);
3676 s_thread_to(sc,OP_EVAL);
3678 CASE(OP_LET1AST): /* let* (make new frame) */
3679 new_frame_in_env(sc, sc->envir);
3680 s_thread_to(sc,OP_LET2AST);
3682 CASE(OP_LET2AST): /* let* (calculate parameters) */
3683 new_slot_in_env(sc, caar(sc->code), sc->value);
3684 sc->code = cdr(sc->code);
3685 if (is_pair(sc->code)) { /* continue */
3686 s_save(sc,OP_LET2AST, sc->args, sc->code);
3687 sc->code = cadar(sc->code);
3689 s_clear_flag(sc, TAIL_CONTEXT);
3690 s_thread_to(sc,OP_EVAL);
3692 sc->code = sc->args;
3694 s_thread_to(sc,OP_BEGIN);
3697 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3698 Error_0(sc,sc->strbuff);
3703 static pointer opexe_1(scheme *sc, enum scheme_opcodes op) {
3707 CASE(OP_LET0REC): /* letrec */
3708 new_frame_in_env(sc, sc->envir);
3710 sc->value = sc->code;
3711 sc->code = car(sc->code);
3712 s_thread_to(sc,OP_LET1REC);
3714 CASE(OP_LET1REC): /* letrec (calculate parameters) */
3716 sc->args = cons(sc, sc->value, sc->args);
3718 if (is_pair(sc->code)) { /* continue */
3719 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
3720 Error_1(sc, "Bad syntax of binding spec in letrec :",
3723 s_save(sc,OP_LET1REC, sc->args, cdr(sc->code));
3724 sc->code = cadar(sc->code);
3726 s_clear_flag(sc, TAIL_CONTEXT);
3729 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3730 sc->code = car(sc->args);
3731 sc->args = cdr(sc->args);
3732 s_thread_to(sc,OP_LET2REC);
3735 CASE(OP_LET2REC): /* letrec */
3736 for (x = car(sc->code), y = sc->args; y != sc->NIL; x = cdr(x), y = cdr(y)) {
3737 new_slot_in_env(sc, caar(x), car(y));
3739 sc->code = cdr(sc->code);
3741 s_goto(sc,OP_BEGIN);
3743 CASE(OP_COND0): /* cond */
3744 if (!is_pair(sc->code)) {
3745 Error_0(sc,"syntax error in cond");
3747 s_save(sc,OP_COND1, sc->NIL, sc->code);
3748 sc->code = caar(sc->code);
3749 s_clear_flag(sc, TAIL_CONTEXT);
3752 CASE(OP_COND1): /* cond */
3753 if (is_true(sc->value)) {
3754 if ((sc->code = cdar(sc->code)) == sc->NIL) {
3755 s_return(sc,sc->value);
3757 if(!sc->code || car(sc->code)==sc->FEED_TO) {
3758 if(!is_pair(cdr(sc->code))) {
3759 Error_0(sc,"syntax error in cond");
3762 x=cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL));
3763 sc->code=cons(sc,cadr(sc->code),cons(sc,x,sc->NIL));
3767 s_goto(sc,OP_BEGIN);
3769 if ((sc->code = cdr(sc->code)) == sc->NIL) {
3770 s_return(sc,sc->NIL);
3772 s_save(sc,OP_COND1, sc->NIL, sc->code);
3773 sc->code = caar(sc->code);
3774 s_clear_flag(sc, TAIL_CONTEXT);
3779 CASE(OP_DELAY): /* delay */
3781 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
3782 typeflag(x)=T_PROMISE;
3783 s_return_enable_gc(sc,x);
3785 CASE(OP_AND0): /* and */
3786 if (sc->code == sc->NIL) {
3789 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
3790 if (cdr(sc->code) != sc->NIL)
3791 s_clear_flag(sc, TAIL_CONTEXT);
3792 sc->code = car(sc->code);
3795 CASE(OP_AND1): /* and */
3796 if (is_false(sc->value)) {
3797 s_return(sc,sc->value);
3798 } else if (sc->code == sc->NIL) {
3799 s_return(sc,sc->value);
3801 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
3802 if (cdr(sc->code) != sc->NIL)
3803 s_clear_flag(sc, TAIL_CONTEXT);
3804 sc->code = car(sc->code);
3808 CASE(OP_OR0): /* or */
3809 if (sc->code == sc->NIL) {
3812 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
3813 if (cdr(sc->code) != sc->NIL)
3814 s_clear_flag(sc, TAIL_CONTEXT);
3815 sc->code = car(sc->code);
3818 CASE(OP_OR1): /* or */
3819 if (is_true(sc->value)) {
3820 s_return(sc,sc->value);
3821 } else if (sc->code == sc->NIL) {
3822 s_return(sc,sc->value);
3824 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
3825 if (cdr(sc->code) != sc->NIL)
3826 s_clear_flag(sc, TAIL_CONTEXT);
3827 sc->code = car(sc->code);
3831 CASE(OP_C0STREAM): /* cons-stream */
3832 s_save(sc,OP_C1STREAM, sc->NIL, cdr(sc->code));
3833 sc->code = car(sc->code);
3836 CASE(OP_C1STREAM): /* cons-stream */
3837 sc->args = sc->value; /* save sc->value to register sc->args for gc */
3839 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
3840 typeflag(x)=T_PROMISE;
3841 s_return_enable_gc(sc, cons(sc, sc->args, x));
3843 CASE(OP_MACRO0): /* macro */
3844 if (is_pair(car(sc->code))) {
3847 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
3851 sc->code = cadr(sc->code);
3853 if (!is_symbol(x)) {
3854 Error_0(sc,"variable is not a symbol");
3856 s_save(sc,OP_MACRO1, sc->NIL, x);
3859 CASE(OP_MACRO1): { /* macro */
3861 typeflag(sc->value) = T_MACRO;
3862 x = find_slot_spec_in_env(sc, sc->envir, sc->code, 0, &sslot);
3864 set_slot_in_env(sc, x, sc->value);
3866 new_slot_spec_in_env(sc, sc->envir, sc->code, sc->value, sslot);
3868 s_return(sc,sc->code);
3871 CASE(OP_CASE0): /* case */
3872 s_save(sc,OP_CASE1, sc->NIL, cdr(sc->code));
3873 sc->code = car(sc->code);
3874 s_clear_flag(sc, TAIL_CONTEXT);
3877 CASE(OP_CASE1): /* case */
3878 for (x = sc->code; x != sc->NIL; x = cdr(x)) {
3879 if (!is_pair(y = caar(x))) {
3882 for ( ; y != sc->NIL; y = cdr(y)) {
3883 if (eqv(car(y), sc->value)) {
3892 if (is_pair(caar(x))) {
3894 s_goto(sc,OP_BEGIN);
3896 s_save(sc,OP_CASE2, sc->NIL, cdar(x));
3901 s_return(sc,sc->NIL);
3904 CASE(OP_CASE2): /* case */
3905 if (is_true(sc->value)) {
3906 s_goto(sc,OP_BEGIN);
3908 s_return(sc,sc->NIL);
3911 CASE(OP_PAPPLY): /* apply */
3912 sc->code = car(sc->args);
3913 sc->args = list_star(sc,cdr(sc->args));
3914 /*sc->args = cadr(sc->args);*/
3915 s_goto(sc,OP_APPLY);
3917 CASE(OP_PEVAL): /* eval */
3918 if(cdr(sc->args)!=sc->NIL) {
3919 sc->envir=cadr(sc->args);
3921 sc->code = car(sc->args);
3924 CASE(OP_CONTINUATION): /* call-with-current-continuation */
3925 sc->code = car(sc->args);
3927 sc->args = cons(sc, mk_continuation(sc, sc->dump), sc->NIL);
3929 s_goto(sc,OP_APPLY);
3932 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3933 Error_0(sc,sc->strbuff);
3940 get_property(scheme *sc, pointer obj, pointer key)
3944 assert (is_symbol(obj));
3945 assert (is_symbol(key));
3947 for (x = symprop(obj); x != sc->NIL; x = cdr(x)) {
3959 set_property(scheme *sc, pointer obj, pointer key, pointer value)
3961 #define set_property_allocates 2
3964 assert (is_symbol(obj));
3965 assert (is_symbol(key));
3967 for (x = symprop(obj); x != sc->NIL; x = cdr(x)) {
3975 gc_disable(sc, gc_reservations(set_property));
3976 symprop(obj) = cons(sc, cons(sc, key, value), symprop(obj));
3984 static pointer opexe_2(scheme *sc, enum scheme_opcodes op) {
3993 CASE(OP_INEX2EX): /* inexact->exact */
3995 if(num_is_integer(x)) {
3997 } else if(modf(rvalue_unchecked(x),&dd)==0.0) {
3998 s_return(sc,mk_integer(sc,ivalue(x)));
4000 Error_1(sc,"inexact->exact: not integral:",x);
4005 s_return(sc, mk_real(sc, exp(rvalue(x))));
4009 s_return(sc, mk_real(sc, log(rvalue(x))));
4013 s_return(sc, mk_real(sc, sin(rvalue(x))));
4017 s_return(sc, mk_real(sc, cos(rvalue(x))));
4021 s_return(sc, mk_real(sc, tan(rvalue(x))));
4025 s_return(sc, mk_real(sc, asin(rvalue(x))));
4029 s_return(sc, mk_real(sc, acos(rvalue(x))));
4033 if(cdr(sc->args)==sc->NIL) {
4034 s_return(sc, mk_real(sc, atan(rvalue(x))));
4036 pointer y=cadr(sc->args);
4037 s_return(sc, mk_real(sc, atan2(rvalue(x),rvalue(y))));
4042 s_return(sc, mk_real(sc, sqrt(rvalue(x))));
4047 pointer y=cadr(sc->args);
4049 if (num_is_integer(x) && num_is_integer(y))
4051 /* This 'if' is an R5RS compatibility fix. */
4052 /* NOTE: Remove this 'if' fix for R6RS. */
4053 if (rvalue(x) == 0 && rvalue(y) < 0) {
4056 result = pow(rvalue(x),rvalue(y));
4058 /* Before returning integer result make sure we can. */
4059 /* If the test fails, result is too big for integer. */
4062 long result_as_long = (long)result;
4063 if (result != (double)result_as_long)
4067 s_return(sc, mk_real(sc, result));
4069 s_return(sc, mk_integer(sc, result));
4075 s_return(sc, mk_real(sc, floor(rvalue(x))));
4079 s_return(sc, mk_real(sc, ceil(rvalue(x))));
4081 CASE(OP_TRUNCATE ): {
4082 double rvalue_of_x ;
4084 rvalue_of_x = rvalue(x) ;
4085 if (rvalue_of_x > 0) {
4086 s_return(sc, mk_real(sc, floor(rvalue_of_x)));
4088 s_return(sc, mk_real(sc, ceil(rvalue_of_x)));
4094 if (num_is_integer(x))
4096 s_return(sc, mk_real(sc, round_per_R5RS(rvalue(x))));
4099 CASE(OP_ADD): /* + */
4101 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4102 v=num_add(v,nvalue(car(x)));
4105 s_return_enable_gc(sc, mk_number(sc, v));
4107 CASE(OP_MUL): /* * */
4109 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4110 v=num_mul(v,nvalue(car(x)));
4113 s_return_enable_gc(sc, mk_number(sc, v));
4115 CASE(OP_SUB): /* - */
4116 if(cdr(sc->args)==sc->NIL) {
4121 v = nvalue(car(sc->args));
4123 for (; x != sc->NIL; x = cdr(x)) {
4124 v=num_sub(v,nvalue(car(x)));
4127 s_return_enable_gc(sc, mk_number(sc, v));
4129 CASE(OP_DIV): /* / */
4130 if(cdr(sc->args)==sc->NIL) {
4135 v = nvalue(car(sc->args));
4137 for (; x != sc->NIL; x = cdr(x)) {
4138 if (!is_zero_double(rvalue(car(x))))
4139 v=num_div(v,nvalue(car(x)));
4141 Error_0(sc,"/: division by zero");
4145 s_return_enable_gc(sc, mk_number(sc, v));
4147 CASE(OP_INTDIV): /* quotient */
4148 if(cdr(sc->args)==sc->NIL) {
4153 v = nvalue(car(sc->args));
4155 for (; x != sc->NIL; x = cdr(x)) {
4156 if (ivalue(car(x)) != 0)
4157 v=num_intdiv(v,nvalue(car(x)));
4159 Error_0(sc,"quotient: division by zero");
4163 s_return_enable_gc(sc, mk_number(sc, v));
4165 CASE(OP_REM): /* remainder */
4166 v = nvalue(car(sc->args));
4167 if (ivalue(cadr(sc->args)) != 0)
4168 v=num_rem(v,nvalue(cadr(sc->args)));
4170 Error_0(sc,"remainder: division by zero");
4173 s_return_enable_gc(sc, mk_number(sc, v));
4175 CASE(OP_MOD): /* modulo */
4176 v = nvalue(car(sc->args));
4177 if (ivalue(cadr(sc->args)) != 0)
4178 v=num_mod(v,nvalue(cadr(sc->args)));
4180 Error_0(sc,"modulo: division by zero");
4183 s_return_enable_gc(sc, mk_number(sc, v));
4185 CASE(OP_CAR): /* car */
4186 s_return(sc,caar(sc->args));
4188 CASE(OP_CDR): /* cdr */
4189 s_return(sc,cdar(sc->args));
4191 CASE(OP_CONS): /* cons */
4192 cdr(sc->args) = cadr(sc->args);
4193 s_return(sc,sc->args);
4195 CASE(OP_SETCAR): /* set-car! */
4196 if(!is_immutable(car(sc->args))) {
4197 caar(sc->args) = cadr(sc->args);
4198 s_return(sc,car(sc->args));
4200 Error_0(sc,"set-car!: unable to alter immutable pair");
4203 CASE(OP_SETCDR): /* set-cdr! */
4204 if(!is_immutable(car(sc->args))) {
4205 cdar(sc->args) = cadr(sc->args);
4206 s_return(sc,car(sc->args));
4208 Error_0(sc,"set-cdr!: unable to alter immutable pair");
4211 CASE(OP_CHAR2INT): { /* char->integer */
4213 c=(char)ivalue(car(sc->args));
4215 s_return_enable_gc(sc, mk_integer(sc, (unsigned char) c));
4218 CASE(OP_INT2CHAR): { /* integer->char */
4220 c=(unsigned char)ivalue(car(sc->args));
4222 s_return_enable_gc(sc, mk_character(sc, (char) c));
4225 CASE(OP_CHARUPCASE): {
4227 c=(unsigned char)ivalue(car(sc->args));
4230 s_return_enable_gc(sc, mk_character(sc, (char) c));
4233 CASE(OP_CHARDNCASE): {
4235 c=(unsigned char)ivalue(car(sc->args));
4238 s_return_enable_gc(sc, mk_character(sc, (char) c));
4241 CASE(OP_STR2SYM): /* string->symbol */
4242 gc_disable(sc, gc_reservations (mk_symbol));
4243 s_return_enable_gc(sc, mk_symbol(sc, strvalue(car(sc->args))));
4245 CASE(OP_STR2ATOM): /* string->atom */ {
4246 char *s=strvalue(car(sc->args));
4248 if(cdr(sc->args)!=sc->NIL) {
4249 /* we know cadr(sc->args) is a natural number */
4250 /* see if it is 2, 8, 10, or 16, or error */
4251 pf = ivalue_unchecked(cadr(sc->args));
4252 if(pf == 16 || pf == 10 || pf == 8 || pf == 2) {
4260 Error_1(sc, "string->atom: bad base:", cadr(sc->args));
4261 } else if(*s=='#') /* no use of base! */ {
4262 s_return(sc, mk_sharp_const(sc, s+1));
4264 if (pf == 0 || pf == 10) {
4265 s_return(sc, mk_atom(sc, s));
4269 long iv = strtol(s,&ep,(int )pf);
4271 s_return(sc, mk_integer(sc, iv));
4274 s_return(sc, sc->F);
4280 CASE(OP_SYM2STR): /* symbol->string */
4282 x=mk_string(sc,symname(car(sc->args)));
4284 s_return_enable_gc(sc, x);
4286 CASE(OP_ATOM2STR): /* atom->string */ {
4289 if(cdr(sc->args)!=sc->NIL) {
4290 /* we know cadr(sc->args) is a natural number */
4291 /* see if it is 2, 8, 10, or 16, or error */
4292 pf = ivalue_unchecked(cadr(sc->args));
4293 if(is_number(x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2)) {
4301 Error_1(sc, "atom->string: bad base:", cadr(sc->args));
4302 } else if(is_number(x) || is_character(x) || is_string(x) || is_symbol(x)) {
4305 atom2str(sc,x,(int )pf,&p,&len);
4307 s_return_enable_gc(sc, mk_counted_string(sc, p, len));
4309 Error_1(sc, "atom->string: not an atom:", x);
4313 CASE(OP_MKSTRING): { /* make-string */
4317 len=ivalue(car(sc->args));
4319 if(cdr(sc->args)!=sc->NIL) {
4320 fill=charvalue(cadr(sc->args));
4323 s_return_enable_gc(sc, mk_empty_string(sc, len, (char) fill));
4326 CASE(OP_STRLEN): /* string-length */
4328 s_return_enable_gc(sc, mk_integer(sc, strlength(car(sc->args))));
4330 CASE(OP_STRREF): { /* string-ref */
4334 str=strvalue(car(sc->args));
4336 index=ivalue(cadr(sc->args));
4338 if(index>=strlength(car(sc->args))) {
4339 Error_1(sc,"string-ref: out of bounds:",cadr(sc->args));
4343 s_return_enable_gc(sc,
4344 mk_character(sc, ((unsigned char*) str)[index]));
4347 CASE(OP_STRSET): { /* string-set! */
4352 if(is_immutable(car(sc->args))) {
4353 Error_1(sc,"string-set!: unable to alter immutable string:",car(sc->args));
4355 str=strvalue(car(sc->args));
4357 index=ivalue(cadr(sc->args));
4358 if(index>=strlength(car(sc->args))) {
4359 Error_1(sc,"string-set!: out of bounds:",cadr(sc->args));
4362 c=charvalue(caddr(sc->args));
4365 s_return(sc,car(sc->args));
4368 CASE(OP_STRAPPEND): { /* string-append */
4369 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4374 /* compute needed length for new string */
4375 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4376 len += strlength(car(x));
4379 newstr = mk_empty_string(sc, len, ' ');
4380 /* store the contents of the argument strings into the new string */
4381 for (pos = strvalue(newstr), x = sc->args; x != sc->NIL;
4382 pos += strlength(car(x)), x = cdr(x)) {
4383 memcpy(pos, strvalue(car(x)), strlength(car(x)));
4385 s_return_enable_gc(sc, newstr);
4388 CASE(OP_SUBSTR): { /* substring */
4394 str=strvalue(car(sc->args));
4396 index0=ivalue(cadr(sc->args));
4398 if(index0>strlength(car(sc->args))) {
4399 Error_1(sc,"substring: start out of bounds:",cadr(sc->args));
4402 if(cddr(sc->args)!=sc->NIL) {
4403 index1=ivalue(caddr(sc->args));
4404 if(index1>strlength(car(sc->args)) || index1<index0) {
4405 Error_1(sc,"substring: end out of bounds:",caddr(sc->args));
4408 index1=strlength(car(sc->args));
4413 x=mk_empty_string(sc,len,' ');
4414 memcpy(strvalue(x),str+index0,len);
4417 s_return_enable_gc(sc, x);
4420 CASE(OP_VECTOR): { /* vector */
4423 int len=list_length(sc,sc->args);
4425 Error_1(sc,"vector: not a proper list:",sc->args);
4427 vec=mk_vector(sc,len);
4428 if(sc->no_memory) { s_return(sc, sc->sink); }
4429 for (x = sc->args, i = 0; is_pair(x); x = cdr(x), i++) {
4430 set_vector_elem(vec,i,car(x));
4435 CASE(OP_MKVECTOR): { /* make-vector */
4436 pointer fill=sc->NIL;
4440 len=ivalue(car(sc->args));
4442 if(cdr(sc->args)!=sc->NIL) {
4443 fill=cadr(sc->args);
4445 vec=mk_vector(sc,len);
4446 if(sc->no_memory) { s_return(sc, sc->sink); }
4448 fill_vector(vec,fill);
4453 CASE(OP_VECLEN): /* vector-length */
4455 s_return_enable_gc(sc, mk_integer(sc, vector_length(car(sc->args))));
4457 CASE(OP_VECREF): { /* vector-ref */
4460 index=ivalue(cadr(sc->args));
4462 if(index >= vector_length(car(sc->args))) {
4463 Error_1(sc,"vector-ref: out of bounds:",cadr(sc->args));
4466 s_return(sc,vector_elem(car(sc->args),index));
4469 CASE(OP_VECSET): { /* vector-set! */
4472 if(is_immutable(car(sc->args))) {
4473 Error_1(sc,"vector-set!: unable to alter immutable vector:",car(sc->args));
4476 index=ivalue(cadr(sc->args));
4477 if(index >= vector_length(car(sc->args))) {
4478 Error_1(sc,"vector-set!: out of bounds:",cadr(sc->args));
4481 set_vector_elem(car(sc->args),index,caddr(sc->args));
4482 s_return(sc,car(sc->args));
4486 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
4487 Error_0(sc,sc->strbuff);
4492 static int is_list(scheme *sc, pointer a)
4493 { return list_length(sc,a) >= 0; }
4499 dotted list: -2 minus length before dot
4501 int list_length(scheme *sc, pointer a) {
4508 if (fast == sc->NIL)
4514 if (fast == sc->NIL)
4521 /* Safe because we would have already returned if `fast'
4522 encountered a non-pair. */
4526 /* the fast pointer has looped back around and caught up
4527 with the slow pointer, hence the structure is circular,
4528 not of finite length, and therefore not a list */
4534 static pointer opexe_3(scheme *sc, enum scheme_opcodes op) {
4537 int (*comp_func)(num,num)=0;
4540 CASE(OP_NOT): /* not */
4541 s_retbool(is_false(car(sc->args)));
4542 CASE(OP_BOOLP): /* boolean? */
4543 s_retbool(car(sc->args) == sc->F || car(sc->args) == sc->T);
4544 CASE(OP_EOFOBJP): /* boolean? */
4545 s_retbool(car(sc->args) == sc->EOF_OBJ);
4546 CASE(OP_NULLP): /* null? */
4547 s_retbool(car(sc->args) == sc->NIL);
4548 CASE(OP_NUMEQ): /* = */
4549 CASE(OP_LESS): /* < */
4550 CASE(OP_GRE): /* > */
4551 CASE(OP_LEQ): /* <= */
4552 CASE(OP_GEQ): /* >= */
4554 case OP_NUMEQ: comp_func=num_eq; break;
4555 case OP_LESS: comp_func=num_lt; break;
4556 case OP_GRE: comp_func=num_gt; break;
4557 case OP_LEQ: comp_func=num_le; break;
4558 case OP_GEQ: comp_func=num_ge; break;
4559 default: assert (! "reached");
4565 for (; x != sc->NIL; x = cdr(x)) {
4566 if(!comp_func(v,nvalue(car(x)))) {
4572 CASE(OP_SYMBOLP): /* symbol? */
4573 s_retbool(is_symbol(car(sc->args)));
4574 CASE(OP_NUMBERP): /* number? */
4575 s_retbool(is_number(car(sc->args)));
4576 CASE(OP_STRINGP): /* string? */
4577 s_retbool(is_string(car(sc->args)));
4578 CASE(OP_INTEGERP): /* integer? */
4579 s_retbool(is_integer(car(sc->args)));
4580 CASE(OP_REALP): /* real? */
4581 s_retbool(is_number(car(sc->args))); /* All numbers are real */
4582 CASE(OP_CHARP): /* char? */
4583 s_retbool(is_character(car(sc->args)));
4584 #if USE_CHAR_CLASSIFIERS
4585 CASE(OP_CHARAP): /* char-alphabetic? */
4586 s_retbool(Cisalpha(ivalue(car(sc->args))));
4587 CASE(OP_CHARNP): /* char-numeric? */
4588 s_retbool(Cisdigit(ivalue(car(sc->args))));
4589 CASE(OP_CHARWP): /* char-whitespace? */
4590 s_retbool(Cisspace(ivalue(car(sc->args))));
4591 CASE(OP_CHARUP): /* char-upper-case? */
4592 s_retbool(Cisupper(ivalue(car(sc->args))));
4593 CASE(OP_CHARLP): /* char-lower-case? */
4594 s_retbool(Cislower(ivalue(car(sc->args))));
4596 CASE(OP_PORTP): /* port? */
4597 s_retbool(is_port(car(sc->args)));
4598 CASE(OP_INPORTP): /* input-port? */
4599 s_retbool(is_inport(car(sc->args)));
4600 CASE(OP_OUTPORTP): /* output-port? */
4601 s_retbool(is_outport(car(sc->args)));
4602 CASE(OP_PROCP): /* procedure? */
4604 * continuation should be procedure by the example
4605 * (call-with-current-continuation procedure?) ==> #t
4606 * in R^3 report sec. 6.9
4608 s_retbool(is_proc(car(sc->args)) || is_closure(car(sc->args))
4609 || is_continuation(car(sc->args)) || is_foreign(car(sc->args)));
4610 CASE(OP_PAIRP): /* pair? */
4611 s_retbool(is_pair(car(sc->args)));
4612 CASE(OP_LISTP): /* list? */
4613 s_retbool(list_length(sc,car(sc->args)) >= 0);
4615 CASE(OP_ENVP): /* environment? */
4616 s_retbool(is_environment(car(sc->args)));
4617 CASE(OP_VECTORP): /* vector? */
4618 s_retbool(is_vector(car(sc->args)));
4619 CASE(OP_EQ): /* eq? */
4620 s_retbool(car(sc->args) == cadr(sc->args));
4621 CASE(OP_EQV): /* eqv? */
4622 s_retbool(eqv(car(sc->args), cadr(sc->args)));
4624 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
4625 Error_0(sc,sc->strbuff);
4630 static pointer opexe_4(scheme *sc, enum scheme_opcodes op) {
4634 CASE(OP_FORCE): /* force */
4635 sc->code = car(sc->args);
4636 if (is_promise(sc->code)) {
4637 /* Should change type to closure here */
4638 s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code);
4640 s_goto(sc,OP_APPLY);
4642 s_return(sc,sc->code);
4645 CASE(OP_SAVE_FORCED): /* Save forced value replacing promise */
4646 memcpy(sc->code,sc->value,sizeof(struct cell));
4647 s_return(sc,sc->value);
4649 CASE(OP_WRITE): /* write */
4650 CASE(OP_DISPLAY): /* display */
4651 CASE(OP_WRITE_CHAR): /* write-char */
4652 if(is_pair(cdr(sc->args))) {
4653 if(cadr(sc->args)!=sc->outport) {
4654 x=cons(sc,sc->outport,sc->NIL);
4655 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
4656 sc->outport=cadr(sc->args);
4659 sc->args = car(sc->args);
4665 s_goto(sc,OP_P0LIST);
4667 CASE(OP_NEWLINE): /* newline */
4668 if(is_pair(sc->args)) {
4669 if(car(sc->args)!=sc->outport) {
4670 x=cons(sc,sc->outport,sc->NIL);
4671 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
4672 sc->outport=car(sc->args);
4678 CASE(OP_ERR0): /* error */
4680 if (!is_string(car(sc->args))) {
4681 sc->args=cons(sc,mk_string(sc," -- "),sc->args);
4682 setimmutable(car(sc->args));
4684 putstr(sc, "Error: ");
4685 putstr(sc, strvalue(car(sc->args)));
4686 sc->args = cdr(sc->args);
4687 s_thread_to(sc,OP_ERR1);
4689 CASE(OP_ERR1): /* error */
4691 if (sc->args != sc->NIL) {
4692 s_save(sc,OP_ERR1, cdr(sc->args), sc->NIL);
4693 sc->args = car(sc->args);
4695 s_goto(sc,OP_P0LIST);
4698 if(sc->interactive_repl) {
4699 s_goto(sc,OP_T0LVL);
4705 CASE(OP_REVERSE): /* reverse */
4706 s_return(sc,reverse(sc, sc->NIL, car(sc->args)));
4708 CASE(OP_LIST_STAR): /* list* */
4709 s_return(sc,list_star(sc,sc->args));
4711 CASE(OP_APPEND): /* append */
4718 /* cdr() in the while condition is not a typo. If car() */
4719 /* is used (append '() 'a) will return the wrong result.*/
4720 while (cdr(y) != sc->NIL) {
4721 x = revappend(sc, x, car(y));
4724 Error_0(sc, "non-list argument to append");
4728 s_return(sc, reverse_in_place(sc, car(y), x));
4731 CASE(OP_SET_SYMBOL_PROPERTY): /* set-symbol-property! */
4732 gc_disable(sc, gc_reservations(set_property));
4733 s_return_enable_gc(sc,
4734 set_property(sc, car(sc->args),
4735 cadr(sc->args), caddr(sc->args)));
4737 CASE(OP_SYMBOL_PROPERTY): /* symbol-property */
4738 s_return(sc, get_property(sc, car(sc->args), cadr(sc->args)));
4739 #endif /* USE_PLIST */
4742 CASE(OP_TAG_VALUE): { /* not exposed */
4743 /* This tags sc->value with car(sc->args). Useful to tag
4744 * results of opcode evaluations. */
4746 free_cons(sc, sc->args, &a, &b);
4747 free_cons(sc, b, &b, &c);
4748 assert(c == sc->NIL);
4749 s_return(sc, mk_tagged_value(sc, sc->value, a, b));
4752 CASE(OP_MK_TAGGED): /* make-tagged-value */
4753 if (is_vector(car(sc->args)))
4754 Error_0(sc, "cannot tag vector");
4755 s_return(sc, mk_tagged_value(sc, car(sc->args),
4756 car(cadr(sc->args)),
4757 cdr(cadr(sc->args))));
4759 CASE(OP_GET_TAG): /* get-tag */
4760 s_return(sc, get_tag(sc, car(sc->args)));
4761 #endif /* USE_TAGS */
4763 CASE(OP_QUIT): /* quit */
4764 if(is_pair(sc->args)) {
4765 sc->retcode=ivalue(car(sc->args));
4769 CASE(OP_GC): /* gc */
4770 gc(sc, sc->NIL, sc->NIL);
4773 CASE(OP_GCVERB): /* gc-verbose */
4774 { int was = sc->gc_verbose;
4776 sc->gc_verbose = (car(sc->args) != sc->F);
4780 CASE(OP_NEWSEGMENT): /* new-segment */
4781 if (!is_pair(sc->args) || !is_number(car(sc->args))) {
4782 Error_0(sc,"new-segment: argument must be a number");
4784 alloc_cellseg(sc, (int) ivalue(car(sc->args)));
4787 CASE(OP_OBLIST): /* oblist */
4788 s_return(sc, oblist_all_symbols(sc));
4790 CASE(OP_CURR_INPORT): /* current-input-port */
4791 s_return(sc,sc->inport);
4793 CASE(OP_CURR_OUTPORT): /* current-output-port */
4794 s_return(sc,sc->outport);
4796 CASE(OP_OPEN_INFILE): /* open-input-file */
4797 CASE(OP_OPEN_OUTFILE): /* open-output-file */
4798 CASE(OP_OPEN_INOUTFILE): /* open-input-output-file */ {
4802 case OP_OPEN_INFILE: prop=port_input; break;
4803 case OP_OPEN_OUTFILE: prop=port_output; break;
4804 case OP_OPEN_INOUTFILE: prop=port_input|port_output; break;
4805 default: assert (! "reached");
4807 p=port_from_filename(sc,strvalue(car(sc->args)),prop);
4813 default: assert (! "reached");
4816 #if USE_STRING_PORTS
4817 CASE(OP_OPEN_INSTRING): /* open-input-string */
4818 CASE(OP_OPEN_INOUTSTRING): /* open-input-output-string */ {
4822 case OP_OPEN_INSTRING: prop=port_input; break;
4823 case OP_OPEN_INOUTSTRING: prop=port_input|port_output; break;
4824 default: assert (! "reached");
4826 p=port_from_string(sc, strvalue(car(sc->args)),
4827 strvalue(car(sc->args))+strlength(car(sc->args)), prop);
4833 CASE(OP_OPEN_OUTSTRING): /* open-output-string */ {
4835 if(car(sc->args)==sc->NIL) {
4836 p=port_from_scratch(sc);
4841 p=port_from_string(sc, strvalue(car(sc->args)),
4842 strvalue(car(sc->args))+strlength(car(sc->args)),
4850 CASE(OP_GET_OUTSTRING): /* get-output-string */ {
4853 if ((p=car(sc->args)->_object._port)->kind&port_string) {
4857 size=p->rep.string.curr-p->rep.string.start+1;
4858 str=sc->malloc(size);
4862 memcpy(str,p->rep.string.start,size-1);
4864 s=mk_string(sc,str);
4873 CASE(OP_CLOSE_INPORT): /* close-input-port */
4874 port_close(sc,car(sc->args),port_input);
4877 CASE(OP_CLOSE_OUTPORT): /* close-output-port */
4878 port_close(sc,car(sc->args),port_output);
4881 CASE(OP_INT_ENV): /* interaction-environment */
4882 s_return(sc,sc->global_env);
4884 CASE(OP_CURR_ENV): /* current-environment */
4885 s_return(sc,sc->envir);
4891 static pointer opexe_5(scheme *sc, enum scheme_opcodes op) {
4894 if(sc->nesting!=0) {
4898 Error_1(sc,"unmatched parentheses:",mk_integer(sc,n));
4902 /* ========== reading part ========== */
4904 if(!is_pair(sc->args)) {
4905 s_goto(sc,OP_READ_INTERNAL);
4907 if(!is_inport(car(sc->args))) {
4908 Error_1(sc,"read: not an input port:",car(sc->args));
4910 if(car(sc->args)==sc->inport) {
4911 s_goto(sc,OP_READ_INTERNAL);
4914 sc->inport=car(sc->args);
4915 x=cons(sc,x,sc->NIL);
4916 s_save(sc,OP_SET_INPORT, x, sc->NIL);
4917 s_goto(sc,OP_READ_INTERNAL);
4919 CASE(OP_READ_CHAR): /* read-char */
4920 CASE(OP_PEEK_CHAR): /* peek-char */ {
4922 if(is_pair(sc->args)) {
4923 if(car(sc->args)!=sc->inport) {
4925 x=cons(sc,x,sc->NIL);
4926 s_save(sc,OP_SET_INPORT, x, sc->NIL);
4927 sc->inport=car(sc->args);
4932 s_return(sc,sc->EOF_OBJ);
4934 if(sc->op==OP_PEEK_CHAR) {
4937 s_return(sc,mk_character(sc,c));
4940 CASE(OP_CHAR_READY): /* char-ready? */ {
4941 pointer p=sc->inport;
4943 if(is_pair(sc->args)) {
4946 res=p->_object._port->kind&port_string;
4950 CASE(OP_SET_INPORT): /* set-input-port */
4951 sc->inport=car(sc->args);
4952 s_return(sc,sc->value);
4954 CASE(OP_SET_OUTPORT): /* set-output-port */
4955 sc->outport=car(sc->args);
4956 s_return(sc,sc->value);
4961 s_return(sc,sc->EOF_OBJ);
4964 s_save(sc,OP_RDVEC,sc->NIL,sc->NIL);
4967 sc->tok = token(sc);
4968 if (sc->tok == TOK_RPAREN) {
4969 s_return(sc,sc->NIL);
4970 } else if (sc->tok == TOK_DOT) {
4971 Error_0(sc,"syntax error: illegal dot expression");
4973 #if USE_TAGS && SHOW_ERROR_LINE
4977 sc->nesting_stack[sc->file_i]++;
4978 #if USE_TAGS && SHOW_ERROR_LINE
4979 filename = sc->load_stack[sc->file_i].filename;
4980 lineno = sc->load_stack[sc->file_i].curr_line;
4982 s_save(sc, OP_TAG_VALUE,
4983 cons(sc, filename, cons(sc, lineno, sc->NIL)),
4986 s_save(sc,OP_RDLIST, sc->NIL, sc->NIL);
4987 s_thread_to(sc,OP_RDSEXPR);
4990 s_save(sc,OP_RDQUOTE, sc->NIL, sc->NIL);
4991 sc->tok = token(sc);
4992 s_thread_to(sc,OP_RDSEXPR);
4994 sc->tok = token(sc);
4995 if(sc->tok==TOK_VEC) {
4996 s_save(sc,OP_RDQQUOTEVEC, sc->NIL, sc->NIL);
4998 s_thread_to(sc,OP_RDSEXPR);
5000 s_save(sc,OP_RDQQUOTE, sc->NIL, sc->NIL);
5002 s_thread_to(sc,OP_RDSEXPR);
5004 s_save(sc,OP_RDUNQUOTE, sc->NIL, sc->NIL);
5005 sc->tok = token(sc);
5006 s_thread_to(sc,OP_RDSEXPR);
5008 s_save(sc,OP_RDUQTSP, sc->NIL, sc->NIL);
5009 sc->tok = token(sc);
5010 s_thread_to(sc,OP_RDSEXPR);
5012 s_return(sc,mk_atom(sc, readstr_upto(sc, DELIMITERS)));
5016 Error_0(sc,"Error reading string");
5021 pointer f=find_slot_in_env(sc,sc->envir,sc->SHARP_HOOK,1);
5023 Error_0(sc,"undefined sharp expression");
5025 sc->code=cons(sc,slot_value_in_env(f),sc->NIL);
5029 case TOK_SHARP_CONST:
5030 if ((x = mk_sharp_const(sc, readstr_upto(sc, DELIMITERS))) == sc->NIL) {
5031 Error_0(sc,"undefined sharp expression");
5036 Error_0(sc,"syntax error: illegal token");
5042 sc->args = cons(sc, sc->value, sc->args);
5044 sc->tok = token(sc);
5045 if (sc->tok == TOK_EOF)
5046 { s_return(sc,sc->EOF_OBJ); }
5047 else if (sc->tok == TOK_RPAREN) {
5052 port_increment_current_line(sc, &sc->load_stack[sc->file_i], 1);
5053 sc->nesting_stack[sc->file_i]--;
5054 s_return(sc,reverse_in_place(sc, sc->NIL, sc->args));
5055 } else if (sc->tok == TOK_DOT) {
5056 s_save(sc,OP_RDDOT, sc->args, sc->NIL);
5057 sc->tok = token(sc);
5058 s_thread_to(sc,OP_RDSEXPR);
5060 s_save(sc,OP_RDLIST, sc->args, sc->NIL);;
5061 s_thread_to(sc,OP_RDSEXPR);
5066 if (token(sc) != TOK_RPAREN) {
5067 Error_0(sc,"syntax error: illegal dot expression");
5069 sc->nesting_stack[sc->file_i]--;
5070 s_return(sc,reverse_in_place(sc, sc->value, sc->args));
5075 s_return_enable_gc(sc, cons(sc, sc->QUOTE,
5076 cons(sc, sc->value, sc->NIL)));
5080 s_return_enable_gc(sc, cons(sc, sc->QQUOTE,
5081 cons(sc, sc->value, sc->NIL)));
5083 CASE(OP_RDQQUOTEVEC):
5084 gc_disable(sc, 5 + 2 * gc_reservations (mk_symbol));
5085 s_return_enable_gc(sc,cons(sc, mk_symbol(sc,"apply"),
5086 cons(sc, mk_symbol(sc,"vector"),
5087 cons(sc,cons(sc, sc->QQUOTE,
5088 cons(sc,sc->value,sc->NIL)),
5093 s_return_enable_gc(sc, cons(sc, sc->UNQUOTE,
5094 cons(sc, sc->value, sc->NIL)));
5098 s_return_enable_gc(sc, cons(sc, sc->UNQUOTESP,
5099 cons(sc, sc->value, sc->NIL)));
5102 /*sc->code=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
5103 s_goto(sc,OP_EVAL); Cannot be quoted*/
5104 /*x=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
5105 s_return(sc,x); Cannot be part of pairs*/
5106 /*sc->code=mk_proc(sc,OP_VECTOR);
5108 s_goto(sc,OP_APPLY);*/
5110 s_goto(sc,OP_VECTOR);
5112 /* ========== printing part ========== */
5114 if(is_vector(sc->args)) {
5116 sc->args=cons(sc,sc->args,mk_integer(sc,0));
5117 s_thread_to(sc,OP_PVECFROM);
5118 } else if(is_environment(sc->args)) {
5119 putstr(sc,"#<ENVIRONMENT>");
5121 } else if (!is_pair(sc->args)) {
5122 printatom(sc, sc->args, sc->print_flag);
5124 } else if (car(sc->args) == sc->QUOTE && ok_abbrev(cdr(sc->args))) {
5126 sc->args = cadr(sc->args);
5127 s_thread_to(sc,OP_P0LIST);
5128 } else if (car(sc->args) == sc->QQUOTE && ok_abbrev(cdr(sc->args))) {
5130 sc->args = cadr(sc->args);
5131 s_thread_to(sc,OP_P0LIST);
5132 } else if (car(sc->args) == sc->UNQUOTE && ok_abbrev(cdr(sc->args))) {
5134 sc->args = cadr(sc->args);
5135 s_thread_to(sc,OP_P0LIST);
5136 } else if (car(sc->args) == sc->UNQUOTESP && ok_abbrev(cdr(sc->args))) {
5138 sc->args = cadr(sc->args);
5139 s_thread_to(sc,OP_P0LIST);
5142 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
5143 sc->args = car(sc->args);
5144 s_thread_to(sc,OP_P0LIST);
5148 if (is_pair(sc->args)) {
5149 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
5151 sc->args = car(sc->args);
5152 s_thread_to(sc,OP_P0LIST);
5153 } else if(is_vector(sc->args)) {
5154 s_save(sc,OP_P1LIST,sc->NIL,sc->NIL);
5156 s_thread_to(sc,OP_P0LIST);
5158 if (sc->args != sc->NIL) {
5160 printatom(sc, sc->args, sc->print_flag);
5165 CASE(OP_PVECFROM): {
5166 int i=ivalue_unchecked(cdr(sc->args));
5167 pointer vec=car(sc->args);
5168 int len = vector_length(vec);
5173 pointer elem=vector_elem(vec,i);
5174 ivalue_unchecked(cdr(sc->args))=i+1;
5175 s_save(sc,OP_PVECFROM, sc->args, sc->NIL);
5179 s_thread_to(sc,OP_P0LIST);
5184 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
5185 Error_0(sc,sc->strbuff);
5191 static pointer opexe_6(scheme *sc, enum scheme_opcodes op) {
5196 CASE(OP_LIST_LENGTH): /* length */ /* a.k */
5197 v=list_length(sc,car(sc->args));
5199 Error_1(sc,"length: not a list:",car(sc->args));
5202 s_return_enable_gc(sc, mk_integer(sc, v));
5204 CASE(OP_ASSQ): /* assq */ /* a.k */
5206 for (y = cadr(sc->args); is_pair(y); y = cdr(y)) {
5207 if (!is_pair(car(y))) {
5208 Error_0(sc,"unable to handle non pair element");
5214 s_return(sc,car(y));
5220 CASE(OP_GET_CLOSURE): /* get-closure-code */ /* a.k */
5221 sc->args = car(sc->args);
5222 if (sc->args == sc->NIL) {
5224 } else if (is_closure(sc->args)) {
5226 s_return_enable_gc(sc, cons(sc, sc->LAMBDA,
5227 closure_code(sc->value)));
5228 } else if (is_macro(sc->args)) {
5230 s_return_enable_gc(sc, cons(sc, sc->LAMBDA,
5231 closure_code(sc->value)));
5235 CASE(OP_CLOSUREP): /* closure? */
5237 * Note, macro object is also a closure.
5238 * Therefore, (closure? <#MACRO>) ==> #t
5240 s_retbool(is_closure(car(sc->args)));
5241 CASE(OP_MACROP): /* macro? */
5242 s_retbool(is_macro(car(sc->args)));
5243 CASE(OP_VM_HISTORY): /* *vm-history* */
5244 s_return(sc, history_flatten(sc));
5246 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
5247 Error_0(sc,sc->strbuff);
5249 return sc->T; /* NOTREACHED */
5252 typedef pointer (*dispatch_func)(scheme *, enum scheme_opcodes);
5254 typedef int (*test_predicate)(pointer);
5256 static int is_any(pointer p) {
5261 static int is_nonneg(pointer p) {
5262 return ivalue(p)>=0 && is_integer(p);
5265 /* Correspond carefully with following defines! */
5272 {is_string, "string"},
5273 {is_symbol, "symbol"},
5275 {is_inport,"input port"},
5276 {is_outport,"output port"},
5277 {is_environment, "environment"},
5280 {is_character, "character"},
5281 {is_vector, "vector"},
5282 {is_number, "number"},
5283 {is_integer, "integer"},
5284 {is_nonneg, "non-negative integer"}
5288 #define TST_ANY "\001"
5289 #define TST_STRING "\002"
5290 #define TST_SYMBOL "\003"
5291 #define TST_PORT "\004"
5292 #define TST_INPORT "\005"
5293 #define TST_OUTPORT "\006"
5294 #define TST_ENVIRONMENT "\007"
5295 #define TST_PAIR "\010"
5296 #define TST_LIST "\011"
5297 #define TST_CHAR "\012"
5298 #define TST_VECTOR "\013"
5299 #define TST_NUMBER "\014"
5300 #define TST_INTEGER "\015"
5301 #define TST_NATURAL "\016"
5308 char *arg_tests_encoding;
5311 #define INF_ARG 0xffff
5313 static op_code_info dispatch_table[]= {
5314 #define _OP_DEF(A,B,C,D,E,OP) {A,B,C,D,E},
5315 #include "opdefines.h"
5319 static const char *procname(pointer x) {
5321 const char *name=dispatch_table[n].name;
5328 /* kernel of this interpreter */
5329 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op) {
5332 op_code_info *pcd=dispatch_table+sc->op;
5333 if (pcd->name!=0) { /* if built-in function, check arguments */
5334 char msg[STRBUFFSIZE];
5336 int n=list_length(sc,sc->args);
5338 /* Check number of arguments */
5339 if(n<pcd->min_arity) {
5341 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5343 pcd->min_arity==pcd->max_arity?"":" at least",
5346 if(ok && n>pcd->max_arity) {
5348 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5350 pcd->min_arity==pcd->max_arity?"":" at most",
5354 if(pcd->arg_tests_encoding!=0) {
5357 const char *t=pcd->arg_tests_encoding;
5358 pointer arglist=sc->args;
5360 pointer arg=car(arglist);
5362 if(j==TST_LIST[0]) {
5363 if(arg!=sc->NIL && !is_pair(arg)) break;
5365 if(!tests[j].fct(arg)) break;
5368 if(t[1]!=0) {/* last test is replicated as necessary */
5371 arglist=cdr(arglist);
5376 snprintf(msg, STRBUFFSIZE, "%s: argument %d must be: %s, got: %s",
5380 type_to_string(type(car(arglist))));
5385 if(_Error_1(sc,msg,0)==sc->NIL) {
5388 pcd=dispatch_table+sc->op;
5391 ok_to_freely_gc(sc);
5392 if (pcd->func(sc, (enum scheme_opcodes)sc->op) == sc->NIL) {
5396 fprintf(stderr,"No memory!\n");
5402 /* ========== Initialization of internal keywords ========== */
5404 static void assign_syntax(scheme *sc, char *name) {
5408 x = oblist_find_by_name(sc, name, &slot);
5409 assert (x == sc->NIL);
5411 x = oblist_add_by_name(sc, name, slot);
5412 typeflag(x) |= T_SYNTAX;
5415 static void assign_proc(scheme *sc, enum scheme_opcodes op, char *name) {
5418 x = mk_symbol(sc, name);
5420 new_slot_in_env(sc, x, y);
5423 static pointer mk_proc(scheme *sc, enum scheme_opcodes op) {
5426 y = get_cell(sc, sc->NIL, sc->NIL);
5427 typeflag(y) = (T_PROC | T_ATOM);
5428 ivalue_unchecked(y) = (long) op;
5433 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5434 static int syntaxnum(pointer p) {
5435 const char *s=strvalue(car(p));
5436 switch(strlength(car(p))) {
5438 if(s[0]=='i') return OP_IF0; /* if */
5439 else return OP_OR0; /* or */
5441 if(s[0]=='a') return OP_AND0; /* and */
5442 else return OP_LET0; /* let */
5445 case 'e': return OP_CASE0; /* case */
5446 case 'd': return OP_COND0; /* cond */
5447 case '*': return OP_LET0AST; /* let* */
5448 default: return OP_SET0; /* set! */
5452 case 'g': return OP_BEGIN; /* begin */
5453 case 'l': return OP_DELAY; /* delay */
5454 case 'c': return OP_MACRO0; /* macro */
5455 default: return OP_QUOTE; /* quote */
5459 case 'm': return OP_LAMBDA; /* lambda */
5460 case 'f': return OP_DEF0; /* define */
5461 default: return OP_LET0REC; /* letrec */
5464 return OP_C0STREAM; /* cons-stream */
5468 /* initialization of TinyScheme */
5470 INTERFACE static pointer s_cons(scheme *sc, pointer a, pointer b) {
5471 return cons(sc,a,b);
5473 INTERFACE static pointer s_immutable_cons(scheme *sc, pointer a, pointer b) {
5474 return immutable_cons(sc,a,b);
5477 static struct scheme_interface vtbl ={
5492 get_foreign_object_vtable,
5493 get_foreign_object_data,
5545 scheme *scheme_init_new() {
5546 scheme *sc=(scheme*)malloc(sizeof(scheme));
5547 if(!scheme_init(sc)) {
5555 scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free) {
5556 scheme *sc=(scheme*)malloc(sizeof(scheme));
5557 if(!scheme_init_custom_alloc(sc,malloc,free)) {
5566 int scheme_init(scheme *sc) {
5567 return scheme_init_custom_alloc(sc,malloc,free);
5570 int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
5571 int i, n=sizeof(dispatch_table)/sizeof(dispatch_table[0]);
5574 num_zero.is_fixnum=1;
5575 num_zero.value.ivalue=0;
5576 num_one.is_fixnum=1;
5577 num_one.value.ivalue=1;
5585 sc->last_cell_seg = -1;
5586 sc->sink = &sc->_sink;
5587 sc->NIL = &sc->_NIL;
5588 sc->T = &sc->_HASHT;
5589 sc->F = &sc->_HASHF;
5590 sc->EOF_OBJ=&sc->_EOF_OBJ;
5592 #if USE_SMALL_INTEGERS
5593 if (initialize_small_integers(sc)) {
5599 sc->free_cell = &sc->_NIL;
5601 sc->inhibit_gc = GC_ENABLED;
5602 sc->reserved_cells = 0;
5603 sc->reserved_lineno = 0;
5606 sc->outport=sc->NIL;
5607 sc->save_inport=sc->NIL;
5608 sc->loadport=sc->NIL;
5610 memset (sc->nesting_stack, 0, sizeof sc->nesting_stack);
5611 sc->interactive_repl=0;
5612 sc->strbuff = sc->malloc(STRBUFFSIZE);
5613 if (sc->strbuff == 0) {
5617 sc->strbuff_size = STRBUFFSIZE;
5619 if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
5624 dump_stack_initialize(sc);
5631 typeflag(sc->NIL) = (T_NIL | T_ATOM | MARK);
5632 car(sc->NIL) = cdr(sc->NIL) = sc->NIL;
5634 typeflag(sc->T) = (T_BOOLEAN | T_ATOM | MARK);
5635 car(sc->T) = cdr(sc->T) = sc->T;
5637 typeflag(sc->F) = (T_BOOLEAN | T_ATOM | MARK);
5638 car(sc->F) = cdr(sc->F) = sc->F;
5640 typeflag(sc->EOF_OBJ) = (T_EOF_OBJ | T_ATOM | MARK);
5641 car(sc->EOF_OBJ) = cdr(sc->EOF_OBJ) = sc->EOF_OBJ;
5643 typeflag(sc->sink) = (T_SINK | T_PAIR | MARK);
5644 car(sc->sink) = cdr(sc->sink) = sc->NIL;
5646 sc->c_nest = sc->NIL;
5648 sc->oblist = oblist_initial_value(sc);
5649 /* init global_env */
5650 new_frame_in_env(sc, sc->NIL);
5651 sc->global_env = sc->envir;
5653 x = mk_symbol(sc,"else");
5654 new_slot_in_env(sc, x, sc->T);
5656 assign_syntax(sc, "lambda");
5657 assign_syntax(sc, "quote");
5658 assign_syntax(sc, "define");
5659 assign_syntax(sc, "if");
5660 assign_syntax(sc, "begin");
5661 assign_syntax(sc, "set!");
5662 assign_syntax(sc, "let");
5663 assign_syntax(sc, "let*");
5664 assign_syntax(sc, "letrec");
5665 assign_syntax(sc, "cond");
5666 assign_syntax(sc, "delay");
5667 assign_syntax(sc, "and");
5668 assign_syntax(sc, "or");
5669 assign_syntax(sc, "cons-stream");
5670 assign_syntax(sc, "macro");
5671 assign_syntax(sc, "case");
5673 for(i=0; i<n; i++) {
5674 if(dispatch_table[i].name!=0) {
5675 assign_proc(sc, (enum scheme_opcodes)i, dispatch_table[i].name);
5679 history_init(sc, 8, 8);
5681 /* initialization of global pointers to special symbols */
5682 sc->LAMBDA = mk_symbol(sc, "lambda");
5683 sc->QUOTE = mk_symbol(sc, "quote");
5684 sc->QQUOTE = mk_symbol(sc, "quasiquote");
5685 sc->UNQUOTE = mk_symbol(sc, "unquote");
5686 sc->UNQUOTESP = mk_symbol(sc, "unquote-splicing");
5687 sc->FEED_TO = mk_symbol(sc, "=>");
5688 sc->COLON_HOOK = mk_symbol(sc,"*colon-hook*");
5689 sc->ERROR_HOOK = mk_symbol(sc, "*error-hook*");
5690 sc->SHARP_HOOK = mk_symbol(sc, "*sharp-hook*");
5691 #if USE_COMPILE_HOOK
5692 sc->COMPILE_HOOK = mk_symbol(sc, "*compile-hook*");
5695 return !sc->no_memory;
5698 void scheme_set_input_port_file(scheme *sc, FILE *fin) {
5699 sc->inport=port_from_file(sc,fin,port_input);
5702 void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end) {
5703 sc->inport=port_from_string(sc,start,past_the_end,port_input);
5706 void scheme_set_output_port_file(scheme *sc, FILE *fout) {
5707 sc->outport=port_from_file(sc,fout,port_output);
5710 void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end) {
5711 sc->outport=port_from_string(sc,start,past_the_end,port_output);
5714 void scheme_set_external_data(scheme *sc, void *p) {
5718 void scheme_deinit(scheme *sc) {
5722 sc->global_env=sc->NIL;
5723 dump_stack_free(sc);
5729 if(is_port(sc->inport)) {
5730 typeflag(sc->inport) = T_ATOM;
5733 sc->outport=sc->NIL;
5734 if(is_port(sc->save_inport)) {
5735 typeflag(sc->save_inport) = T_ATOM;
5737 sc->save_inport=sc->NIL;
5738 if(is_port(sc->loadport)) {
5739 typeflag(sc->loadport) = T_ATOM;
5741 sc->loadport=sc->NIL;
5743 for(i=0; i<=sc->file_i; i++) {
5744 port_clear_location(sc, &sc->load_stack[i]);
5748 gc(sc,sc->NIL,sc->NIL);
5750 #if USE_SMALL_INTEGERS
5751 sc->free(sc->integer_alloc);
5754 for(i=0; i<=sc->last_cell_seg; i++) {
5755 sc->free(sc->alloc_seg[i]);
5757 sc->free(sc->strbuff);
5760 void scheme_load_file(scheme *sc, FILE *fin)
5761 { scheme_load_named_file(sc,fin,0); }
5763 void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename) {
5764 dump_stack_reset(sc);
5765 sc->envir = sc->global_env;
5767 sc->load_stack[0].kind=port_input|port_file;
5768 sc->load_stack[0].rep.stdio.file=fin;
5769 sc->loadport=mk_port(sc,sc->load_stack);
5772 sc->interactive_repl=1;
5775 port_init_location(sc, &sc->load_stack[0],
5776 (fin != stdin && filename)
5777 ? mk_string(sc, filename)
5780 sc->inport=sc->loadport;
5781 sc->args = mk_integer(sc,sc->file_i);
5782 Eval_Cycle(sc, OP_T0LVL);
5783 typeflag(sc->loadport)=T_ATOM;
5784 if(sc->retcode==0) {
5785 sc->retcode=sc->nesting!=0;
5788 port_clear_location(sc, &sc->load_stack[0]);
5791 void scheme_load_string(scheme *sc, const char *cmd) {
5792 dump_stack_reset(sc);
5793 sc->envir = sc->global_env;
5795 sc->load_stack[0].kind=port_input|port_string;
5796 sc->load_stack[0].rep.string.start=(char*)cmd; /* This func respects const */
5797 sc->load_stack[0].rep.string.past_the_end=(char*)cmd+strlen(cmd);
5798 sc->load_stack[0].rep.string.curr=(char*)cmd;
5799 port_init_location(sc, &sc->load_stack[0], NULL);
5800 sc->loadport=mk_port(sc,sc->load_stack);
5802 sc->interactive_repl=0;
5803 sc->inport=sc->loadport;
5804 sc->args = mk_integer(sc,sc->file_i);
5805 Eval_Cycle(sc, OP_T0LVL);
5806 typeflag(sc->loadport)=T_ATOM;
5807 if(sc->retcode==0) {
5808 sc->retcode=sc->nesting!=0;
5811 port_clear_location(sc, &sc->load_stack[0]);
5814 void scheme_define(scheme *sc, pointer envir, pointer symbol, pointer value) {
5817 x = find_slot_spec_in_env(sc, envir, symbol, 0, &sslot);
5819 set_slot_in_env(sc, x, value);
5821 new_slot_spec_in_env(sc, envir, symbol, value, sslot);
5826 void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr)
5830 mk_symbol(sc,sr->name),
5831 mk_foreign_func(sc, sr->f));
5834 void scheme_register_foreign_func_list(scheme * sc,
5835 scheme_registerable * list,
5839 for(i = 0; i < count; i++)
5841 scheme_register_foreign_func(sc, list + i);
5845 pointer scheme_apply0(scheme *sc, const char *procname)
5846 { return scheme_eval(sc, cons(sc,mk_symbol(sc,procname),sc->NIL)); }
5848 void save_from_C_call(scheme *sc)
5850 pointer saved_data =
5857 sc->c_nest = cons(sc, saved_data, sc->c_nest);
5858 /* Truncate the dump stack so TS will return here when done, not
5859 directly resume pre-C-call operations. */
5860 dump_stack_reset(sc);
5862 void restore_from_C_call(scheme *sc)
5864 car(sc->sink) = caar(sc->c_nest);
5865 sc->envir = cadar(sc->c_nest);
5866 sc->dump = cdr(cdar(sc->c_nest));
5868 sc->c_nest = cdr(sc->c_nest);
5871 /* "func" and "args" are assumed to be already eval'ed. */
5872 pointer scheme_call(scheme *sc, pointer func, pointer args)
5874 int old_repl = sc->interactive_repl;
5875 sc->interactive_repl = 0;
5876 save_from_C_call(sc);
5877 sc->envir = sc->global_env;
5881 Eval_Cycle(sc, OP_APPLY);
5882 sc->interactive_repl = old_repl;
5883 restore_from_C_call(sc);
5887 pointer scheme_eval(scheme *sc, pointer obj)
5889 int old_repl = sc->interactive_repl;
5890 sc->interactive_repl = 0;
5891 save_from_C_call(sc);
5895 Eval_Cycle(sc, OP_EVAL);
5896 sc->interactive_repl = old_repl;
5897 restore_from_C_call(sc);
5904 /* ========== Main ========== */
5908 #if defined(__APPLE__) && !defined (OSX)
5911 extern MacTS_main(int argc, char **argv);
5913 int argc = ccommand(&argv);
5914 MacTS_main(argc,argv);
5917 int MacTS_main(int argc, char **argv) {
5919 int main(int argc, char **argv) {
5923 char *file_name=InitFile;
5930 if(argc==2 && strcmp(argv[1],"-?")==0) {
5931 printf("Usage: tinyscheme -?\n");
5932 printf("or: tinyscheme [<file1> <file2> ...]\n");
5933 printf("followed by\n");
5934 printf(" -1 <file> [<arg1> <arg2> ...]\n");
5935 printf(" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5936 printf("assuming that the executable is named tinyscheme.\n");
5937 printf("Use - as filename for stdin.\n");
5940 if(!scheme_init(&sc)) {
5941 fprintf(stderr,"Could not initialize!\n");
5944 scheme_set_input_port_file(&sc, stdin);
5945 scheme_set_output_port_file(&sc, stdout);
5947 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"load-extension"),mk_foreign_func(&sc, scm_load_ext));
5950 if(access(file_name,0)!=0) {
5951 char *p=getenv("TINYSCHEMEINIT");
5957 if(strcmp(file_name,"-")==0) {
5959 } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0) {
5960 pointer args=sc.NIL;
5961 isfile=file_name[1]=='1';
5963 if(strcmp(file_name,"-")==0) {
5966 fin=fopen(file_name,"r");
5968 for(;*argv;argv++) {
5969 pointer value=mk_string(&sc,*argv);
5970 args=cons(&sc,value,args);
5972 args=reverse_in_place(&sc,sc.NIL,args);
5973 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args);
5976 fin=fopen(file_name,"r");
5978 if(isfile && fin==0) {
5979 fprintf(stderr,"Could not open file %s\n",file_name);
5982 scheme_load_named_file(&sc,fin,file_name);
5984 scheme_load_string(&sc,file_name);
5986 if(!isfile || fin!=stdin) {
5988 fprintf(stderr,"Errors encountered reading %s\n",file_name);
5996 } while(file_name!=0);
5998 scheme_load_named_file(&sc,stdin,0);