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)
19 #define _SCHEME_SOURCE
20 #include "scheme-private.h"
25 #define snprintf _snprintf
43 # define stricmp strcasecmp
47 /* Used for documentation purposes, to signal functions in 'interface' */
62 #define TOK_SHARP_CONST 11
66 #define DELIMITERS "()\";\f\t\v\n\r "
69 * Basic memory allocation units
72 #define banner "TinyScheme 1.41"
79 static int stricmp(const char *s1, const char *s2)
93 #endif /* __APPLE__ */
95 #if USE_STRLWR && !defined(HAVE_STRLWR)
96 static const char *strlwr(char *s) {
107 # define prompt "ts> "
111 # define InitFile "init.scm"
114 #ifndef FIRST_CELLSEGS
115 # define FIRST_CELLSEGS 3
120 /* All types have the LSB set. The garbage collector takes advantage
121 * of that to identify types. */
123 T_STRING = 1 << 1 | 1,
124 T_NUMBER = 2 << 1 | 1,
125 T_SYMBOL = 3 << 1 | 1,
128 T_CLOSURE = 6 << 1 | 1,
129 T_CONTINUATION = 7 << 1 | 1,
130 T_FOREIGN = 8 << 1 | 1,
131 T_CHARACTER = 9 << 1 | 1,
132 T_PORT = 10 << 1 | 1,
133 T_VECTOR = 11 << 1 | 1,
134 T_MACRO = 12 << 1 | 1,
135 T_PROMISE = 13 << 1 | 1,
136 T_ENVIRONMENT = 14 << 1 | 1,
137 T_FOREIGN_OBJECT = 15 << 1 | 1,
138 T_BOOLEAN = 16 << 1 | 1,
140 T_EOF_OBJ = 18 << 1 | 1,
141 T_SINK = 19 << 1 | 1,
142 T_LAST_SYSTEM_TYPE = 19 << 1 | 1
146 type_to_string (enum scheme_types typ)
150 case T_STRING: return "string";
151 case T_NUMBER: return "number";
152 case T_SYMBOL: return "symbol";
153 case T_PROC: return "proc";
154 case T_PAIR: return "pair";
155 case T_CLOSURE: return "closure";
156 case T_CONTINUATION: return "continuation";
157 case T_FOREIGN: return "foreign";
158 case T_CHARACTER: return "character";
159 case T_PORT: return "port";
160 case T_VECTOR: return "vector";
161 case T_MACRO: return "macro";
162 case T_PROMISE: return "promise";
163 case T_ENVIRONMENT: return "environment";
164 case T_FOREIGN_OBJECT: return "foreign object";
165 case T_BOOLEAN: return "boolean";
166 case T_NIL: return "nil";
167 case T_EOF_OBJ: return "eof object";
168 case T_SINK: return "sink";
170 assert (! "not reached");
173 /* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */
175 #define ADJ (1 << TYPE_BITS)
176 #define T_MASKTYPE (ADJ - 1)
177 #define T_TAGGED 1024 /* 0000010000000000 */
178 #define T_FINALIZE 2048 /* 0000100000000000 */
179 #define T_SYNTAX 4096 /* 0001000000000000 */
180 #define T_IMMUTABLE 8192 /* 0010000000000000 */
181 #define T_ATOM 16384 /* 0100000000000000 */ /* only for gc */
182 #define CLRATOM 49151 /* 1011111111111111 */ /* only for gc */
183 #define MARK 32768 /* 1000000000000000 */
184 #define UNMARK 32767 /* 0111111111111111 */
187 static num num_add(num a, num b);
188 static num num_mul(num a, num b);
189 static num num_div(num a, num b);
190 static num num_intdiv(num a, num b);
191 static num num_sub(num a, num b);
192 static num num_rem(num a, num b);
193 static num num_mod(num a, num b);
194 static int num_eq(num a, num b);
195 static int num_gt(num a, num b);
196 static int num_ge(num a, num b);
197 static int num_lt(num a, num b);
198 static int num_le(num a, num b);
201 static double round_per_R5RS(double x);
203 static int is_zero_double(double x);
204 static INLINE int num_is_integer(pointer p) {
205 return ((p)->_object._number.is_fixnum);
211 /* macros for cell operations */
212 #define typeflag(p) ((p)->_flag)
213 #define type(p) (typeflag(p)&T_MASKTYPE)
215 INTERFACE INLINE int is_string(pointer p) { return (type(p)==T_STRING); }
216 #define strvalue(p) ((p)->_object._string._svalue)
217 #define strlength(p) ((p)->_object._string._length)
219 INTERFACE static int is_list(scheme *sc, pointer p);
220 INTERFACE INLINE int is_vector(pointer p) { return (type(p)==T_VECTOR); }
221 /* Given a vector, return it's length. */
222 #define vector_length(v) (v)->_object._vector._length
223 /* Given a vector length, compute the amount of cells required to
225 #define vector_size(len) (1 + ((len) - 1 + 2) / 3)
226 INTERFACE static void fill_vector(pointer vec, pointer obj);
227 INTERFACE static pointer *vector_elem_slot(pointer vec, int ielem);
228 INTERFACE static pointer vector_elem(pointer vec, int ielem);
229 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a);
230 INTERFACE INLINE int is_number(pointer p) { return (type(p)==T_NUMBER); }
231 INTERFACE INLINE int is_integer(pointer p) {
234 if (num_is_integer(p) || (double)ivalue(p) == rvalue(p))
239 INTERFACE INLINE int is_real(pointer p) {
240 return is_number(p) && (!(p)->_object._number.is_fixnum);
243 INTERFACE INLINE int is_character(pointer p) { return (type(p)==T_CHARACTER); }
244 INTERFACE INLINE char *string_value(pointer p) { return strvalue(p); }
245 INLINE num nvalue(pointer p) { return ((p)->_object._number); }
246 INTERFACE long ivalue(pointer p) { return (num_is_integer(p)?(p)->_object._number.value.ivalue:(long)(p)->_object._number.value.rvalue); }
247 INTERFACE double rvalue(pointer p) { return (!num_is_integer(p)?(p)->_object._number.value.rvalue:(double)(p)->_object._number.value.ivalue); }
248 #define ivalue_unchecked(p) ((p)->_object._number.value.ivalue)
249 #define rvalue_unchecked(p) ((p)->_object._number.value.rvalue)
250 #define set_num_integer(p) (p)->_object._number.is_fixnum=1;
251 #define set_num_real(p) (p)->_object._number.is_fixnum=0;
252 INTERFACE long charvalue(pointer p) { return ivalue_unchecked(p); }
254 INTERFACE INLINE int is_port(pointer p) { return (type(p)==T_PORT); }
255 INTERFACE INLINE int is_inport(pointer p) { return is_port(p) && p->_object._port->kind & port_input; }
256 INTERFACE INLINE int is_outport(pointer p) { return is_port(p) && p->_object._port->kind & port_output; }
258 INTERFACE INLINE int is_pair(pointer p) { return (type(p)==T_PAIR); }
259 #define car(p) ((p)->_object._cons._car)
260 #define cdr(p) ((p)->_object._cons._cdr)
261 INTERFACE pointer pair_car(pointer p) { return car(p); }
262 INTERFACE pointer pair_cdr(pointer p) { return cdr(p); }
263 INTERFACE pointer set_car(pointer p, pointer q) { return car(p)=q; }
264 INTERFACE pointer set_cdr(pointer p, pointer q) { return cdr(p)=q; }
266 INTERFACE INLINE int is_symbol(pointer p) { return (type(p)==T_SYMBOL); }
267 INTERFACE INLINE char *symname(pointer p) { return strvalue(car(p)); }
269 SCHEME_EXPORT INLINE int hasprop(pointer p) { return (is_symbol(p)); }
270 #define symprop(p) cdr(p)
273 INTERFACE INLINE int is_syntax(pointer p) { return (typeflag(p)&T_SYNTAX); }
274 INTERFACE INLINE int is_proc(pointer p) { return (type(p)==T_PROC); }
275 INTERFACE INLINE int is_foreign(pointer p) { return (type(p)==T_FOREIGN); }
276 INTERFACE INLINE char *syntaxname(pointer p) { return strvalue(car(p)); }
277 #define procnum(p) ivalue_unchecked(p)
278 static const char *procname(pointer x);
280 INTERFACE INLINE int is_closure(pointer p) { return (type(p)==T_CLOSURE); }
281 INTERFACE INLINE int is_macro(pointer p) { return (type(p)==T_MACRO); }
282 INTERFACE INLINE pointer closure_code(pointer p) { return car(p); }
283 INTERFACE INLINE pointer closure_env(pointer p) { return cdr(p); }
285 INTERFACE INLINE int is_continuation(pointer p) { return (type(p)==T_CONTINUATION); }
286 #define cont_dump(p) cdr(p)
288 INTERFACE INLINE int is_foreign_object(pointer p) { return (type(p)==T_FOREIGN_OBJECT); }
289 INTERFACE const foreign_object_vtable *get_foreign_object_vtable(pointer p) {
290 return p->_object._foreign_object._vtable;
292 INTERFACE void *get_foreign_object_data(pointer p) {
293 return p->_object._foreign_object._data;
296 /* To do: promise should be forced ONCE only */
297 INTERFACE INLINE int is_promise(pointer p) { return (type(p)==T_PROMISE); }
299 INTERFACE INLINE int is_environment(pointer p) { return (type(p)==T_ENVIRONMENT); }
300 #define setenvironment(p) typeflag(p) = T_ENVIRONMENT
302 #define is_atom(p) (typeflag(p)&T_ATOM)
303 #define setatom(p) typeflag(p) |= T_ATOM
304 #define clratom(p) typeflag(p) &= CLRATOM
306 #define is_mark(p) (typeflag(p)&MARK)
307 #define setmark(p) typeflag(p) |= MARK
308 #define clrmark(p) typeflag(p) &= UNMARK
310 INTERFACE INLINE int is_immutable(pointer p) { return (typeflag(p)&T_IMMUTABLE); }
311 /*#define setimmutable(p) typeflag(p) |= T_IMMUTABLE*/
312 INTERFACE INLINE void setimmutable(pointer p) { typeflag(p) |= T_IMMUTABLE; }
314 #define caar(p) car(car(p))
315 #define cadr(p) car(cdr(p))
316 #define cdar(p) cdr(car(p))
317 #define cddr(p) cdr(cdr(p))
318 #define cadar(p) car(cdr(car(p)))
319 #define caddr(p) car(cdr(cdr(p)))
320 #define cdaar(p) cdr(car(car(p)))
321 #define cadaar(p) car(cdr(car(car(p))))
322 #define cadddr(p) car(cdr(cdr(cdr(p))))
323 #define cddddr(p) cdr(cdr(cdr(cdr(p))))
326 static pointer history_flatten(scheme *sc);
327 static void history_mark(scheme *sc);
329 # define history_mark(SC) (void) 0
330 # define history_flatten(SC) (SC)->NIL
333 #if USE_CHAR_CLASSIFIERS
334 static INLINE int Cisalpha(int c) { return isascii(c) && isalpha(c); }
335 static INLINE int Cisdigit(int c) { return isascii(c) && isdigit(c); }
336 static INLINE int Cisspace(int c) { return isascii(c) && isspace(c); }
337 static INLINE int Cisupper(int c) { return isascii(c) && isupper(c); }
338 static INLINE int Cislower(int c) { return isascii(c) && islower(c); }
342 static const char *charnames[32]={
377 static int is_ascii_name(const char *name, int *pc) {
379 for(i=0; i<32; i++) {
380 if(stricmp(name,charnames[i])==0) {
385 if(stricmp(name,"del")==0) {
394 static int file_push(scheme *sc, pointer fname);
395 static void file_pop(scheme *sc);
396 static int file_interactive(scheme *sc);
397 static INLINE int is_one_of(char *s, int c);
398 static int alloc_cellseg(scheme *sc, int n);
399 static long binary_decode(const char *s);
400 static INLINE pointer get_cell(scheme *sc, pointer a, pointer b);
401 static pointer _get_cell(scheme *sc, pointer a, pointer b);
402 static pointer reserve_cells(scheme *sc, int n);
403 static pointer get_consecutive_cells(scheme *sc, int n);
404 static pointer find_consecutive_cells(scheme *sc, int n);
405 static void finalize_cell(scheme *sc, pointer a);
406 static int count_consecutive_cells(pointer x, int needed);
407 static pointer find_slot_in_env(scheme *sc, pointer env, pointer sym, int all);
408 static pointer mk_number(scheme *sc, num n);
409 static char *store_string(scheme *sc, int len, const char *str, char fill);
410 static pointer mk_vector(scheme *sc, int len);
411 static pointer mk_atom(scheme *sc, char *q);
412 static pointer mk_sharp_const(scheme *sc, char *name);
413 static pointer mk_port(scheme *sc, port *p);
414 static pointer port_from_filename(scheme *sc, const char *fn, int prop);
415 static pointer port_from_file(scheme *sc, FILE *, int prop);
416 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop);
417 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop);
418 static port *port_rep_from_file(scheme *sc, FILE *, int prop);
419 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop);
420 static void port_close(scheme *sc, pointer p, int flag);
421 static void mark(pointer a);
422 static void gc(scheme *sc, pointer a, pointer b);
423 static int basic_inchar(port *pt);
424 static int inchar(scheme *sc);
425 static void backchar(scheme *sc, int c);
426 static char *readstr_upto(scheme *sc, char *delim);
427 static pointer readstrexp(scheme *sc);
428 static INLINE int skipspace(scheme *sc);
429 static int token(scheme *sc);
430 static void printslashstring(scheme *sc, char *s, int len);
431 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen);
432 static void printatom(scheme *sc, pointer l, int f);
433 static pointer mk_proc(scheme *sc, enum scheme_opcodes op);
434 static pointer mk_closure(scheme *sc, pointer c, pointer e);
435 static pointer mk_continuation(scheme *sc, pointer d);
436 static pointer reverse(scheme *sc, pointer term, pointer list);
437 static pointer reverse_in_place(scheme *sc, pointer term, pointer list);
438 static pointer revappend(scheme *sc, pointer a, pointer b);
439 static void dump_stack_mark(scheme *);
440 static pointer opexe_0(scheme *sc, enum scheme_opcodes op);
441 static pointer opexe_1(scheme *sc, enum scheme_opcodes op);
442 static pointer opexe_2(scheme *sc, enum scheme_opcodes op);
443 static pointer opexe_3(scheme *sc, enum scheme_opcodes op);
444 static pointer opexe_4(scheme *sc, enum scheme_opcodes op);
445 static pointer opexe_5(scheme *sc, enum scheme_opcodes op);
446 static pointer opexe_6(scheme *sc, enum scheme_opcodes op);
447 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op);
448 static void assign_syntax(scheme *sc, char *name);
449 static int syntaxnum(pointer p);
450 static void assign_proc(scheme *sc, enum scheme_opcodes, char *name);
452 #define num_ivalue(n) (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue)
453 #define num_rvalue(n) (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue)
455 static num num_add(num a, num b) {
457 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
459 ret.value.ivalue= a.value.ivalue+b.value.ivalue;
461 ret.value.rvalue=num_rvalue(a)+num_rvalue(b);
466 static num num_mul(num a, num b) {
468 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
470 ret.value.ivalue= a.value.ivalue*b.value.ivalue;
472 ret.value.rvalue=num_rvalue(a)*num_rvalue(b);
477 static num num_div(num a, num b) {
479 ret.is_fixnum=a.is_fixnum && b.is_fixnum && a.value.ivalue%b.value.ivalue==0;
481 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
483 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
488 static num num_intdiv(num a, num b) {
490 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
492 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
494 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
499 static num num_sub(num a, num b) {
501 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
503 ret.value.ivalue= a.value.ivalue-b.value.ivalue;
505 ret.value.rvalue=num_rvalue(a)-num_rvalue(b);
510 static num num_rem(num a, num b) {
513 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
517 /* remainder should have same sign as second operand */
522 } else if (res < 0) {
527 ret.value.ivalue=res;
531 static num num_mod(num a, num b) {
534 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
538 /* modulo should have same sign as second operand */
542 ret.value.ivalue=res;
546 static int num_eq(num a, num b) {
548 int is_fixnum=a.is_fixnum && b.is_fixnum;
550 ret= a.value.ivalue==b.value.ivalue;
552 ret=num_rvalue(a)==num_rvalue(b);
558 static int num_gt(num a, num b) {
560 int is_fixnum=a.is_fixnum && b.is_fixnum;
562 ret= a.value.ivalue>b.value.ivalue;
564 ret=num_rvalue(a)>num_rvalue(b);
569 static int num_ge(num a, num b) {
573 static int num_lt(num a, num b) {
575 int is_fixnum=a.is_fixnum && b.is_fixnum;
577 ret= a.value.ivalue<b.value.ivalue;
579 ret=num_rvalue(a)<num_rvalue(b);
584 static int num_le(num a, num b) {
589 /* Round to nearest. Round to even if midway */
590 static double round_per_R5RS(double x) {
600 if(fmod(fl,2.0)==0.0) { /* I imagine this holds */
609 static int is_zero_double(double x) {
610 return x<DBL_MIN && x>-DBL_MIN;
613 static long binary_decode(const char *s) {
616 while(*s!=0 && (*s=='1' || *s=='0')) {
627 /* Tags are like property lists, but can be attached to arbitrary
633 mk_tagged_value(scheme *sc, pointer v, pointer tag_car, pointer tag_cdr)
637 assert(! is_vector(v));
639 r = get_consecutive_cells(sc, 2);
643 memcpy(r, v, sizeof *v);
644 typeflag(r) |= T_TAGGED;
647 typeflag(t) = T_PAIR;
657 return !! (typeflag(v) & T_TAGGED);
660 static INLINE pointer
661 get_tag(scheme *sc, pointer v)
670 #define mk_tagged_value(SC, X, A, B) (X)
672 #define get_tag(SC, V) (SC)->NIL
678 /* Allocate a new cell segment but do not make it available yet. */
680 _alloc_cellseg(scheme *sc, size_t len, void **alloc, pointer *cells)
685 if (adj < sizeof(struct cell))
686 adj = sizeof(struct cell);
688 cp = sc->malloc(len * sizeof(struct cell) + adj);
694 /* adjust in TYPE_BITS-bit boundary */
695 if (((uintptr_t) cp) % adj != 0)
696 cp = (void *) (adj * ((uintptr_t) cp / adj + 1));
702 /* allocate new cell segment */
703 static int alloc_cellseg(scheme *sc, int n) {
710 for (k = 0; k < n; k++) {
711 if (sc->last_cell_seg >= CELL_NSEGMENT - 1)
713 i = ++sc->last_cell_seg;
714 if (_alloc_cellseg(sc, CELL_SEGSIZE, &sc->alloc_seg[i], &newp)) {
718 /* insert new segment in address order */
719 sc->cell_seg[i] = newp;
720 while (i > 0 && sc->cell_seg[i - 1] > sc->cell_seg[i]) {
722 sc->cell_seg[i] = sc->cell_seg[i - 1];
723 sc->cell_seg[--i] = p;
725 sc->fcells += CELL_SEGSIZE;
726 last = newp + CELL_SEGSIZE - 1;
727 for (p = newp; p <= last; p++) {
732 /* insert new cells in address order on free list */
733 if (sc->free_cell == sc->NIL || p < sc->free_cell) {
734 cdr(last) = sc->free_cell;
735 sc->free_cell = newp;
738 while (cdr(p) != sc->NIL && newp > cdr(p))
749 /* Controlling the garbage collector.
751 * Every time a cell is allocated, the interpreter may run out of free
752 * cells and do a garbage collection. This is problematic because it
753 * might garbage collect objects that have been allocated, but are not
754 * yet made available to the interpreter.
756 * Previously, we would plug such newly allocated cells into the list
757 * of newly allocated objects rooted at car(sc->sink), but that
758 * requires allocating yet another cell increasing pressure on the
759 * memory management system.
761 * A faster alternative is to preallocate the cells needed for an
762 * operation and make sure the garbage collection is not run until all
763 * allocated objects are plugged in. This can be done with gc_disable
767 /* The garbage collector is enabled if the inhibit counter is
771 /* For now we provide a way to disable this optimization for
772 * benchmarking and because it produces slightly smaller code. */
773 #ifndef USE_GC_LOCKING
774 # define USE_GC_LOCKING 1
777 /* To facilitate nested calls to gc_disable, functions that allocate
778 * more than one cell may define a macro, e.g. foo_allocates. This
779 * macro can be used to compute the amount of preallocation at the
780 * call site with the help of this macro. */
781 #define gc_reservations(fn) fn ## _allocates
785 /* Report a shortage in reserved cells, and terminate the program. */
787 gc_reservation_failure(struct scheme *sc)
791 "insufficient reservation\n")
794 "insufficient reservation in line %d\n",
795 sc->reserved_lineno);
800 /* Disable the garbage collection and reserve the given number of
801 * cells. gc_disable may be nested, but the enclosing reservation
802 * must include the reservations of all nested calls. Note: You must
803 * re-enable the gc before calling Error_X. */
805 _gc_disable(struct scheme *sc, size_t reserve, int lineno)
807 if (sc->inhibit_gc == 0) {
808 reserve_cells(sc, (reserve));
809 sc->reserved_cells = (reserve);
813 sc->reserved_lineno = lineno;
815 } else if (sc->reserved_cells < (reserve))
816 gc_reservation_failure (sc);
819 #define gc_disable(sc, reserve) \
820 _gc_disable (sc, reserve, __LINE__)
822 /* Enable the garbage collector. */
823 #define gc_enable(sc) \
825 assert(sc->inhibit_gc); \
826 sc->inhibit_gc -= 1; \
829 /* Test whether the garbage collector is enabled. */
830 #define gc_enabled(sc) \
831 (sc->inhibit_gc == GC_ENABLED)
833 /* Consume a reserved cell. */
834 #define gc_consume(sc) \
836 assert(! gc_enabled (sc)); \
837 if (sc->reserved_cells == 0) \
838 gc_reservation_failure (sc); \
839 sc->reserved_cells -= 1; \
842 #else /* USE_GC_LOCKING */
844 #define gc_disable(sc, reserve) (void) 0
845 #define gc_enable(sc) (void) 0
846 #define gc_enabled(sc) 1
847 #define gc_consume(sc) (void) 0
849 #endif /* USE_GC_LOCKING */
851 static INLINE pointer get_cell_x(scheme *sc, pointer a, pointer b) {
852 if (! gc_enabled (sc) || sc->free_cell != sc->NIL) {
853 pointer x = sc->free_cell;
854 if (! gc_enabled (sc))
856 sc->free_cell = cdr(x);
860 assert (gc_enabled (sc));
861 return _get_cell (sc, a, b);
865 /* get new cell. parameter a, b is marked by gc. */
866 static pointer _get_cell(scheme *sc, pointer a, pointer b) {
873 assert (gc_enabled (sc));
874 if (sc->free_cell == sc->NIL) {
875 const int min_to_be_recovered = sc->last_cell_seg*8;
877 if (sc->fcells < min_to_be_recovered
878 || sc->free_cell == sc->NIL) {
879 /* if only a few recovered, get more to avoid fruitless gc's */
880 if (!alloc_cellseg(sc,1) && sc->free_cell == sc->NIL) {
887 sc->free_cell = cdr(x);
892 /* make sure that there is a given number of cells free */
893 static pointer reserve_cells(scheme *sc, int n) {
898 /* Are there enough cells available? */
899 if (sc->fcells < n) {
900 /* If not, try gc'ing some */
901 gc(sc, sc->NIL, sc->NIL);
902 if (sc->fcells < n) {
903 /* If there still aren't, try getting more heap */
904 if (!alloc_cellseg(sc,1)) {
909 if (sc->fcells < n) {
910 /* If all fail, report failure */
918 static pointer get_consecutive_cells(scheme *sc, int n) {
921 if(sc->no_memory) { return sc->sink; }
923 /* Are there any cells available? */
924 x=find_consecutive_cells(sc,n);
925 if (x != sc->NIL) { return x; }
927 /* If not, try gc'ing some */
928 gc(sc, sc->NIL, sc->NIL);
929 x=find_consecutive_cells(sc,n);
930 if (x != sc->NIL) { return x; }
932 /* If there still aren't, try getting more heap */
933 if (!alloc_cellseg(sc,1))
939 x=find_consecutive_cells(sc,n);
940 if (x != sc->NIL) { return x; }
942 /* If all fail, report failure */
947 static int count_consecutive_cells(pointer x, int needed) {
952 if(n>needed) return n;
957 static pointer find_consecutive_cells(scheme *sc, int n) {
962 while(*pp!=sc->NIL) {
963 cnt=count_consecutive_cells(*pp,n);
975 /* Free a cell. This is dangerous. Only free cells that are not
978 free_cell(scheme *sc, pointer a)
980 cdr(a) = sc->free_cell;
985 /* Free a cell and retrieve its content. This is dangerous. Only
986 * free cells that are not referenced. */
988 free_cons(scheme *sc, pointer a, pointer *r_car, pointer *r_cdr)
995 /* To retain recent allocs before interpreter knows about them -
998 static void push_recent_alloc(scheme *sc, pointer recent, pointer extra)
1000 pointer holder = get_cell_x(sc, recent, extra);
1001 typeflag(holder) = T_PAIR | T_IMMUTABLE;
1002 car(holder) = recent;
1003 cdr(holder) = car(sc->sink);
1004 car(sc->sink) = holder;
1007 static INLINE void ok_to_freely_gc(scheme *sc)
1009 pointer a = car(sc->sink), next;
1010 car(sc->sink) = sc->NIL;
1011 while (a != sc->NIL)
1019 static pointer get_cell(scheme *sc, pointer a, pointer b)
1021 pointer cell = get_cell_x(sc, a, b);
1022 /* For right now, include "a" and "b" in "cell" so that gc doesn't
1023 think they are garbage. */
1024 /* Tentatively record it as a pair so gc understands it. */
1025 typeflag(cell) = T_PAIR;
1028 if (gc_enabled (sc))
1029 push_recent_alloc(sc, cell, sc->NIL);
1033 static pointer get_vector_object(scheme *sc, int len, pointer init)
1035 pointer cells = get_consecutive_cells(sc, vector_size(len));
1036 if(sc->no_memory) { return sc->sink; }
1037 /* Record it as a vector so that gc understands it. */
1038 typeflag(cells) = (T_VECTOR | T_ATOM | T_FINALIZE);
1039 vector_length(cells) = len;
1040 fill_vector(cells,init);
1041 if (gc_enabled (sc))
1042 push_recent_alloc(sc, cells, sc->NIL);
1046 /* Medium level cell allocation */
1048 /* get new cons cell */
1049 pointer _cons(scheme *sc, pointer a, pointer b, int immutable) {
1050 pointer x = get_cell(sc,a, b);
1052 typeflag(x) = T_PAIR;
1061 /* ========== oblist implementation ========== */
1063 #ifndef USE_OBJECT_LIST
1065 static int hash_fn(const char *key, int table_size);
1067 static pointer oblist_initial_value(scheme *sc)
1069 /* There are about 768 symbols used after loading the
1071 return mk_vector(sc, 1009);
1074 /* Add a new symbol NAME at SLOT. SLOT must be obtained using
1075 * oblist_find_by_name, and no insertion must be done between
1076 * obtaining the SLOT and calling this function. Returns the new
1078 static pointer oblist_add_by_name(scheme *sc, const char *name, pointer *slot)
1080 #define oblist_add_by_name_allocates 3
1083 gc_disable(sc, gc_reservations (oblist_add_by_name));
1084 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
1085 typeflag(x) = T_SYMBOL;
1086 setimmutable(car(x));
1087 *slot = immutable_cons(sc, x, *slot);
1092 /* Lookup the symbol NAME. Returns the symbol, or NIL if it does not
1093 * exist. In that case, SLOT points to the point where the new symbol
1094 * is to be inserted. */
1095 static INLINE pointer
1096 oblist_find_by_name(scheme *sc, const char *name, pointer **slot)
1103 location = hash_fn(name, vector_length(sc->oblist));
1104 for (*slot = vector_elem_slot(sc->oblist, location), x = **slot;
1105 x != sc->NIL; *slot = &cdr(x), x = **slot) {
1106 s = symname(car(x));
1107 /* case-insensitive, per R5RS section 2. */
1108 d = stricmp(name, s);
1110 return car(x); /* Hit. */
1117 static pointer oblist_all_symbols(scheme *sc)
1121 pointer ob_list = sc->NIL;
1123 for (i = 0; i < vector_length(sc->oblist); i++) {
1124 for (x = vector_elem(sc->oblist, i); x != sc->NIL; x = cdr(x)) {
1125 ob_list = cons(sc, x, ob_list);
1133 static pointer oblist_initial_value(scheme *sc)
1138 /* Lookup the symbol NAME. Returns the symbol, or NIL if it does not
1139 * exist. In that case, SLOT points to the point where the new symbol
1140 * is to be inserted. */
1141 static INLINE pointer
1142 oblist_find_by_name(scheme *sc, const char *name, pointer **slot)
1148 for (*slot = &sc->oblist, x = **slot; x != sc->NIL; *slot = &cdr(x), x = **slot) {
1149 s = symname(car(x));
1150 /* case-insensitive, per R5RS section 2. */
1151 d = stricmp(name, s);
1153 return car(x); /* Hit. */
1160 /* Add a new symbol NAME at SLOT. SLOT must be obtained using
1161 * oblist_find_by_name, and no insertion must be done between
1162 * obtaining the SLOT and calling this function. Returns the new
1164 static pointer oblist_add_by_name(scheme *sc, const char *name, pointer *slot)
1166 #define oblist_add_by_name_allocates 3
1169 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
1170 typeflag(x) = T_SYMBOL;
1171 setimmutable(car(x));
1172 *slot = immutable_cons(sc, x, *slot);
1175 static pointer oblist_all_symbols(scheme *sc)
1182 static pointer mk_port(scheme *sc, port *p) {
1183 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1185 typeflag(x) = T_PORT|T_ATOM|T_FINALIZE;
1190 pointer mk_foreign_func(scheme *sc, foreign_func f) {
1191 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1193 typeflag(x) = (T_FOREIGN | T_ATOM);
1198 pointer mk_foreign_object(scheme *sc, const foreign_object_vtable *vtable, void *data) {
1199 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1201 typeflag(x) = (T_FOREIGN_OBJECT | T_ATOM | T_FINALIZE);
1202 x->_object._foreign_object._vtable=vtable;
1203 x->_object._foreign_object._data = data;
1207 INTERFACE pointer mk_character(scheme *sc, int c) {
1208 pointer x = get_cell(sc,sc->NIL, sc->NIL);
1210 typeflag(x) = (T_CHARACTER | T_ATOM);
1211 ivalue_unchecked(x)= c;
1218 #if USE_SMALL_INTEGERS
1220 /* s_save assumes that all opcodes can be expressed as a small
1222 #define MAX_SMALL_INTEGER OP_MAXDEFINED
1225 initialize_small_integers(scheme *sc)
1228 if (_alloc_cellseg(sc, MAX_SMALL_INTEGER, &sc->integer_alloc,
1229 &sc->integer_cells))
1232 for (i = 0; i < MAX_SMALL_INTEGER; i++) {
1233 pointer x = &sc->integer_cells[i];
1234 typeflag(x) = T_NUMBER | T_ATOM | MARK;
1235 ivalue_unchecked(x) = i;
1242 static INLINE pointer
1243 mk_small_integer(scheme *sc, long n)
1245 #define mk_small_integer_allocates 0
1246 assert(0 <= n && n < MAX_SMALL_INTEGER);
1247 return &sc->integer_cells[n];
1251 #define mk_small_integer_allocates 1
1252 #define mk_small_integer mk_integer
1256 /* get number atom (integer) */
1257 INTERFACE pointer mk_integer(scheme *sc, long n) {
1260 #if USE_SMALL_INTEGERS
1261 if (0 <= n && n < MAX_SMALL_INTEGER)
1262 return mk_small_integer(sc, n);
1265 x = get_cell(sc,sc->NIL, sc->NIL);
1266 typeflag(x) = (T_NUMBER | T_ATOM);
1267 ivalue_unchecked(x)= n;
1274 INTERFACE pointer mk_real(scheme *sc, double n) {
1275 pointer x = get_cell(sc,sc->NIL, sc->NIL);
1277 typeflag(x) = (T_NUMBER | T_ATOM);
1278 rvalue_unchecked(x)= n;
1283 static pointer mk_number(scheme *sc, num n) {
1285 return mk_integer(sc,n.value.ivalue);
1287 return mk_real(sc,n.value.rvalue);
1291 /* allocate name to string area */
1292 static char *store_string(scheme *sc, int len_str, const char *str, char fill) {
1295 q=(char*)sc->malloc(len_str+1);
1301 memcpy (q, str, len_str);
1304 memset(q, fill, len_str);
1310 /* get new string */
1311 INTERFACE pointer mk_string(scheme *sc, const char *str) {
1312 return mk_counted_string(sc,str,strlen(str));
1315 INTERFACE pointer mk_counted_string(scheme *sc, const char *str, int len) {
1316 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1317 typeflag(x) = (T_STRING | T_ATOM | T_FINALIZE);
1318 strvalue(x) = store_string(sc,len,str,0);
1323 INTERFACE pointer mk_empty_string(scheme *sc, int len, char fill) {
1324 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1325 typeflag(x) = (T_STRING | T_ATOM | T_FINALIZE);
1326 strvalue(x) = store_string(sc,len,0,fill);
1331 INTERFACE static pointer mk_vector(scheme *sc, int len)
1332 { return get_vector_object(sc,len,sc->NIL); }
1334 INTERFACE static void fill_vector(pointer vec, pointer obj) {
1336 assert (is_vector (vec));
1337 for(i = 0; i < vector_length(vec); i++) {
1338 vec->_object._vector._elements[i] = obj;
1342 INTERFACE static pointer *vector_elem_slot(pointer vec, int ielem) {
1343 assert (is_vector (vec));
1344 assert (ielem < vector_length(vec));
1345 return &vec->_object._vector._elements[ielem];
1348 INTERFACE static pointer vector_elem(pointer vec, int ielem) {
1349 assert (is_vector (vec));
1350 assert (ielem < vector_length(vec));
1351 return vec->_object._vector._elements[ielem];
1354 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a) {
1355 assert (is_vector (vec));
1356 assert (ielem < vector_length(vec));
1357 vec->_object._vector._elements[ielem] = a;
1361 /* get new symbol */
1362 INTERFACE pointer mk_symbol(scheme *sc, const char *name) {
1363 #define mk_symbol_allocates oblist_add_by_name_allocates
1367 /* first check oblist */
1368 x = oblist_find_by_name(sc, name, &slot);
1372 x = oblist_add_by_name(sc, name, slot);
1377 INTERFACE pointer gensym(scheme *sc) {
1382 for(; sc->gensym_cnt<LONG_MAX; sc->gensym_cnt++) {
1383 snprintf(name,40,"gensym-%ld",sc->gensym_cnt);
1385 /* first check oblist */
1386 x = oblist_find_by_name(sc, name, &slot);
1391 x = oblist_add_by_name(sc, name, slot);
1399 /* double the size of the string buffer */
1400 static int expand_strbuff(scheme *sc) {
1401 size_t new_size = sc->strbuff_size * 2;
1402 char *new_buffer = sc->malloc(new_size);
1403 if (new_buffer == 0) {
1407 memcpy(new_buffer, sc->strbuff, sc->strbuff_size);
1408 sc->free(sc->strbuff);
1409 sc->strbuff = new_buffer;
1410 sc->strbuff_size = new_size;
1414 /* make symbol or number atom from string */
1415 static pointer mk_atom(scheme *sc, char *q) {
1417 int has_dec_point=0;
1423 while ((next = strstr(next, "::")) != 0) {
1424 /* Keep looking for the last occurrence. */
1431 return cons(sc, sc->COLON_HOOK,
1435 cons(sc, mk_symbol(sc, strlwr(p + 2)),
1437 cons(sc, mk_atom(sc, q), sc->NIL)));
1443 if ((c == '+') || (c == '-')) {
1450 return (mk_symbol(sc, strlwr(q)));
1452 } else if (c == '.') {
1456 return (mk_symbol(sc, strlwr(q)));
1458 } else if (!isdigit(c)) {
1459 return (mk_symbol(sc, strlwr(q)));
1462 for ( ; (c = *p) != 0; ++p) {
1465 if(!has_dec_point) {
1470 else if ((c == 'e') || (c == 'E')) {
1472 has_dec_point = 1; /* decimal point illegal
1475 if ((*p == '-') || (*p == '+') || isdigit(*p)) {
1480 return (mk_symbol(sc, strlwr(q)));
1484 return mk_real(sc,atof(q));
1486 return (mk_integer(sc, atol(q)));
1490 static pointer mk_sharp_const(scheme *sc, char *name) {
1492 char tmp[STRBUFFSIZE];
1494 if (!strcmp(name, "t"))
1496 else if (!strcmp(name, "f"))
1498 else if (*name == 'o') {/* #o (octal) */
1499 snprintf(tmp, STRBUFFSIZE, "0%s", name+1);
1500 sscanf(tmp, "%lo", (long unsigned *)&x);
1501 return (mk_integer(sc, x));
1502 } else if (*name == 'd') { /* #d (decimal) */
1503 sscanf(name+1, "%ld", (long int *)&x);
1504 return (mk_integer(sc, x));
1505 } else if (*name == 'x') { /* #x (hex) */
1506 snprintf(tmp, STRBUFFSIZE, "0x%s", name+1);
1507 sscanf(tmp, "%lx", (long unsigned *)&x);
1508 return (mk_integer(sc, x));
1509 } else if (*name == 'b') { /* #b (binary) */
1510 x = binary_decode(name+1);
1511 return (mk_integer(sc, x));
1512 } else if (*name == '\\') { /* #\w (character) */
1514 if(stricmp(name+1,"space")==0) {
1516 } else if(stricmp(name+1,"newline")==0) {
1518 } else if(stricmp(name+1,"return")==0) {
1520 } else if(stricmp(name+1,"tab")==0) {
1522 } else if(name[1]=='x' && name[2]!=0) {
1524 if(sscanf(name+2,"%x",(unsigned int *)&c1)==1 && c1 < UCHAR_MAX) {
1530 } else if(is_ascii_name(name+1,&c)) {
1533 } else if(name[2]==0) {
1538 return mk_character(sc,c);
1543 /* ========== garbage collector ========== */
1546 * We use algorithm E (Knuth, The Art of Computer Programming Vol.1,
1547 * sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm,
1550 static void mark(pointer a) {
1558 for (i = 0; i < vector_length(p); i++) {
1559 mark(p->_object._vector._elements[i]);
1563 else if (is_port(p)) {
1564 port *pt = p->_object._port;
1565 mark(pt->curr_line);
1569 /* Mark tag if p has one. */
1576 if (q && !is_mark(q)) {
1577 setatom(p); /* a note that we have moved car */
1583 E5: q = cdr(p); /* down cdr */
1584 if (q && !is_mark(q)) {
1590 E6: /* up. Undo the link switching from steps E4 and E5. */
1608 /* garbage collection. parameter a, b is marked. */
1609 static void gc(scheme *sc, pointer a, pointer b) {
1613 assert (gc_enabled (sc));
1615 if(sc->gc_verbose) {
1616 putstr(sc, "gc...");
1619 /* mark system globals */
1621 mark(sc->global_env);
1623 /* mark current registers */
1628 dump_stack_mark(sc);
1631 mark(sc->save_inport);
1634 for (i = 0; i <= sc->file_i; i++) {
1635 mark(sc->load_stack[i].filename);
1636 mark(sc->load_stack[i].curr_line);
1639 /* Mark recent objects the interpreter doesn't know about yet. */
1640 mark(car(sc->sink));
1641 /* Mark any older stuff above nested C calls */
1644 /* mark variables a, b */
1648 /* garbage collect */
1651 sc->free_cell = sc->NIL;
1652 /* free-list is kept sorted by address so as to maintain consecutive
1653 ranges, if possible, for use with vectors. Here we scan the cells
1654 (which are also kept sorted by address) downwards to build the
1655 free-list in sorted order.
1657 for (i = sc->last_cell_seg; i >= 0; i--) {
1658 p = sc->cell_seg[i] + CELL_SEGSIZE;
1659 while (--p >= sc->cell_seg[i]) {
1660 if ((typeflag(p) & 1) == 0)
1661 /* All types have the LSB set. This is not a typeflag. */
1667 if (typeflag(p) & T_FINALIZE) {
1668 finalize_cell(sc, p);
1673 cdr(p) = sc->free_cell;
1679 if (sc->gc_verbose) {
1681 snprintf(msg,80,"done: %ld cells were recovered.\n", sc->fcells);
1686 static void finalize_cell(scheme *sc, pointer a) {
1688 sc->free(strvalue(a));
1689 } else if(is_port(a)) {
1690 if(a->_object._port->kind&port_file
1691 && a->_object._port->rep.stdio.closeit) {
1692 port_close(sc,a,port_input|port_output);
1693 } else if (a->_object._port->kind & port_srfi6) {
1694 sc->free(a->_object._port->rep.string.start);
1696 sc->free(a->_object._port);
1697 } else if(is_foreign_object(a)) {
1698 a->_object._foreign_object._vtable->finalize(sc, a->_object._foreign_object._data);
1699 } else if (is_vector(a)) {
1701 for (i = vector_size(vector_length(a)) - 1; i > 0; i--) {
1705 cdr(p) = sc->free_cell;
1714 port_clear_location (scheme *sc, port *p)
1716 p->curr_line = sc->NIL;
1717 p->filename = sc->NIL;
1721 port_increment_current_line (scheme *sc, port *p, long delta)
1727 mk_integer(sc, ivalue_unchecked(p->curr_line) + delta);
1731 port_init_location (scheme *sc, port *p, pointer name)
1733 p->curr_line = mk_integer(sc, 0);
1734 p->filename = name ? name : mk_string(sc, "<unknown>");
1740 port_clear_location (scheme *sc, port *p)
1745 port_increment_current_line (scheme *sc, port *p, long delta)
1750 port_init_location (scheme *sc, port *p, pointer name)
1756 /* ========== Routines for Reading ========== */
1758 static int file_push(scheme *sc, pointer fname) {
1761 if (sc->file_i == MAXFIL-1)
1763 fin = fopen(string_value(fname), "r");
1766 sc->load_stack[sc->file_i].kind=port_file|port_input;
1767 sc->load_stack[sc->file_i].rep.stdio.file=fin;
1768 sc->load_stack[sc->file_i].rep.stdio.closeit=1;
1769 sc->nesting_stack[sc->file_i]=0;
1770 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1771 port_init_location(sc, &sc->load_stack[sc->file_i], fname);
1776 static void file_pop(scheme *sc) {
1777 if(sc->file_i != 0) {
1778 sc->nesting=sc->nesting_stack[sc->file_i];
1779 port_close(sc,sc->loadport,port_input);
1780 port_clear_location(sc, &sc->load_stack[sc->file_i]);
1782 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1786 static int file_interactive(scheme *sc) {
1787 return sc->file_i==0 && sc->load_stack[0].rep.stdio.file==stdin
1788 && sc->inport->_object._port->kind&port_file;
1791 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop) {
1795 if(prop==(port_input|port_output)) {
1797 } else if(prop==port_output) {
1806 pt=port_rep_from_file(sc,f,prop);
1807 pt->rep.stdio.closeit=1;
1808 port_init_location(sc, pt, mk_string(sc, fn));
1812 static pointer port_from_filename(scheme *sc, const char *fn, int prop) {
1814 pt=port_rep_from_filename(sc,fn,prop);
1818 return mk_port(sc,pt);
1821 static port *port_rep_from_file(scheme *sc, FILE *f, int prop)
1825 pt = (port *)sc->malloc(sizeof *pt);
1829 pt->kind = port_file | prop;
1830 pt->rep.stdio.file = f;
1831 pt->rep.stdio.closeit = 0;
1832 port_init_location(sc, pt, NULL);
1836 static pointer port_from_file(scheme *sc, FILE *f, int prop) {
1838 pt=port_rep_from_file(sc,f,prop);
1842 return mk_port(sc,pt);
1845 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1847 pt=(port*)sc->malloc(sizeof(port));
1851 pt->kind=port_string|prop;
1852 pt->rep.string.start=start;
1853 pt->rep.string.curr=start;
1854 pt->rep.string.past_the_end=past_the_end;
1855 port_init_location(sc, pt, NULL);
1859 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1861 pt=port_rep_from_string(sc,start,past_the_end,prop);
1865 return mk_port(sc,pt);
1868 #define BLOCK_SIZE 256
1870 static port *port_rep_from_scratch(scheme *sc) {
1873 pt=(port*)sc->malloc(sizeof(port));
1877 start=sc->malloc(BLOCK_SIZE);
1881 memset(start,' ',BLOCK_SIZE-1);
1882 start[BLOCK_SIZE-1]='\0';
1883 pt->kind=port_string|port_output|port_srfi6;
1884 pt->rep.string.start=start;
1885 pt->rep.string.curr=start;
1886 pt->rep.string.past_the_end=start+BLOCK_SIZE-1;
1887 port_init_location(sc, pt, NULL);
1891 static pointer port_from_scratch(scheme *sc) {
1893 pt=port_rep_from_scratch(sc);
1897 return mk_port(sc,pt);
1900 static void port_close(scheme *sc, pointer p, int flag) {
1901 port *pt=p->_object._port;
1903 if((pt->kind & (port_input|port_output))==0) {
1904 /* Cleanup is here so (close-*-port) functions could work too */
1905 port_clear_location(sc, pt);
1906 if(pt->kind&port_file) {
1907 fclose(pt->rep.stdio.file);
1913 /* get new character from input file */
1914 static int inchar(scheme *sc) {
1918 pt = sc->inport->_object._port;
1919 if(pt->kind & port_saw_EOF)
1921 c = basic_inchar(pt);
1922 if(c == EOF && sc->inport == sc->loadport) {
1923 /* Instead, set port_saw_EOF */
1924 pt->kind |= port_saw_EOF;
1933 static int basic_inchar(port *pt) {
1934 if(pt->kind & port_file) {
1935 return fgetc(pt->rep.stdio.file);
1937 if(*pt->rep.string.curr == 0 ||
1938 pt->rep.string.curr == pt->rep.string.past_the_end) {
1941 return *pt->rep.string.curr++;
1946 /* back character to input buffer */
1947 static void backchar(scheme *sc, int c) {
1950 pt=sc->inport->_object._port;
1951 if(pt->kind&port_file) {
1952 ungetc(c,pt->rep.stdio.file);
1954 if(pt->rep.string.curr!=pt->rep.string.start) {
1955 --pt->rep.string.curr;
1960 static int realloc_port_string(scheme *sc, port *p)
1962 char *start=p->rep.string.start;
1963 size_t old_size = p->rep.string.past_the_end - start;
1964 size_t new_size=p->rep.string.past_the_end-start+1+BLOCK_SIZE;
1965 char *str=sc->malloc(new_size);
1967 memset(str,' ',new_size-1);
1968 str[new_size-1]='\0';
1969 memcpy(str, start, old_size);
1970 p->rep.string.start=str;
1971 p->rep.string.past_the_end=str+new_size-1;
1972 p->rep.string.curr-=start-str;
1980 INTERFACE void putstr(scheme *sc, const char *s) {
1981 port *pt=sc->outport->_object._port;
1982 if(pt->kind&port_file) {
1983 fputs(s,pt->rep.stdio.file);
1986 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
1987 *pt->rep.string.curr++=*s;
1988 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
1989 *pt->rep.string.curr++=*s;
1995 static void putchars(scheme *sc, const char *s, int len) {
1996 port *pt=sc->outport->_object._port;
1997 if(pt->kind&port_file) {
1998 fwrite(s,1,len,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 INTERFACE void putcharacter(scheme *sc, int c) {
2011 port *pt=sc->outport->_object._port;
2012 if(pt->kind&port_file) {
2013 fputc(c,pt->rep.stdio.file);
2015 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
2016 *pt->rep.string.curr++=c;
2017 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
2018 *pt->rep.string.curr++=c;
2023 /* read characters up to delimiter, but cater to character constants */
2024 static char *readstr_upto(scheme *sc, char *delim) {
2025 char *p = sc->strbuff;
2027 while ((p - sc->strbuff < sc->strbuff_size) &&
2028 !is_one_of(delim, (*p++ = inchar(sc))));
2030 if(p == sc->strbuff+2 && p[-2] == '\\') {
2039 /* read string expression "xxx...xxx" */
2040 static pointer readstrexp(scheme *sc) {
2041 char *p = sc->strbuff;
2044 enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state=st_ok;
2051 if(p-sc->strbuff > (sc->strbuff_size)-1) {
2052 ptrdiff_t offset = p - sc->strbuff;
2053 if (expand_strbuff(sc) != 0) {
2056 p = sc->strbuff + offset;
2066 return mk_counted_string(sc,sc->strbuff,p-sc->strbuff);
2115 if(c>='0' && c<='F') {
2119 c1=(c1<<4)+c-'A'+10;
2133 if (c < '0' || c > '7')
2141 if (state==st_oct2 && c1 >= 32)
2146 if (state == st_oct1)
2160 /* check c is in chars */
2161 static INLINE int is_one_of(char *s, int c) {
2162 if(c==EOF) return 1;
2169 /* skip white characters */
2170 static INLINE int skipspace(scheme *sc) {
2171 int c = 0, curr_line = 0;
2179 } while (isspace(c));
2182 port_increment_current_line(sc, &sc->load_stack[sc->file_i], curr_line);
2193 static int token(scheme *sc) {
2196 if(c == EOF) { return (TOK_EOF); }
2197 switch (c=inchar(sc)) {
2201 return (TOK_LPAREN);
2203 return (TOK_RPAREN);
2206 if(is_one_of(" \n\t",c)) {
2216 while ((c=inchar(sc)) != '\n' && c!=EOF)
2220 port_increment_current_line(sc, &sc->load_stack[sc->file_i], 1);
2223 { return (TOK_EOF); }
2225 { return (token(sc));}
2227 return (TOK_DQUOTE);
2229 return (TOK_BQUOTE);
2231 if ((c=inchar(sc)) == '@') {
2232 return (TOK_ATMARK);
2241 } else if(c == '!') {
2242 while ((c=inchar(sc)) != '\n' && c!=EOF)
2246 port_increment_current_line(sc, &sc->load_stack[sc->file_i], 1);
2249 { return (TOK_EOF); }
2251 { return (token(sc));}
2254 if(is_one_of(" tfodxb\\",c)) {
2255 return TOK_SHARP_CONST;
2266 /* ========== Routines for Printing ========== */
2267 #define ok_abbrev(x) (is_pair(x) && cdr(x) == sc->NIL)
2269 static void printslashstring(scheme *sc, char *p, int len) {
2271 unsigned char *s=(unsigned char*)p;
2272 putcharacter(sc,'"');
2273 for ( i=0; i<len; i++) {
2274 if(*s==0xff || *s=='"' || *s<' ' || *s=='\\') {
2275 putcharacter(sc,'\\');
2278 putcharacter(sc,'"');
2281 putcharacter(sc,'n');
2284 putcharacter(sc,'t');
2287 putcharacter(sc,'r');
2290 putcharacter(sc,'\\');
2294 putcharacter(sc,'x');
2296 putcharacter(sc,d+'0');
2298 putcharacter(sc,d-10+'A');
2302 putcharacter(sc,d+'0');
2304 putcharacter(sc,d-10+'A');
2309 putcharacter(sc,*s);
2313 putcharacter(sc,'"');
2318 static void printatom(scheme *sc, pointer l, int f) {
2321 atom2str(sc,l,f,&p,&len);
2326 /* Uses internal buffer unless string pointer is already available */
2327 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen) {
2332 } else if (l == sc->T) {
2334 } else if (l == sc->F) {
2336 } else if (l == sc->EOF_OBJ) {
2338 } else if (is_port(l)) {
2340 } else if (is_number(l)) {
2342 if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */ {
2343 if(num_is_integer(l)) {
2344 snprintf(p, STRBUFFSIZE, "%ld", ivalue_unchecked(l));
2346 snprintf(p, STRBUFFSIZE, "%.10g", rvalue_unchecked(l));
2347 /* r5rs says there must be a '.' (unless 'e'?) */
2348 f = strcspn(p, ".e");
2350 p[f] = '.'; /* not found, so add '.0' at the end */
2359 snprintf(p, STRBUFFSIZE, "%lx", v);
2361 snprintf(p, STRBUFFSIZE, "-%lx", -v);
2362 } else if (f == 8) {
2364 snprintf(p, STRBUFFSIZE, "%lo", v);
2366 snprintf(p, STRBUFFSIZE, "-%lo", -v);
2367 } else if (f == 2) {
2368 unsigned long b = (v < 0) ? -v : v;
2369 p = &p[STRBUFFSIZE-1];
2371 do { *--p = (b&1) ? '1' : '0'; b >>= 1; } while (b != 0);
2372 if (v < 0) *--p = '-';
2375 } else if (is_string(l)) {
2378 *plen = strlength(l);
2380 } else { /* Hack, uses the fact that printing is needed */
2383 printslashstring(sc, strvalue(l), strlength(l));
2386 } else if (is_character(l)) {
2412 snprintf(p,STRBUFFSIZE, "#\\%s",charnames[c]);
2417 snprintf(p,STRBUFFSIZE,"#\\x%x",c);
2421 snprintf(p,STRBUFFSIZE,"#\\%c",c);
2425 } else if (is_symbol(l)) {
2427 } else if (is_proc(l)) {
2429 snprintf(p,STRBUFFSIZE,"#<%s PROCEDURE %ld>", procname(l),procnum(l));
2430 } else if (is_macro(l)) {
2432 } else if (is_closure(l)) {
2434 } else if (is_promise(l)) {
2436 } else if (is_foreign(l)) {
2438 snprintf(p,STRBUFFSIZE,"#<FOREIGN PROCEDURE %ld>", procnum(l));
2439 } else if (is_continuation(l)) {
2440 p = "#<CONTINUATION>";
2441 } else if (is_foreign_object(l)) {
2443 l->_object._foreign_object._vtable->to_string(sc, p, STRBUFFSIZE, l->_object._foreign_object._data);
2450 /* ========== Routines for Evaluation Cycle ========== */
2452 /* make closure. c is code. e is environment */
2453 static pointer mk_closure(scheme *sc, pointer c, pointer e) {
2454 pointer x = get_cell(sc, c, e);
2456 typeflag(x) = T_CLOSURE;
2462 /* make continuation. */
2463 static pointer mk_continuation(scheme *sc, pointer d) {
2464 pointer x = get_cell(sc, sc->NIL, d);
2466 typeflag(x) = T_CONTINUATION;
2471 static pointer list_star(scheme *sc, pointer d) {
2473 if(cdr(d)==sc->NIL) {
2476 p=cons(sc,car(d),cdr(d));
2478 while(cdr(cdr(p))!=sc->NIL) {
2479 d=cons(sc,car(p),cdr(p));
2480 if(cdr(cdr(p))!=sc->NIL) {
2488 /* reverse list -- produce new list */
2489 static pointer reverse(scheme *sc, pointer term, pointer list) {
2490 /* a must be checked by gc */
2491 pointer a = list, p = term;
2493 for ( ; is_pair(a); a = cdr(a)) {
2494 p = cons(sc, car(a), p);
2499 /* reverse list --- in-place */
2500 static pointer reverse_in_place(scheme *sc, pointer term, pointer list) {
2501 pointer p = list, result = term, q;
2503 while (p != sc->NIL) {
2512 /* append list -- produce new list (in reverse order) */
2513 static pointer revappend(scheme *sc, pointer a, pointer b) {
2517 while (is_pair(p)) {
2518 result = cons(sc, car(p), result);
2526 return sc->F; /* signal an error */
2529 /* equivalence of atoms */
2530 int eqv(pointer a, pointer b) {
2533 return (strvalue(a) == strvalue(b));
2536 } else if (is_number(a)) {
2538 if (num_is_integer(a) == num_is_integer(b))
2539 return num_eq(nvalue(a),nvalue(b));
2542 } else if (is_character(a)) {
2543 if (is_character(b))
2544 return charvalue(a)==charvalue(b);
2547 } else if (is_port(a)) {
2552 } else if (is_proc(a)) {
2554 return procnum(a)==procnum(b);
2562 /* true or false value macro */
2563 /* () is #t in R5RS */
2564 #define is_true(p) ((p) != sc->F)
2565 #define is_false(p) ((p) == sc->F)
2567 /* ========== Environment implementation ========== */
2569 #if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
2571 static int hash_fn(const char *key, int table_size)
2573 unsigned int hashed = 0;
2575 int bits_per_int = sizeof(unsigned int)*8;
2577 for (c = key; *c; c++) {
2578 /* letters have about 5 bits in them */
2579 hashed = (hashed<<5) | (hashed>>(bits_per_int-5));
2582 return hashed % table_size;
2586 /* Compares A and B. Returns an integer less than, equal to, or
2587 * greater than zero if A is stored at a memory location that is
2588 * numerical less than, equal to, or greater than that of B. */
2590 pointercmp(pointer a, pointer b)
2592 uintptr_t a_n = (uintptr_t) a;
2593 uintptr_t b_n = (uintptr_t) b;
2602 #ifndef USE_ALIST_ENV
2605 * In this implementation, each frame of the environment may be
2606 * a hash table: a vector of alists hashed by variable name.
2607 * In practice, we use a vector only for the initial frame;
2608 * subsequent frames are too small and transient for the lookup
2609 * speed to out-weigh the cost of making a new vector.
2612 static void new_frame_in_env(scheme *sc, pointer old_env)
2616 /* The interaction-environment has about 480 variables in it. */
2617 if (old_env == sc->NIL) {
2618 new_frame = mk_vector(sc, 751);
2620 new_frame = sc->NIL;
2624 sc->envir = immutable_cons(sc, new_frame, old_env);
2626 setenvironment(sc->envir);
2629 /* Insert (VARIABLE, VALUE) at SSLOT. SSLOT must be obtained using
2630 * find_slot_spec_in_env, and no insertion must be done between
2631 * obtaining SSLOT and the call to this function. */
2632 static INLINE void new_slot_spec_in_env(scheme *sc,
2633 pointer variable, pointer value,
2636 #define new_slot_spec_in_env_allocates 2
2638 gc_disable(sc, gc_reservations (new_slot_spec_in_env));
2639 slot = immutable_cons(sc, variable, value);
2640 *sslot = immutable_cons(sc, slot, *sslot);
2644 /* Find the slot in ENV under the key HDL. If ALL is given, look in
2645 * all environments enclosing ENV. If the lookup fails, and SSLOT is
2646 * given, the position where the new slot has to be inserted is stored
2649 find_slot_spec_in_env(scheme *sc, pointer env, pointer hdl, int all, pointer **sslot)
2655 assert(is_symbol(hdl));
2657 for (x = env; x != sc->NIL; x = cdr(x)) {
2658 if (is_vector(car(x))) {
2659 location = hash_fn(symname(hdl), vector_length(car(x)));
2660 sl = vector_elem_slot(car(x), location);
2664 for (y = *sl ; y != sc->NIL; sl = &cdr(y), y = *sl) {
2665 d = pointercmp(caar(y), hdl);
2667 return car(y); /* Hit. */
2672 if (x == env && sslot)
2673 *sslot = sl; /* Insert here. */
2676 return sc->NIL; /* Miss, and stop looking. */
2679 return sc->NIL; /* Not found in any environment. */
2682 #else /* USE_ALIST_ENV */
2684 static INLINE void new_frame_in_env(scheme *sc, pointer old_env)
2686 sc->envir = immutable_cons(sc, sc->NIL, old_env);
2687 setenvironment(sc->envir);
2690 /* Insert (VARIABLE, VALUE) at SSLOT. SSLOT must be obtained using
2691 * find_slot_spec_in_env, and no insertion must be done between
2692 * obtaining SSLOT and the call to this function. */
2693 static INLINE void new_slot_spec_in_env(scheme *sc,
2694 pointer variable, pointer value,
2697 #define new_slot_spec_in_env_allocates 2
2698 assert(is_symbol(variable));
2699 *sslot = immutable_cons(sc, immutable_cons(sc, variable, value), *sslot);
2702 /* Find the slot in ENV under the key HDL. If ALL is given, look in
2703 * all environments enclosing ENV. If the lookup fails, and SSLOT is
2704 * given, the position where the new slot has to be inserted is stored
2707 find_slot_spec_in_env(scheme *sc, pointer env, pointer hdl, int all, pointer **sslot)
2712 assert(is_symbol(hdl));
2714 for (x = env; x != sc->NIL; x = cdr(x)) {
2715 for (sl = &car(x), y = *sl; y != sc->NIL; sl = &cdr(y), y = *sl) {
2716 d = pointercmp(caar(y), hdl);
2718 return car(y); /* Hit. */
2723 if (x == env && sslot)
2724 *sslot = sl; /* Insert here. */
2727 return sc->NIL; /* Miss, and stop looking. */
2730 return sc->NIL; /* Not found in any environment. */
2733 #endif /* USE_ALIST_ENV else */
2735 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
2737 return find_slot_spec_in_env(sc, env, hdl, all, NULL);
2740 static INLINE void new_slot_in_env(scheme *sc, pointer variable, pointer value)
2742 #define new_slot_in_env_allocates new_slot_spec_in_env_allocates
2745 assert(is_symbol(variable));
2746 slot = find_slot_spec_in_env(sc, sc->envir, variable, 0, &sslot);
2747 assert(slot == sc->NIL);
2748 new_slot_spec_in_env(sc, variable, value, sslot);
2751 static INLINE void set_slot_in_env(scheme *sc, pointer slot, pointer value)
2757 static INLINE pointer slot_value_in_env(pointer slot)
2762 /* ========== Evaluation Cycle ========== */
2765 static pointer _Error_1(scheme *sc, const char *s, pointer a) {
2766 const char *str = s;
2770 pointer hdl=sc->ERROR_HOOK;
2774 char sbuf[STRBUFFSIZE];
2777 history = history_flatten(sc);
2780 /* make sure error is not in REPL */
2781 if (((sc->load_stack[sc->file_i].kind & port_file) == 0
2782 || sc->load_stack[sc->file_i].rep.stdio.file != stdin)) {
2787 if (history != sc->NIL && has_tag(car(history))
2788 && (tag = get_tag(sc, car(history)))
2789 && is_string(car(tag)) && is_integer(cdr(tag))) {
2790 fname = string_value(car(tag));
2791 ln = ivalue_unchecked(cdr(tag));
2793 fname = string_value(sc->load_stack[sc->file_i].filename);
2794 ln = ivalue_unchecked(sc->load_stack[sc->file_i].curr_line);
2797 /* should never happen */
2798 if(!fname) fname = "<unknown>";
2800 /* we started from 0 */
2802 snprintf(sbuf, STRBUFFSIZE, "%s:%i: %s", fname, ln, s);
2804 str = (const char*)sbuf;
2809 x=find_slot_in_env(sc,sc->envir,hdl,1);
2811 sc->code = cons(sc, cons(sc, sc->QUOTE,
2812 cons(sc, history, sc->NIL)),
2815 sc->code = cons(sc, cons(sc, sc->QUOTE, cons(sc, a, sc->NIL)),
2818 sc->code = cons(sc, sc->F, sc->code);
2820 sc->code = cons(sc, mk_string(sc, str), sc->code);
2821 setimmutable(car(sc->code));
2822 sc->code = cons(sc, slot_value_in_env(x), sc->code);
2823 sc->op = (int)OP_EVAL;
2829 sc->args = cons(sc, (a), sc->NIL);
2833 sc->args = cons(sc, mk_string(sc, str), sc->args);
2834 setimmutable(car(sc->args));
2835 sc->op = (int)OP_ERR0;
2838 #define Error_1(sc,s, a) return _Error_1(sc,s,a)
2839 #define Error_0(sc,s) return _Error_1(sc,s,0)
2841 /* Too small to turn into function */
2843 # define END } while (0)
2847 /* Flags. The interpreter has a flags field. When the interpreter
2848 * pushes a frame to the dump stack, it is encoded with the opcode.
2849 * Therefore, we do not use the least significant byte. */
2851 /* Masks used to encode and decode opcode and flags. */
2852 #define S_OP_MASK 0x000000ff
2853 #define S_FLAG_MASK 0xffffff00
2855 /* Set if the interpreter evaluates an expression in a tail context
2856 * (see R5RS, section 3.5). If a function, procedure, or continuation
2857 * is invoked while this flag is set, the call is recorded as tail
2858 * call in the history buffer. */
2859 #define S_FLAG_TAIL_CONTEXT 0x00000100
2862 #define s_set_flag(sc, f) \
2864 (sc)->flags |= S_FLAG_ ## f; \
2868 #define s_clear_flag(sc, f) \
2870 (sc)->flags &= ~ S_FLAG_ ## f; \
2873 /* Check if flag F is set. */
2874 #define s_get_flag(sc, f) \
2875 !!((sc)->flags & S_FLAG_ ## f)
2879 /* Bounce back to Eval_Cycle and execute A. */
2880 #define s_goto(sc,a) BEGIN \
2881 sc->op = (int)(a); \
2884 #if USE_THREADED_CODE
2886 /* Do not bounce back to Eval_Cycle but execute A by jumping directly
2887 * to it. Only applicable if A is part of the same dispatch
2889 #define s_thread_to(sc, a) \
2895 /* Define a label OP and emit a case statement for OP. For use in the
2896 * dispatch functions. The slightly peculiar goto that is never
2897 * executed avoids warnings about unused labels. */
2898 #define CASE(OP) if (0) goto OP; OP: case OP
2900 #else /* USE_THREADED_CODE */
2901 #define s_thread_to(sc, a) s_goto(sc, a)
2902 #define CASE(OP) case OP
2903 #endif /* USE_THREADED_CODE */
2905 /* Return to the previous frame on the dump stack, setting the current
2907 #define s_return(sc, a) return _s_return(sc, a, 0)
2909 /* Return to the previous frame on the dump stack, setting the current
2910 * value to A, and re-enable the garbage collector. */
2911 #define s_return_enable_gc(sc, a) return _s_return(sc, a, 1)
2913 static INLINE void dump_stack_reset(scheme *sc)
2918 static INLINE void dump_stack_initialize(scheme *sc)
2920 dump_stack_reset(sc);
2923 static void dump_stack_free(scheme *sc)
2928 static pointer _s_return(scheme *sc, pointer a, int enable_gc) {
2929 pointer dump = sc->dump;
2935 if (dump == sc->NIL)
2937 free_cons(sc, dump, &op, &dump);
2938 v = (unsigned long) ivalue_unchecked(op);
2939 sc->op = (int) (v & S_OP_MASK);
2940 sc->flags = v & S_FLAG_MASK;
2941 #ifdef USE_SMALL_INTEGERS
2942 if (v < MAX_SMALL_INTEGER) {
2943 /* This is a small integer, we must not free it. */
2945 /* Normal integer. Recover the cell. */
2948 free_cons(sc, dump, &sc->args, &dump);
2949 free_cons(sc, dump, &sc->envir, &dump);
2950 free_cons(sc, dump, &sc->code, &sc->dump);
2954 static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) {
2955 #define s_save_allocates 5
2957 unsigned long v = sc->flags | ((unsigned long) op);
2958 gc_disable(sc, gc_reservations (s_save));
2959 dump = cons(sc, sc->envir, cons(sc, (code), sc->dump));
2960 dump = cons(sc, (args), dump);
2961 sc->dump = cons(sc, mk_integer(sc, (long) v), dump);
2965 static INLINE void dump_stack_mark(scheme *sc)
2975 history_free(scheme *sc)
2977 sc->free(sc->history.m);
2978 sc->history.tailstacks = sc->NIL;
2979 sc->history.callstack = sc->NIL;
2983 history_init(scheme *sc, size_t N, size_t M)
2986 struct history *h = &sc->history;
2991 assert ((N & h->mask_N) == 0);
2995 assert ((M & h->mask_M) == 0);
2997 h->callstack = mk_vector(sc, N);
2998 if (h->callstack == sc->sink)
3001 h->tailstacks = mk_vector(sc, N);
3002 for (i = 0; i < N; i++) {
3003 pointer tailstack = mk_vector(sc, M);
3004 if (tailstack == sc->sink)
3006 set_vector_elem(h->tailstacks, i, tailstack);
3009 h->m = sc->malloc(N * sizeof *h->m);
3013 for (i = 0; i < N; i++)
3024 history_mark(scheme *sc)
3026 struct history *h = &sc->history;
3028 mark(h->tailstacks);
3031 #define add_mod(a, b, mask) (((a) + (b)) & (mask))
3032 #define sub_mod(a, b, mask) add_mod(a, (mask) + 1 - (b), mask)
3035 tailstack_clear(scheme *sc, pointer v)
3037 assert(is_vector(v));
3039 fill_vector(v, sc->NIL);
3043 callstack_pop(scheme *sc)
3045 struct history *h = &sc->history;
3049 if (h->callstack == sc->NIL)
3052 item = vector_elem(h->callstack, n);
3053 /* Clear our frame so that it can be gc'ed and we don't run into it
3054 * when walking the history. */
3055 set_vector_elem(h->callstack, n, sc->NIL);
3056 tailstack_clear(sc, vector_elem(h->tailstacks, n));
3058 /* Exit from the frame. */
3059 h->n = sub_mod(h->n, 1, h->mask_N);
3065 callstack_push(scheme *sc, pointer item)
3067 struct history *h = &sc->history;
3070 if (h->callstack == sc->NIL)
3073 /* Enter a new frame. */
3074 n = h->n = add_mod(n, 1, h->mask_N);
3076 /* Initialize tail stack. */
3077 tailstack_clear(sc, vector_elem(h->tailstacks, n));
3078 h->m[n] = h->mask_M;
3080 set_vector_elem(h->callstack, n, item);
3084 tailstack_push(scheme *sc, pointer item)
3086 struct history *h = &sc->history;
3090 if (h->callstack == sc->NIL)
3093 /* Enter a new tail frame. */
3094 m = h->m[n] = add_mod(m, 1, h->mask_M);
3095 set_vector_elem(vector_elem(h->tailstacks, n), m, item);
3099 tailstack_flatten(scheme *sc, pointer tailstack, size_t i, size_t n,
3102 struct history *h = &sc->history;
3108 if (acc == sc->sink)
3112 /* We reached the end, but we did not see a unused frame. Signal
3113 this using '... . */
3114 return cons(sc, mk_symbol(sc, "..."), acc);
3117 frame = vector_elem(tailstack, n);
3118 if (frame == sc->NIL) {
3119 /* A unused frame. We reached the end of the history. */
3124 acc = cons(sc, frame, acc);
3126 return tailstack_flatten(sc, tailstack, i - 1, sub_mod(n, 1, h->mask_M),
3131 callstack_flatten(scheme *sc, size_t i, size_t n, pointer acc)
3133 struct history *h = &sc->history;
3139 if (acc == sc->sink)
3143 /* We reached the end, but we did not see a unused frame. Signal
3144 this using '... . */
3145 return cons(sc, mk_symbol(sc, "..."), acc);
3148 frame = vector_elem(h->callstack, n);
3149 if (frame == sc->NIL) {
3150 /* A unused frame. We reached the end of the history. */
3154 /* First, emit the tail calls. */
3155 acc = tailstack_flatten(sc, vector_elem(h->tailstacks, n), h->M, h->m[n],
3159 acc = cons(sc, frame, acc);
3161 return callstack_flatten(sc, i - 1, sub_mod(n, 1, h->mask_N), acc);
3165 history_flatten(scheme *sc)
3167 struct history *h = &sc->history;
3170 if (h->callstack == sc->NIL)
3173 history = callstack_flatten(sc, h->N, h->n, sc->NIL);
3174 if (history == sc->sink)
3177 return reverse_in_place(sc, sc->NIL, history);
3183 #else /* USE_HISTORY */
3185 #define history_init(SC, A, B) (void) 0
3186 #define history_free(SC) (void) 0
3187 #define callstack_pop(SC) (void) 0
3188 #define callstack_push(SC, X) (void) 0
3189 #define tailstack_push(SC, X) (void) 0
3191 #endif /* USE_HISTORY */
3195 #define s_retbool(tf) s_return(sc,(tf) ? sc->T : sc->F)
3197 static pointer opexe_0(scheme *sc, enum scheme_opcodes op) {
3202 CASE(OP_LOAD): /* load */
3203 if(file_interactive(sc)) {
3204 fprintf(sc->outport->_object._port->rep.stdio.file,
3205 "Loading %s\n", strvalue(car(sc->args)));
3207 if (!file_push(sc, car(sc->args))) {
3208 Error_1(sc,"unable to open", car(sc->args));
3212 sc->args = mk_integer(sc,sc->file_i);
3213 s_thread_to(sc,OP_T0LVL);
3216 CASE(OP_T0LVL): /* top level */
3217 /* If we reached the end of file, this loop is done. */
3218 if(sc->loadport->_object._port->kind & port_saw_EOF)
3223 sc->nesting = sc->nesting_stack[0];
3229 s_return(sc,sc->value);
3234 /* If interactive, be nice to user. */
3235 if(file_interactive(sc))
3237 sc->envir = sc->global_env;
3238 dump_stack_reset(sc);
3243 /* Set up another iteration of REPL */
3245 sc->save_inport=sc->inport;
3246 sc->inport = sc->loadport;
3247 s_save(sc,OP_T0LVL, sc->NIL, sc->NIL);
3248 s_save(sc,OP_VALUEPRINT, sc->NIL, sc->NIL);
3249 s_save(sc,OP_T1LVL, sc->NIL, sc->NIL);
3250 s_thread_to(sc,OP_READ_INTERNAL);
3252 CASE(OP_T1LVL): /* top level */
3253 sc->code = sc->value;
3254 sc->inport=sc->save_inport;
3255 s_thread_to(sc,OP_EVAL);
3257 CASE(OP_READ_INTERNAL): /* internal read */
3258 sc->tok = token(sc);
3259 if(sc->tok==TOK_EOF)
3260 { s_return(sc,sc->EOF_OBJ); }
3261 s_goto(sc,OP_RDSEXPR);
3264 s_return(sc, gensym(sc));
3266 CASE(OP_VALUEPRINT): /* print evaluation result */
3267 /* OP_VALUEPRINT is always pushed, because when changing from
3268 non-interactive to interactive mode, it needs to be
3269 already on the stack */
3271 putstr(sc,"\nGives: ");
3273 if(file_interactive(sc)) {
3275 sc->args = sc->value;
3276 s_goto(sc,OP_P0LIST);
3278 s_return(sc,sc->value);
3281 CASE(OP_EVAL): /* main part of evaluation */
3284 /*s_save(sc,OP_VALUEPRINT,sc->NIL,sc->NIL);*/
3285 s_save(sc,OP_REAL_EVAL,sc->args,sc->code);
3287 putstr(sc,"\nEval: ");
3288 s_goto(sc,OP_P0LIST);
3293 if (is_symbol(sc->code)) { /* symbol */
3294 x=find_slot_in_env(sc,sc->envir,sc->code,1);
3296 s_return(sc,slot_value_in_env(x));
3298 Error_1(sc,"eval: unbound variable:", sc->code);
3300 } else if (is_pair(sc->code)) {
3301 if (is_syntax(x = car(sc->code))) { /* SYNTAX */
3302 sc->code = cdr(sc->code);
3303 s_goto(sc,syntaxnum(x));
3304 } else {/* first, eval top element and eval arguments */
3305 s_save(sc,OP_E0ARGS, sc->NIL, sc->code);
3306 /* If no macros => s_save(sc,OP_E1ARGS, sc->NIL, cdr(sc->code));*/
3307 sc->code = car(sc->code);
3308 s_clear_flag(sc, TAIL_CONTEXT);
3309 s_thread_to(sc,OP_EVAL);
3312 s_return(sc,sc->code);
3315 CASE(OP_E0ARGS): /* eval arguments */
3316 if (is_macro(sc->value)) { /* macro expansion */
3317 gc_disable(sc, 1 + gc_reservations (s_save));
3318 s_save(sc,OP_DOMACRO, sc->NIL, sc->NIL);
3319 sc->args = cons(sc,sc->code, sc->NIL);
3321 sc->code = sc->value;
3322 s_clear_flag(sc, TAIL_CONTEXT);
3323 s_thread_to(sc,OP_APPLY);
3326 sc->args = cons(sc, sc->code, sc->NIL);
3328 sc->code = cdr(sc->code);
3329 s_thread_to(sc,OP_E1ARGS);
3332 CASE(OP_E1ARGS): /* eval arguments */
3334 sc->args = cons(sc, sc->value, sc->args);
3336 if (is_pair(sc->code)) { /* continue */
3337 s_save(sc,OP_E1ARGS, sc->args, cdr(sc->code));
3338 sc->code = car(sc->code);
3340 s_clear_flag(sc, TAIL_CONTEXT);
3341 s_thread_to(sc,OP_EVAL);
3343 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3344 s_thread_to(sc,OP_APPLY_CODE);
3350 sc->tracing=ivalue(car(sc->args));
3352 s_return_enable_gc(sc, mk_integer(sc, tr));
3357 CASE(OP_CALLSTACK_POP): /* pop the call stack */
3359 s_return(sc, sc->value);
3362 CASE(OP_APPLY_CODE): /* apply 'cadr(args)' to 'cddr(args)',
3363 * record in the history as invoked from
3365 free_cons(sc, sc->args, &callsite, &sc->args);
3366 sc->code = car(sc->args);
3367 sc->args = cdr(sc->args);
3370 CASE(OP_APPLY): /* apply 'code' to 'args' */
3373 s_save(sc,OP_REAL_APPLY,sc->args,sc->code);
3375 /* sc->args=cons(sc,sc->code,sc->args);*/
3376 putstr(sc,"\nApply to: ");
3377 s_goto(sc,OP_P0LIST);
3380 CASE(OP_REAL_APPLY):
3383 if (op != OP_APPLY_CODE)
3384 callsite = sc->code;
3385 if (s_get_flag(sc, TAIL_CONTEXT)) {
3386 /* We are evaluating a tail call. */
3387 tailstack_push(sc, callsite);
3389 callstack_push(sc, callsite);
3390 s_save(sc, OP_CALLSTACK_POP, sc->NIL, sc->NIL);
3394 if (is_proc(sc->code)) {
3395 s_goto(sc,procnum(sc->code)); /* PROCEDURE */
3396 } else if (is_foreign(sc->code))
3398 /* Keep nested calls from GC'ing the arglist */
3399 push_recent_alloc(sc,sc->args,sc->NIL);
3400 x=sc->code->_object._ff(sc,sc->args);
3402 } else if (is_closure(sc->code) || is_macro(sc->code)
3403 || is_promise(sc->code)) { /* CLOSURE */
3404 /* Should not accept promise */
3405 /* make environment */
3406 new_frame_in_env(sc, closure_env(sc->code));
3407 for (x = car(closure_code(sc->code)), y = sc->args;
3408 is_pair(x); x = cdr(x), y = cdr(y)) {
3410 Error_1(sc, "not enough arguments, missing:", x);
3412 new_slot_in_env(sc, car(x), car(y));
3417 Error_0(sc, "too many arguments");
3419 } else if (is_symbol(x))
3420 new_slot_in_env(sc, x, y);
3422 Error_1(sc,"syntax error in closure: not a symbol:", x);
3424 sc->code = cdr(closure_code(sc->code));
3426 s_set_flag(sc, TAIL_CONTEXT);
3427 s_thread_to(sc,OP_BEGIN);
3428 } else if (is_continuation(sc->code)) { /* CONTINUATION */
3429 sc->dump = cont_dump(sc->code);
3430 s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL);
3432 Error_1(sc,"illegal function",sc->code);
3435 CASE(OP_DOMACRO): /* do macro */
3436 sc->code = sc->value;
3437 s_thread_to(sc,OP_EVAL);
3439 #if USE_COMPILE_HOOK
3440 CASE(OP_LAMBDA): /* lambda */
3441 /* If the hook is defined, apply it to sc->code, otherwise
3442 set sc->value fall through */
3444 pointer f=find_slot_in_env(sc,sc->envir,sc->COMPILE_HOOK,1);
3446 sc->value = sc->code;
3449 gc_disable(sc, 1 + gc_reservations (s_save));
3450 s_save(sc,OP_LAMBDA1,sc->args,sc->code);
3451 sc->args=cons(sc,sc->code,sc->NIL);
3453 sc->code=slot_value_in_env(f);
3454 s_thread_to(sc,OP_APPLY);
3459 CASE(OP_LAMBDA): /* lambda */
3460 sc->value = sc->code;
3466 s_return_enable_gc(sc, mk_closure(sc, sc->value, sc->envir));
3469 CASE(OP_MKCLOSURE): /* make-closure */
3471 if(car(x)==sc->LAMBDA) {
3474 if(cdr(sc->args)==sc->NIL) {
3480 s_return_enable_gc(sc, mk_closure(sc, x, y));
3482 CASE(OP_QUOTE): /* quote */
3483 s_return(sc,car(sc->code));
3485 CASE(OP_DEF0): /* define */
3486 if(is_immutable(car(sc->code)))
3487 Error_1(sc,"define: unable to alter immutable", car(sc->code));
3489 if (is_pair(car(sc->code))) {
3492 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
3496 sc->code = cadr(sc->code);
3498 if (!is_symbol(x)) {
3499 Error_0(sc,"variable is not a symbol");
3501 s_save(sc,OP_DEF1, sc->NIL, x);
3502 s_thread_to(sc,OP_EVAL);
3504 CASE(OP_DEF1): { /* define */
3506 x = find_slot_spec_in_env(sc, sc->envir, sc->code, 0, &sslot);
3508 set_slot_in_env(sc, x, sc->value);
3510 new_slot_spec_in_env(sc, sc->code, sc->value, sslot);
3512 s_return(sc,sc->code);
3515 CASE(OP_DEFP): /* defined? */
3517 if(cdr(sc->args)!=sc->NIL) {
3520 s_retbool(find_slot_in_env(sc,x,car(sc->args),1)!=sc->NIL);
3522 CASE(OP_SET0): /* set! */
3523 if(is_immutable(car(sc->code)))
3524 Error_1(sc,"set!: unable to alter immutable variable",car(sc->code));
3525 s_save(sc,OP_SET1, sc->NIL, car(sc->code));
3526 sc->code = cadr(sc->code);
3527 s_thread_to(sc,OP_EVAL);
3529 CASE(OP_SET1): /* set! */
3530 y=find_slot_in_env(sc,sc->envir,sc->code,1);
3532 set_slot_in_env(sc, y, sc->value);
3533 s_return(sc,sc->value);
3535 Error_1(sc,"set!: unbound variable:", sc->code);
3539 CASE(OP_BEGIN): /* begin */
3543 if (!is_pair(sc->code)) {
3544 s_return(sc,sc->code);
3547 last = cdr(sc->code) == sc->NIL;
3549 s_save(sc,OP_BEGIN, sc->NIL, cdr(sc->code));
3551 sc->code = car(sc->code);
3553 /* This is not the end of the list. This is not a tail
3555 s_clear_flag(sc, TAIL_CONTEXT);
3556 s_thread_to(sc,OP_EVAL);
3559 CASE(OP_IF0): /* if */
3560 s_save(sc,OP_IF1, sc->NIL, cdr(sc->code));
3561 sc->code = car(sc->code);
3562 s_clear_flag(sc, TAIL_CONTEXT);
3563 s_thread_to(sc,OP_EVAL);
3565 CASE(OP_IF1): /* if */
3566 if (is_true(sc->value))
3567 sc->code = car(sc->code);
3569 sc->code = cadr(sc->code); /* (if #f 1) ==> () because
3570 * car(sc->NIL) = sc->NIL */
3571 s_thread_to(sc,OP_EVAL);
3573 CASE(OP_LET0): /* let */
3575 sc->value = sc->code;
3576 sc->code = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code);
3577 s_thread_to(sc,OP_LET1);
3579 CASE(OP_LET1): /* let (calculate parameters) */
3580 gc_disable(sc, 1 + (is_pair(sc->code) ? gc_reservations (s_save) : 0));
3581 sc->args = cons(sc, sc->value, sc->args);
3582 if (is_pair(sc->code)) { /* continue */
3583 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
3585 Error_1(sc, "Bad syntax of binding spec in let :",
3588 s_save(sc,OP_LET1, sc->args, cdr(sc->code));
3590 sc->code = cadar(sc->code);
3592 s_clear_flag(sc, TAIL_CONTEXT);
3593 s_thread_to(sc,OP_EVAL);
3596 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3597 sc->code = car(sc->args);
3598 sc->args = cdr(sc->args);
3599 s_thread_to(sc,OP_LET2);
3602 CASE(OP_LET2): /* let */
3603 new_frame_in_env(sc, sc->envir);
3604 for (x = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code), y = sc->args;
3605 y != sc->NIL; x = cdr(x), y = cdr(y)) {
3606 new_slot_in_env(sc, caar(x), car(y));
3608 if (is_symbol(car(sc->code))) { /* named let */
3609 for (x = cadr(sc->code), sc->args = sc->NIL; x != sc->NIL; x = cdr(x)) {
3611 Error_1(sc, "Bad syntax of binding in let :", x);
3612 if (!is_list(sc, car(x)))
3613 Error_1(sc, "Bad syntax of binding in let :", car(x));
3615 sc->args = cons(sc, caar(x), sc->args);
3618 gc_disable(sc, 2 + gc_reservations (new_slot_in_env));
3619 x = mk_closure(sc, cons(sc, reverse_in_place(sc, sc->NIL, sc->args), cddr(sc->code)), sc->envir);
3620 new_slot_in_env(sc, car(sc->code), x);
3622 sc->code = cddr(sc->code);
3625 sc->code = cdr(sc->code);
3628 s_thread_to(sc,OP_BEGIN);
3630 CASE(OP_LET0AST): /* let* */
3631 if (car(sc->code) == sc->NIL) {
3632 new_frame_in_env(sc, sc->envir);
3633 sc->code = cdr(sc->code);
3634 s_thread_to(sc,OP_BEGIN);
3636 if(!is_pair(car(sc->code)) || !is_pair(caar(sc->code)) || !is_pair(cdaar(sc->code))) {
3637 Error_1(sc,"Bad syntax of binding spec in let* :",car(sc->code));
3639 s_save(sc,OP_LET1AST, cdr(sc->code), car(sc->code));
3640 sc->code = cadaar(sc->code);
3641 s_clear_flag(sc, TAIL_CONTEXT);
3642 s_thread_to(sc,OP_EVAL);
3644 CASE(OP_LET1AST): /* let* (make new frame) */
3645 new_frame_in_env(sc, sc->envir);
3646 s_thread_to(sc,OP_LET2AST);
3648 CASE(OP_LET2AST): /* let* (calculate parameters) */
3649 new_slot_in_env(sc, caar(sc->code), sc->value);
3650 sc->code = cdr(sc->code);
3651 if (is_pair(sc->code)) { /* continue */
3652 s_save(sc,OP_LET2AST, sc->args, sc->code);
3653 sc->code = cadar(sc->code);
3655 s_clear_flag(sc, TAIL_CONTEXT);
3656 s_thread_to(sc,OP_EVAL);
3658 sc->code = sc->args;
3660 s_thread_to(sc,OP_BEGIN);
3663 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3664 Error_0(sc,sc->strbuff);
3669 static pointer opexe_1(scheme *sc, enum scheme_opcodes op) {
3673 CASE(OP_LET0REC): /* letrec */
3674 new_frame_in_env(sc, sc->envir);
3676 sc->value = sc->code;
3677 sc->code = car(sc->code);
3678 s_thread_to(sc,OP_LET1REC);
3680 CASE(OP_LET1REC): /* letrec (calculate parameters) */
3682 sc->args = cons(sc, sc->value, sc->args);
3684 if (is_pair(sc->code)) { /* continue */
3685 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
3686 Error_1(sc, "Bad syntax of binding spec in letrec :",
3689 s_save(sc,OP_LET1REC, sc->args, cdr(sc->code));
3690 sc->code = cadar(sc->code);
3692 s_clear_flag(sc, TAIL_CONTEXT);
3695 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3696 sc->code = car(sc->args);
3697 sc->args = cdr(sc->args);
3698 s_thread_to(sc,OP_LET2REC);
3701 CASE(OP_LET2REC): /* letrec */
3702 for (x = car(sc->code), y = sc->args; y != sc->NIL; x = cdr(x), y = cdr(y)) {
3703 new_slot_in_env(sc, caar(x), car(y));
3705 sc->code = cdr(sc->code);
3707 s_goto(sc,OP_BEGIN);
3709 CASE(OP_COND0): /* cond */
3710 if (!is_pair(sc->code)) {
3711 Error_0(sc,"syntax error in cond");
3713 s_save(sc,OP_COND1, sc->NIL, sc->code);
3714 sc->code = caar(sc->code);
3715 s_clear_flag(sc, TAIL_CONTEXT);
3718 CASE(OP_COND1): /* cond */
3719 if (is_true(sc->value)) {
3720 if ((sc->code = cdar(sc->code)) == sc->NIL) {
3721 s_return(sc,sc->value);
3723 if(!sc->code || car(sc->code)==sc->FEED_TO) {
3724 if(!is_pair(cdr(sc->code))) {
3725 Error_0(sc,"syntax error in cond");
3728 x=cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL));
3729 sc->code=cons(sc,cadr(sc->code),cons(sc,x,sc->NIL));
3733 s_goto(sc,OP_BEGIN);
3735 if ((sc->code = cdr(sc->code)) == sc->NIL) {
3736 s_return(sc,sc->NIL);
3738 s_save(sc,OP_COND1, sc->NIL, sc->code);
3739 sc->code = caar(sc->code);
3740 s_clear_flag(sc, TAIL_CONTEXT);
3745 CASE(OP_DELAY): /* delay */
3747 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
3748 typeflag(x)=T_PROMISE;
3749 s_return_enable_gc(sc,x);
3751 CASE(OP_AND0): /* and */
3752 if (sc->code == sc->NIL) {
3755 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
3756 if (cdr(sc->code) != sc->NIL)
3757 s_clear_flag(sc, TAIL_CONTEXT);
3758 sc->code = car(sc->code);
3761 CASE(OP_AND1): /* and */
3762 if (is_false(sc->value)) {
3763 s_return(sc,sc->value);
3764 } else if (sc->code == sc->NIL) {
3765 s_return(sc,sc->value);
3767 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
3768 if (cdr(sc->code) != sc->NIL)
3769 s_clear_flag(sc, TAIL_CONTEXT);
3770 sc->code = car(sc->code);
3774 CASE(OP_OR0): /* or */
3775 if (sc->code == sc->NIL) {
3778 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
3779 if (cdr(sc->code) != sc->NIL)
3780 s_clear_flag(sc, TAIL_CONTEXT);
3781 sc->code = car(sc->code);
3784 CASE(OP_OR1): /* or */
3785 if (is_true(sc->value)) {
3786 s_return(sc,sc->value);
3787 } else if (sc->code == sc->NIL) {
3788 s_return(sc,sc->value);
3790 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
3791 if (cdr(sc->code) != sc->NIL)
3792 s_clear_flag(sc, TAIL_CONTEXT);
3793 sc->code = car(sc->code);
3797 CASE(OP_C0STREAM): /* cons-stream */
3798 s_save(sc,OP_C1STREAM, sc->NIL, cdr(sc->code));
3799 sc->code = car(sc->code);
3802 CASE(OP_C1STREAM): /* cons-stream */
3803 sc->args = sc->value; /* save sc->value to register sc->args for gc */
3805 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
3806 typeflag(x)=T_PROMISE;
3807 s_return_enable_gc(sc, cons(sc, sc->args, x));
3809 CASE(OP_MACRO0): /* macro */
3810 if (is_pair(car(sc->code))) {
3813 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
3817 sc->code = cadr(sc->code);
3819 if (!is_symbol(x)) {
3820 Error_0(sc,"variable is not a symbol");
3822 s_save(sc,OP_MACRO1, sc->NIL, x);
3825 CASE(OP_MACRO1): { /* macro */
3827 typeflag(sc->value) = T_MACRO;
3828 x = find_slot_spec_in_env(sc, sc->envir, sc->code, 0, &sslot);
3830 set_slot_in_env(sc, x, sc->value);
3832 new_slot_spec_in_env(sc, sc->code, sc->value, sslot);
3834 s_return(sc,sc->code);
3837 CASE(OP_CASE0): /* case */
3838 s_save(sc,OP_CASE1, sc->NIL, cdr(sc->code));
3839 sc->code = car(sc->code);
3840 s_clear_flag(sc, TAIL_CONTEXT);
3843 CASE(OP_CASE1): /* case */
3844 for (x = sc->code; x != sc->NIL; x = cdr(x)) {
3845 if (!is_pair(y = caar(x))) {
3848 for ( ; y != sc->NIL; y = cdr(y)) {
3849 if (eqv(car(y), sc->value)) {
3858 if (is_pair(caar(x))) {
3860 s_goto(sc,OP_BEGIN);
3862 s_save(sc,OP_CASE2, sc->NIL, cdar(x));
3867 s_return(sc,sc->NIL);
3870 CASE(OP_CASE2): /* case */
3871 if (is_true(sc->value)) {
3872 s_goto(sc,OP_BEGIN);
3874 s_return(sc,sc->NIL);
3877 CASE(OP_PAPPLY): /* apply */
3878 sc->code = car(sc->args);
3879 sc->args = list_star(sc,cdr(sc->args));
3880 /*sc->args = cadr(sc->args);*/
3881 s_goto(sc,OP_APPLY);
3883 CASE(OP_PEVAL): /* eval */
3884 if(cdr(sc->args)!=sc->NIL) {
3885 sc->envir=cadr(sc->args);
3887 sc->code = car(sc->args);
3890 CASE(OP_CONTINUATION): /* call-with-current-continuation */
3891 sc->code = car(sc->args);
3893 sc->args = cons(sc, mk_continuation(sc, sc->dump), sc->NIL);
3895 s_goto(sc,OP_APPLY);
3898 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3899 Error_0(sc,sc->strbuff);
3906 get_property(scheme *sc, pointer obj, pointer key)
3910 assert (is_symbol(obj));
3911 assert (is_symbol(key));
3913 for (x = symprop(obj); x != sc->NIL; x = cdr(x)) {
3925 set_property(scheme *sc, pointer obj, pointer key, pointer value)
3927 #define set_property_allocates 2
3930 assert (is_symbol(obj));
3931 assert (is_symbol(key));
3933 for (x = symprop(obj); x != sc->NIL; x = cdr(x)) {
3941 gc_disable(sc, gc_reservations(set_property));
3942 symprop(obj) = cons(sc, cons(sc, key, value), symprop(obj));
3950 static pointer opexe_2(scheme *sc, enum scheme_opcodes op) {
3959 CASE(OP_INEX2EX): /* inexact->exact */
3961 if(num_is_integer(x)) {
3963 } else if(modf(rvalue_unchecked(x),&dd)==0.0) {
3964 s_return(sc,mk_integer(sc,ivalue(x)));
3966 Error_1(sc,"inexact->exact: not integral:",x);
3971 s_return(sc, mk_real(sc, exp(rvalue(x))));
3975 s_return(sc, mk_real(sc, log(rvalue(x))));
3979 s_return(sc, mk_real(sc, sin(rvalue(x))));
3983 s_return(sc, mk_real(sc, cos(rvalue(x))));
3987 s_return(sc, mk_real(sc, tan(rvalue(x))));
3991 s_return(sc, mk_real(sc, asin(rvalue(x))));
3995 s_return(sc, mk_real(sc, acos(rvalue(x))));
3999 if(cdr(sc->args)==sc->NIL) {
4000 s_return(sc, mk_real(sc, atan(rvalue(x))));
4002 pointer y=cadr(sc->args);
4003 s_return(sc, mk_real(sc, atan2(rvalue(x),rvalue(y))));
4008 s_return(sc, mk_real(sc, sqrt(rvalue(x))));
4013 pointer y=cadr(sc->args);
4015 if (num_is_integer(x) && num_is_integer(y))
4017 /* This 'if' is an R5RS compatibility fix. */
4018 /* NOTE: Remove this 'if' fix for R6RS. */
4019 if (rvalue(x) == 0 && rvalue(y) < 0) {
4022 result = pow(rvalue(x),rvalue(y));
4024 /* Before returning integer result make sure we can. */
4025 /* If the test fails, result is too big for integer. */
4028 long result_as_long = (long)result;
4029 if (result != (double)result_as_long)
4033 s_return(sc, mk_real(sc, result));
4035 s_return(sc, mk_integer(sc, result));
4041 s_return(sc, mk_real(sc, floor(rvalue(x))));
4045 s_return(sc, mk_real(sc, ceil(rvalue(x))));
4047 CASE(OP_TRUNCATE ): {
4048 double rvalue_of_x ;
4050 rvalue_of_x = rvalue(x) ;
4051 if (rvalue_of_x > 0) {
4052 s_return(sc, mk_real(sc, floor(rvalue_of_x)));
4054 s_return(sc, mk_real(sc, ceil(rvalue_of_x)));
4060 if (num_is_integer(x))
4062 s_return(sc, mk_real(sc, round_per_R5RS(rvalue(x))));
4065 CASE(OP_ADD): /* + */
4067 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4068 v=num_add(v,nvalue(car(x)));
4071 s_return_enable_gc(sc, mk_number(sc, v));
4073 CASE(OP_MUL): /* * */
4075 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4076 v=num_mul(v,nvalue(car(x)));
4079 s_return_enable_gc(sc, mk_number(sc, v));
4081 CASE(OP_SUB): /* - */
4082 if(cdr(sc->args)==sc->NIL) {
4087 v = nvalue(car(sc->args));
4089 for (; x != sc->NIL; x = cdr(x)) {
4090 v=num_sub(v,nvalue(car(x)));
4093 s_return_enable_gc(sc, mk_number(sc, v));
4095 CASE(OP_DIV): /* / */
4096 if(cdr(sc->args)==sc->NIL) {
4101 v = nvalue(car(sc->args));
4103 for (; x != sc->NIL; x = cdr(x)) {
4104 if (!is_zero_double(rvalue(car(x))))
4105 v=num_div(v,nvalue(car(x)));
4107 Error_0(sc,"/: division by zero");
4111 s_return_enable_gc(sc, mk_number(sc, v));
4113 CASE(OP_INTDIV): /* quotient */
4114 if(cdr(sc->args)==sc->NIL) {
4119 v = nvalue(car(sc->args));
4121 for (; x != sc->NIL; x = cdr(x)) {
4122 if (ivalue(car(x)) != 0)
4123 v=num_intdiv(v,nvalue(car(x)));
4125 Error_0(sc,"quotient: division by zero");
4129 s_return_enable_gc(sc, mk_number(sc, v));
4131 CASE(OP_REM): /* remainder */
4132 v = nvalue(car(sc->args));
4133 if (ivalue(cadr(sc->args)) != 0)
4134 v=num_rem(v,nvalue(cadr(sc->args)));
4136 Error_0(sc,"remainder: division by zero");
4139 s_return_enable_gc(sc, mk_number(sc, v));
4141 CASE(OP_MOD): /* modulo */
4142 v = nvalue(car(sc->args));
4143 if (ivalue(cadr(sc->args)) != 0)
4144 v=num_mod(v,nvalue(cadr(sc->args)));
4146 Error_0(sc,"modulo: division by zero");
4149 s_return_enable_gc(sc, mk_number(sc, v));
4151 CASE(OP_CAR): /* car */
4152 s_return(sc,caar(sc->args));
4154 CASE(OP_CDR): /* cdr */
4155 s_return(sc,cdar(sc->args));
4157 CASE(OP_CONS): /* cons */
4158 cdr(sc->args) = cadr(sc->args);
4159 s_return(sc,sc->args);
4161 CASE(OP_SETCAR): /* set-car! */
4162 if(!is_immutable(car(sc->args))) {
4163 caar(sc->args) = cadr(sc->args);
4164 s_return(sc,car(sc->args));
4166 Error_0(sc,"set-car!: unable to alter immutable pair");
4169 CASE(OP_SETCDR): /* set-cdr! */
4170 if(!is_immutable(car(sc->args))) {
4171 cdar(sc->args) = cadr(sc->args);
4172 s_return(sc,car(sc->args));
4174 Error_0(sc,"set-cdr!: unable to alter immutable pair");
4177 CASE(OP_CHAR2INT): { /* char->integer */
4179 c=(char)ivalue(car(sc->args));
4181 s_return_enable_gc(sc, mk_integer(sc, (unsigned char) c));
4184 CASE(OP_INT2CHAR): { /* integer->char */
4186 c=(unsigned char)ivalue(car(sc->args));
4188 s_return_enable_gc(sc, mk_character(sc, (char) c));
4191 CASE(OP_CHARUPCASE): {
4193 c=(unsigned char)ivalue(car(sc->args));
4196 s_return_enable_gc(sc, mk_character(sc, (char) c));
4199 CASE(OP_CHARDNCASE): {
4201 c=(unsigned char)ivalue(car(sc->args));
4204 s_return_enable_gc(sc, mk_character(sc, (char) c));
4207 CASE(OP_STR2SYM): /* string->symbol */
4208 gc_disable(sc, gc_reservations (mk_symbol));
4209 s_return_enable_gc(sc, mk_symbol(sc, strvalue(car(sc->args))));
4211 CASE(OP_STR2ATOM): /* string->atom */ {
4212 char *s=strvalue(car(sc->args));
4214 if(cdr(sc->args)!=sc->NIL) {
4215 /* we know cadr(sc->args) is a natural number */
4216 /* see if it is 2, 8, 10, or 16, or error */
4217 pf = ivalue_unchecked(cadr(sc->args));
4218 if(pf == 16 || pf == 10 || pf == 8 || pf == 2) {
4226 Error_1(sc, "string->atom: bad base:", cadr(sc->args));
4227 } else if(*s=='#') /* no use of base! */ {
4228 s_return(sc, mk_sharp_const(sc, s+1));
4230 if (pf == 0 || pf == 10) {
4231 s_return(sc, mk_atom(sc, s));
4235 long iv = strtol(s,&ep,(int )pf);
4237 s_return(sc, mk_integer(sc, iv));
4240 s_return(sc, sc->F);
4246 CASE(OP_SYM2STR): /* symbol->string */
4248 x=mk_string(sc,symname(car(sc->args)));
4250 s_return_enable_gc(sc, x);
4252 CASE(OP_ATOM2STR): /* atom->string */ {
4255 if(cdr(sc->args)!=sc->NIL) {
4256 /* we know cadr(sc->args) is a natural number */
4257 /* see if it is 2, 8, 10, or 16, or error */
4258 pf = ivalue_unchecked(cadr(sc->args));
4259 if(is_number(x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2)) {
4267 Error_1(sc, "atom->string: bad base:", cadr(sc->args));
4268 } else if(is_number(x) || is_character(x) || is_string(x) || is_symbol(x)) {
4271 atom2str(sc,x,(int )pf,&p,&len);
4273 s_return_enable_gc(sc, mk_counted_string(sc, p, len));
4275 Error_1(sc, "atom->string: not an atom:", x);
4279 CASE(OP_MKSTRING): { /* make-string */
4283 len=ivalue(car(sc->args));
4285 if(cdr(sc->args)!=sc->NIL) {
4286 fill=charvalue(cadr(sc->args));
4289 s_return_enable_gc(sc, mk_empty_string(sc, len, (char) fill));
4292 CASE(OP_STRLEN): /* string-length */
4294 s_return_enable_gc(sc, mk_integer(sc, strlength(car(sc->args))));
4296 CASE(OP_STRREF): { /* string-ref */
4300 str=strvalue(car(sc->args));
4302 index=ivalue(cadr(sc->args));
4304 if(index>=strlength(car(sc->args))) {
4305 Error_1(sc,"string-ref: out of bounds:",cadr(sc->args));
4309 s_return_enable_gc(sc,
4310 mk_character(sc, ((unsigned char*) str)[index]));
4313 CASE(OP_STRSET): { /* string-set! */
4318 if(is_immutable(car(sc->args))) {
4319 Error_1(sc,"string-set!: unable to alter immutable string:",car(sc->args));
4321 str=strvalue(car(sc->args));
4323 index=ivalue(cadr(sc->args));
4324 if(index>=strlength(car(sc->args))) {
4325 Error_1(sc,"string-set!: out of bounds:",cadr(sc->args));
4328 c=charvalue(caddr(sc->args));
4331 s_return(sc,car(sc->args));
4334 CASE(OP_STRAPPEND): { /* string-append */
4335 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4340 /* compute needed length for new string */
4341 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4342 len += strlength(car(x));
4345 newstr = mk_empty_string(sc, len, ' ');
4346 /* store the contents of the argument strings into the new string */
4347 for (pos = strvalue(newstr), x = sc->args; x != sc->NIL;
4348 pos += strlength(car(x)), x = cdr(x)) {
4349 memcpy(pos, strvalue(car(x)), strlength(car(x)));
4351 s_return_enable_gc(sc, newstr);
4354 CASE(OP_SUBSTR): { /* substring */
4360 str=strvalue(car(sc->args));
4362 index0=ivalue(cadr(sc->args));
4364 if(index0>strlength(car(sc->args))) {
4365 Error_1(sc,"substring: start out of bounds:",cadr(sc->args));
4368 if(cddr(sc->args)!=sc->NIL) {
4369 index1=ivalue(caddr(sc->args));
4370 if(index1>strlength(car(sc->args)) || index1<index0) {
4371 Error_1(sc,"substring: end out of bounds:",caddr(sc->args));
4374 index1=strlength(car(sc->args));
4379 x=mk_empty_string(sc,len,' ');
4380 memcpy(strvalue(x),str+index0,len);
4383 s_return_enable_gc(sc, x);
4386 CASE(OP_VECTOR): { /* vector */
4389 int len=list_length(sc,sc->args);
4391 Error_1(sc,"vector: not a proper list:",sc->args);
4393 vec=mk_vector(sc,len);
4394 if(sc->no_memory) { s_return(sc, sc->sink); }
4395 for (x = sc->args, i = 0; is_pair(x); x = cdr(x), i++) {
4396 set_vector_elem(vec,i,car(x));
4401 CASE(OP_MKVECTOR): { /* make-vector */
4402 pointer fill=sc->NIL;
4406 len=ivalue(car(sc->args));
4408 if(cdr(sc->args)!=sc->NIL) {
4409 fill=cadr(sc->args);
4411 vec=mk_vector(sc,len);
4412 if(sc->no_memory) { s_return(sc, sc->sink); }
4414 fill_vector(vec,fill);
4419 CASE(OP_VECLEN): /* vector-length */
4421 s_return_enable_gc(sc, mk_integer(sc, vector_length(car(sc->args))));
4423 CASE(OP_VECREF): { /* vector-ref */
4426 index=ivalue(cadr(sc->args));
4428 if(index >= vector_length(car(sc->args))) {
4429 Error_1(sc,"vector-ref: out of bounds:",cadr(sc->args));
4432 s_return(sc,vector_elem(car(sc->args),index));
4435 CASE(OP_VECSET): { /* vector-set! */
4438 if(is_immutable(car(sc->args))) {
4439 Error_1(sc,"vector-set!: unable to alter immutable vector:",car(sc->args));
4442 index=ivalue(cadr(sc->args));
4443 if(index >= vector_length(car(sc->args))) {
4444 Error_1(sc,"vector-set!: out of bounds:",cadr(sc->args));
4447 set_vector_elem(car(sc->args),index,caddr(sc->args));
4448 s_return(sc,car(sc->args));
4452 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
4453 Error_0(sc,sc->strbuff);
4458 static int is_list(scheme *sc, pointer a)
4459 { return list_length(sc,a) >= 0; }
4465 dotted list: -2 minus length before dot
4467 int list_length(scheme *sc, pointer a) {
4474 if (fast == sc->NIL)
4480 if (fast == sc->NIL)
4487 /* Safe because we would have already returned if `fast'
4488 encountered a non-pair. */
4492 /* the fast pointer has looped back around and caught up
4493 with the slow pointer, hence the structure is circular,
4494 not of finite length, and therefore not a list */
4500 static pointer opexe_3(scheme *sc, enum scheme_opcodes op) {
4503 int (*comp_func)(num,num)=0;
4506 CASE(OP_NOT): /* not */
4507 s_retbool(is_false(car(sc->args)));
4508 CASE(OP_BOOLP): /* boolean? */
4509 s_retbool(car(sc->args) == sc->F || car(sc->args) == sc->T);
4510 CASE(OP_EOFOBJP): /* boolean? */
4511 s_retbool(car(sc->args) == sc->EOF_OBJ);
4512 CASE(OP_NULLP): /* null? */
4513 s_retbool(car(sc->args) == sc->NIL);
4514 CASE(OP_NUMEQ): /* = */
4515 CASE(OP_LESS): /* < */
4516 CASE(OP_GRE): /* > */
4517 CASE(OP_LEQ): /* <= */
4518 CASE(OP_GEQ): /* >= */
4520 case OP_NUMEQ: comp_func=num_eq; break;
4521 case OP_LESS: comp_func=num_lt; break;
4522 case OP_GRE: comp_func=num_gt; break;
4523 case OP_LEQ: comp_func=num_le; break;
4524 case OP_GEQ: comp_func=num_ge; break;
4525 default: assert (! "reached");
4531 for (; x != sc->NIL; x = cdr(x)) {
4532 if(!comp_func(v,nvalue(car(x)))) {
4538 CASE(OP_SYMBOLP): /* symbol? */
4539 s_retbool(is_symbol(car(sc->args)));
4540 CASE(OP_NUMBERP): /* number? */
4541 s_retbool(is_number(car(sc->args)));
4542 CASE(OP_STRINGP): /* string? */
4543 s_retbool(is_string(car(sc->args)));
4544 CASE(OP_INTEGERP): /* integer? */
4545 s_retbool(is_integer(car(sc->args)));
4546 CASE(OP_REALP): /* real? */
4547 s_retbool(is_number(car(sc->args))); /* All numbers are real */
4548 CASE(OP_CHARP): /* char? */
4549 s_retbool(is_character(car(sc->args)));
4550 #if USE_CHAR_CLASSIFIERS
4551 CASE(OP_CHARAP): /* char-alphabetic? */
4552 s_retbool(Cisalpha(ivalue(car(sc->args))));
4553 CASE(OP_CHARNP): /* char-numeric? */
4554 s_retbool(Cisdigit(ivalue(car(sc->args))));
4555 CASE(OP_CHARWP): /* char-whitespace? */
4556 s_retbool(Cisspace(ivalue(car(sc->args))));
4557 CASE(OP_CHARUP): /* char-upper-case? */
4558 s_retbool(Cisupper(ivalue(car(sc->args))));
4559 CASE(OP_CHARLP): /* char-lower-case? */
4560 s_retbool(Cislower(ivalue(car(sc->args))));
4562 CASE(OP_PORTP): /* port? */
4563 s_retbool(is_port(car(sc->args)));
4564 CASE(OP_INPORTP): /* input-port? */
4565 s_retbool(is_inport(car(sc->args)));
4566 CASE(OP_OUTPORTP): /* output-port? */
4567 s_retbool(is_outport(car(sc->args)));
4568 CASE(OP_PROCP): /* procedure? */
4570 * continuation should be procedure by the example
4571 * (call-with-current-continuation procedure?) ==> #t
4572 * in R^3 report sec. 6.9
4574 s_retbool(is_proc(car(sc->args)) || is_closure(car(sc->args))
4575 || is_continuation(car(sc->args)) || is_foreign(car(sc->args)));
4576 CASE(OP_PAIRP): /* pair? */
4577 s_retbool(is_pair(car(sc->args)));
4578 CASE(OP_LISTP): /* list? */
4579 s_retbool(list_length(sc,car(sc->args)) >= 0);
4581 CASE(OP_ENVP): /* environment? */
4582 s_retbool(is_environment(car(sc->args)));
4583 CASE(OP_VECTORP): /* vector? */
4584 s_retbool(is_vector(car(sc->args)));
4585 CASE(OP_EQ): /* eq? */
4586 s_retbool(car(sc->args) == cadr(sc->args));
4587 CASE(OP_EQV): /* eqv? */
4588 s_retbool(eqv(car(sc->args), cadr(sc->args)));
4590 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
4591 Error_0(sc,sc->strbuff);
4596 static pointer opexe_4(scheme *sc, enum scheme_opcodes op) {
4600 CASE(OP_FORCE): /* force */
4601 sc->code = car(sc->args);
4602 if (is_promise(sc->code)) {
4603 /* Should change type to closure here */
4604 s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code);
4606 s_goto(sc,OP_APPLY);
4608 s_return(sc,sc->code);
4611 CASE(OP_SAVE_FORCED): /* Save forced value replacing promise */
4612 memcpy(sc->code,sc->value,sizeof(struct cell));
4613 s_return(sc,sc->value);
4615 CASE(OP_WRITE): /* write */
4616 CASE(OP_DISPLAY): /* display */
4617 CASE(OP_WRITE_CHAR): /* write-char */
4618 if(is_pair(cdr(sc->args))) {
4619 if(cadr(sc->args)!=sc->outport) {
4620 x=cons(sc,sc->outport,sc->NIL);
4621 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
4622 sc->outport=cadr(sc->args);
4625 sc->args = car(sc->args);
4631 s_goto(sc,OP_P0LIST);
4633 CASE(OP_NEWLINE): /* newline */
4634 if(is_pair(sc->args)) {
4635 if(car(sc->args)!=sc->outport) {
4636 x=cons(sc,sc->outport,sc->NIL);
4637 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
4638 sc->outport=car(sc->args);
4644 CASE(OP_ERR0): /* error */
4646 if (!is_string(car(sc->args))) {
4647 sc->args=cons(sc,mk_string(sc," -- "),sc->args);
4648 setimmutable(car(sc->args));
4650 putstr(sc, "Error: ");
4651 putstr(sc, strvalue(car(sc->args)));
4652 sc->args = cdr(sc->args);
4653 s_thread_to(sc,OP_ERR1);
4655 CASE(OP_ERR1): /* error */
4657 if (sc->args != sc->NIL) {
4658 s_save(sc,OP_ERR1, cdr(sc->args), sc->NIL);
4659 sc->args = car(sc->args);
4661 s_goto(sc,OP_P0LIST);
4664 if(sc->interactive_repl) {
4665 s_goto(sc,OP_T0LVL);
4671 CASE(OP_REVERSE): /* reverse */
4672 s_return(sc,reverse(sc, sc->NIL, car(sc->args)));
4674 CASE(OP_LIST_STAR): /* list* */
4675 s_return(sc,list_star(sc,sc->args));
4677 CASE(OP_APPEND): /* append */
4684 /* cdr() in the while condition is not a typo. If car() */
4685 /* is used (append '() 'a) will return the wrong result.*/
4686 while (cdr(y) != sc->NIL) {
4687 x = revappend(sc, x, car(y));
4690 Error_0(sc, "non-list argument to append");
4694 s_return(sc, reverse_in_place(sc, car(y), x));
4697 CASE(OP_SET_SYMBOL_PROPERTY): /* set-symbol-property! */
4698 gc_disable(sc, gc_reservations(set_property));
4699 s_return_enable_gc(sc,
4700 set_property(sc, car(sc->args),
4701 cadr(sc->args), caddr(sc->args)));
4703 CASE(OP_SYMBOL_PROPERTY): /* symbol-property */
4704 s_return(sc, get_property(sc, car(sc->args), cadr(sc->args)));
4705 #endif /* USE_PLIST */
4708 CASE(OP_TAG_VALUE): { /* not exposed */
4709 /* This tags sc->value with car(sc->args). Useful to tag
4710 * results of opcode evaluations. */
4712 free_cons(sc, sc->args, &a, &b);
4713 free_cons(sc, b, &b, &c);
4714 assert(c == sc->NIL);
4715 s_return(sc, mk_tagged_value(sc, sc->value, a, b));
4718 CASE(OP_MK_TAGGED): /* make-tagged-value */
4719 if (is_vector(car(sc->args)))
4720 Error_0(sc, "cannot tag vector");
4721 s_return(sc, mk_tagged_value(sc, car(sc->args),
4722 car(cadr(sc->args)),
4723 cdr(cadr(sc->args))));
4725 CASE(OP_GET_TAG): /* get-tag */
4726 s_return(sc, get_tag(sc, car(sc->args)));
4727 #endif /* USE_TAGS */
4729 CASE(OP_QUIT): /* quit */
4730 if(is_pair(sc->args)) {
4731 sc->retcode=ivalue(car(sc->args));
4735 CASE(OP_GC): /* gc */
4736 gc(sc, sc->NIL, sc->NIL);
4739 CASE(OP_GCVERB): /* gc-verbose */
4740 { int was = sc->gc_verbose;
4742 sc->gc_verbose = (car(sc->args) != sc->F);
4746 CASE(OP_NEWSEGMENT): /* new-segment */
4747 if (!is_pair(sc->args) || !is_number(car(sc->args))) {
4748 Error_0(sc,"new-segment: argument must be a number");
4750 alloc_cellseg(sc, (int) ivalue(car(sc->args)));
4753 CASE(OP_OBLIST): /* oblist */
4754 s_return(sc, oblist_all_symbols(sc));
4756 CASE(OP_CURR_INPORT): /* current-input-port */
4757 s_return(sc,sc->inport);
4759 CASE(OP_CURR_OUTPORT): /* current-output-port */
4760 s_return(sc,sc->outport);
4762 CASE(OP_OPEN_INFILE): /* open-input-file */
4763 CASE(OP_OPEN_OUTFILE): /* open-output-file */
4764 CASE(OP_OPEN_INOUTFILE): /* open-input-output-file */ {
4768 case OP_OPEN_INFILE: prop=port_input; break;
4769 case OP_OPEN_OUTFILE: prop=port_output; break;
4770 case OP_OPEN_INOUTFILE: prop=port_input|port_output; break;
4771 default: assert (! "reached");
4773 p=port_from_filename(sc,strvalue(car(sc->args)),prop);
4779 default: assert (! "reached");
4782 #if USE_STRING_PORTS
4783 CASE(OP_OPEN_INSTRING): /* open-input-string */
4784 CASE(OP_OPEN_INOUTSTRING): /* open-input-output-string */ {
4788 case OP_OPEN_INSTRING: prop=port_input; break;
4789 case OP_OPEN_INOUTSTRING: prop=port_input|port_output; break;
4790 default: assert (! "reached");
4792 p=port_from_string(sc, strvalue(car(sc->args)),
4793 strvalue(car(sc->args))+strlength(car(sc->args)), prop);
4799 CASE(OP_OPEN_OUTSTRING): /* open-output-string */ {
4801 if(car(sc->args)==sc->NIL) {
4802 p=port_from_scratch(sc);
4807 p=port_from_string(sc, strvalue(car(sc->args)),
4808 strvalue(car(sc->args))+strlength(car(sc->args)),
4816 CASE(OP_GET_OUTSTRING): /* get-output-string */ {
4819 if ((p=car(sc->args)->_object._port)->kind&port_string) {
4823 size=p->rep.string.curr-p->rep.string.start+1;
4824 str=sc->malloc(size);
4828 memcpy(str,p->rep.string.start,size-1);
4830 s=mk_string(sc,str);
4839 CASE(OP_CLOSE_INPORT): /* close-input-port */
4840 port_close(sc,car(sc->args),port_input);
4843 CASE(OP_CLOSE_OUTPORT): /* close-output-port */
4844 port_close(sc,car(sc->args),port_output);
4847 CASE(OP_INT_ENV): /* interaction-environment */
4848 s_return(sc,sc->global_env);
4850 CASE(OP_CURR_ENV): /* current-environment */
4851 s_return(sc,sc->envir);
4857 static pointer opexe_5(scheme *sc, enum scheme_opcodes op) {
4860 if(sc->nesting!=0) {
4864 Error_1(sc,"unmatched parentheses:",mk_integer(sc,n));
4868 /* ========== reading part ========== */
4870 if(!is_pair(sc->args)) {
4871 s_goto(sc,OP_READ_INTERNAL);
4873 if(!is_inport(car(sc->args))) {
4874 Error_1(sc,"read: not an input port:",car(sc->args));
4876 if(car(sc->args)==sc->inport) {
4877 s_goto(sc,OP_READ_INTERNAL);
4880 sc->inport=car(sc->args);
4881 x=cons(sc,x,sc->NIL);
4882 s_save(sc,OP_SET_INPORT, x, sc->NIL);
4883 s_goto(sc,OP_READ_INTERNAL);
4885 CASE(OP_READ_CHAR): /* read-char */
4886 CASE(OP_PEEK_CHAR): /* peek-char */ {
4888 if(is_pair(sc->args)) {
4889 if(car(sc->args)!=sc->inport) {
4891 x=cons(sc,x,sc->NIL);
4892 s_save(sc,OP_SET_INPORT, x, sc->NIL);
4893 sc->inport=car(sc->args);
4898 s_return(sc,sc->EOF_OBJ);
4900 if(sc->op==OP_PEEK_CHAR) {
4903 s_return(sc,mk_character(sc,c));
4906 CASE(OP_CHAR_READY): /* char-ready? */ {
4907 pointer p=sc->inport;
4909 if(is_pair(sc->args)) {
4912 res=p->_object._port->kind&port_string;
4916 CASE(OP_SET_INPORT): /* set-input-port */
4917 sc->inport=car(sc->args);
4918 s_return(sc,sc->value);
4920 CASE(OP_SET_OUTPORT): /* set-output-port */
4921 sc->outport=car(sc->args);
4922 s_return(sc,sc->value);
4927 s_return(sc,sc->EOF_OBJ);
4930 s_save(sc,OP_RDVEC,sc->NIL,sc->NIL);
4933 sc->tok = token(sc);
4934 if (sc->tok == TOK_RPAREN) {
4935 s_return(sc,sc->NIL);
4936 } else if (sc->tok == TOK_DOT) {
4937 Error_0(sc,"syntax error: illegal dot expression");
4939 #if USE_TAGS && SHOW_ERROR_LINE
4943 sc->nesting_stack[sc->file_i]++;
4944 #if USE_TAGS && SHOW_ERROR_LINE
4945 filename = sc->load_stack[sc->file_i].filename;
4946 lineno = sc->load_stack[sc->file_i].curr_line;
4948 s_save(sc, OP_TAG_VALUE,
4949 cons(sc, filename, cons(sc, lineno, sc->NIL)),
4952 s_save(sc,OP_RDLIST, sc->NIL, sc->NIL);
4953 s_thread_to(sc,OP_RDSEXPR);
4956 s_save(sc,OP_RDQUOTE, sc->NIL, sc->NIL);
4957 sc->tok = token(sc);
4958 s_thread_to(sc,OP_RDSEXPR);
4960 sc->tok = token(sc);
4961 if(sc->tok==TOK_VEC) {
4962 s_save(sc,OP_RDQQUOTEVEC, sc->NIL, sc->NIL);
4964 s_thread_to(sc,OP_RDSEXPR);
4966 s_save(sc,OP_RDQQUOTE, sc->NIL, sc->NIL);
4968 s_thread_to(sc,OP_RDSEXPR);
4970 s_save(sc,OP_RDUNQUOTE, sc->NIL, sc->NIL);
4971 sc->tok = token(sc);
4972 s_thread_to(sc,OP_RDSEXPR);
4974 s_save(sc,OP_RDUQTSP, sc->NIL, sc->NIL);
4975 sc->tok = token(sc);
4976 s_thread_to(sc,OP_RDSEXPR);
4978 s_return(sc,mk_atom(sc, readstr_upto(sc, DELIMITERS)));
4982 Error_0(sc,"Error reading string");
4987 pointer f=find_slot_in_env(sc,sc->envir,sc->SHARP_HOOK,1);
4989 Error_0(sc,"undefined sharp expression");
4991 sc->code=cons(sc,slot_value_in_env(f),sc->NIL);
4995 case TOK_SHARP_CONST:
4996 if ((x = mk_sharp_const(sc, readstr_upto(sc, DELIMITERS))) == sc->NIL) {
4997 Error_0(sc,"undefined sharp expression");
5002 Error_0(sc,"syntax error: illegal token");
5008 sc->args = cons(sc, sc->value, sc->args);
5010 sc->tok = token(sc);
5011 if (sc->tok == TOK_EOF)
5012 { s_return(sc,sc->EOF_OBJ); }
5013 else if (sc->tok == TOK_RPAREN) {
5018 port_increment_current_line(sc, &sc->load_stack[sc->file_i], 1);
5019 sc->nesting_stack[sc->file_i]--;
5020 s_return(sc,reverse_in_place(sc, sc->NIL, sc->args));
5021 } else if (sc->tok == TOK_DOT) {
5022 s_save(sc,OP_RDDOT, sc->args, sc->NIL);
5023 sc->tok = token(sc);
5024 s_thread_to(sc,OP_RDSEXPR);
5026 s_save(sc,OP_RDLIST, sc->args, sc->NIL);;
5027 s_thread_to(sc,OP_RDSEXPR);
5032 if (token(sc) != TOK_RPAREN) {
5033 Error_0(sc,"syntax error: illegal dot expression");
5035 sc->nesting_stack[sc->file_i]--;
5036 s_return(sc,reverse_in_place(sc, sc->value, sc->args));
5041 s_return_enable_gc(sc, cons(sc, sc->QUOTE,
5042 cons(sc, sc->value, sc->NIL)));
5046 s_return_enable_gc(sc, cons(sc, sc->QQUOTE,
5047 cons(sc, sc->value, sc->NIL)));
5049 CASE(OP_RDQQUOTEVEC):
5050 gc_disable(sc, 5 + 2 * gc_reservations (mk_symbol));
5051 s_return_enable_gc(sc,cons(sc, mk_symbol(sc,"apply"),
5052 cons(sc, mk_symbol(sc,"vector"),
5053 cons(sc,cons(sc, sc->QQUOTE,
5054 cons(sc,sc->value,sc->NIL)),
5059 s_return_enable_gc(sc, cons(sc, sc->UNQUOTE,
5060 cons(sc, sc->value, sc->NIL)));
5064 s_return_enable_gc(sc, cons(sc, sc->UNQUOTESP,
5065 cons(sc, sc->value, sc->NIL)));
5068 /*sc->code=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
5069 s_goto(sc,OP_EVAL); Cannot be quoted*/
5070 /*x=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
5071 s_return(sc,x); Cannot be part of pairs*/
5072 /*sc->code=mk_proc(sc,OP_VECTOR);
5074 s_goto(sc,OP_APPLY);*/
5076 s_goto(sc,OP_VECTOR);
5078 /* ========== printing part ========== */
5080 if(is_vector(sc->args)) {
5082 sc->args=cons(sc,sc->args,mk_integer(sc,0));
5083 s_thread_to(sc,OP_PVECFROM);
5084 } else if(is_environment(sc->args)) {
5085 putstr(sc,"#<ENVIRONMENT>");
5087 } else if (!is_pair(sc->args)) {
5088 printatom(sc, sc->args, sc->print_flag);
5090 } else if (car(sc->args) == sc->QUOTE && ok_abbrev(cdr(sc->args))) {
5092 sc->args = cadr(sc->args);
5093 s_thread_to(sc,OP_P0LIST);
5094 } else if (car(sc->args) == sc->QQUOTE && ok_abbrev(cdr(sc->args))) {
5096 sc->args = cadr(sc->args);
5097 s_thread_to(sc,OP_P0LIST);
5098 } else if (car(sc->args) == sc->UNQUOTE && ok_abbrev(cdr(sc->args))) {
5100 sc->args = cadr(sc->args);
5101 s_thread_to(sc,OP_P0LIST);
5102 } else if (car(sc->args) == sc->UNQUOTESP && ok_abbrev(cdr(sc->args))) {
5104 sc->args = cadr(sc->args);
5105 s_thread_to(sc,OP_P0LIST);
5108 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
5109 sc->args = car(sc->args);
5110 s_thread_to(sc,OP_P0LIST);
5114 if (is_pair(sc->args)) {
5115 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
5117 sc->args = car(sc->args);
5118 s_thread_to(sc,OP_P0LIST);
5119 } else if(is_vector(sc->args)) {
5120 s_save(sc,OP_P1LIST,sc->NIL,sc->NIL);
5122 s_thread_to(sc,OP_P0LIST);
5124 if (sc->args != sc->NIL) {
5126 printatom(sc, sc->args, sc->print_flag);
5131 CASE(OP_PVECFROM): {
5132 int i=ivalue_unchecked(cdr(sc->args));
5133 pointer vec=car(sc->args);
5134 int len = vector_length(vec);
5139 pointer elem=vector_elem(vec,i);
5140 ivalue_unchecked(cdr(sc->args))=i+1;
5141 s_save(sc,OP_PVECFROM, sc->args, sc->NIL);
5145 s_thread_to(sc,OP_P0LIST);
5150 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
5151 Error_0(sc,sc->strbuff);
5157 static pointer opexe_6(scheme *sc, enum scheme_opcodes op) {
5162 CASE(OP_LIST_LENGTH): /* length */ /* a.k */
5163 v=list_length(sc,car(sc->args));
5165 Error_1(sc,"length: not a list:",car(sc->args));
5168 s_return_enable_gc(sc, mk_integer(sc, v));
5170 CASE(OP_ASSQ): /* assq */ /* a.k */
5172 for (y = cadr(sc->args); is_pair(y); y = cdr(y)) {
5173 if (!is_pair(car(y))) {
5174 Error_0(sc,"unable to handle non pair element");
5180 s_return(sc,car(y));
5186 CASE(OP_GET_CLOSURE): /* get-closure-code */ /* a.k */
5187 sc->args = car(sc->args);
5188 if (sc->args == sc->NIL) {
5190 } else if (is_closure(sc->args)) {
5192 s_return_enable_gc(sc, cons(sc, sc->LAMBDA,
5193 closure_code(sc->value)));
5194 } else if (is_macro(sc->args)) {
5196 s_return_enable_gc(sc, cons(sc, sc->LAMBDA,
5197 closure_code(sc->value)));
5201 CASE(OP_CLOSUREP): /* closure? */
5203 * Note, macro object is also a closure.
5204 * Therefore, (closure? <#MACRO>) ==> #t
5206 s_retbool(is_closure(car(sc->args)));
5207 CASE(OP_MACROP): /* macro? */
5208 s_retbool(is_macro(car(sc->args)));
5209 CASE(OP_VM_HISTORY): /* *vm-history* */
5210 s_return(sc, history_flatten(sc));
5212 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
5213 Error_0(sc,sc->strbuff);
5215 return sc->T; /* NOTREACHED */
5218 typedef pointer (*dispatch_func)(scheme *, enum scheme_opcodes);
5220 typedef int (*test_predicate)(pointer);
5222 static int is_any(pointer p) {
5227 static int is_nonneg(pointer p) {
5228 return ivalue(p)>=0 && is_integer(p);
5231 /* Correspond carefully with following defines! */
5238 {is_string, "string"},
5239 {is_symbol, "symbol"},
5241 {is_inport,"input port"},
5242 {is_outport,"output port"},
5243 {is_environment, "environment"},
5246 {is_character, "character"},
5247 {is_vector, "vector"},
5248 {is_number, "number"},
5249 {is_integer, "integer"},
5250 {is_nonneg, "non-negative integer"}
5254 #define TST_ANY "\001"
5255 #define TST_STRING "\002"
5256 #define TST_SYMBOL "\003"
5257 #define TST_PORT "\004"
5258 #define TST_INPORT "\005"
5259 #define TST_OUTPORT "\006"
5260 #define TST_ENVIRONMENT "\007"
5261 #define TST_PAIR "\010"
5262 #define TST_LIST "\011"
5263 #define TST_CHAR "\012"
5264 #define TST_VECTOR "\013"
5265 #define TST_NUMBER "\014"
5266 #define TST_INTEGER "\015"
5267 #define TST_NATURAL "\016"
5274 char *arg_tests_encoding;
5277 #define INF_ARG 0xffff
5279 static op_code_info dispatch_table[]= {
5280 #define _OP_DEF(A,B,C,D,E,OP) {A,B,C,D,E},
5281 #include "opdefines.h"
5285 static const char *procname(pointer x) {
5287 const char *name=dispatch_table[n].name;
5294 /* kernel of this interpreter */
5295 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op) {
5298 op_code_info *pcd=dispatch_table+sc->op;
5299 if (pcd->name!=0) { /* if built-in function, check arguments */
5300 char msg[STRBUFFSIZE];
5302 int n=list_length(sc,sc->args);
5304 /* Check number of arguments */
5305 if(n<pcd->min_arity) {
5307 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5309 pcd->min_arity==pcd->max_arity?"":" at least",
5312 if(ok && n>pcd->max_arity) {
5314 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5316 pcd->min_arity==pcd->max_arity?"":" at most",
5320 if(pcd->arg_tests_encoding!=0) {
5323 const char *t=pcd->arg_tests_encoding;
5324 pointer arglist=sc->args;
5326 pointer arg=car(arglist);
5328 if(j==TST_LIST[0]) {
5329 if(arg!=sc->NIL && !is_pair(arg)) break;
5331 if(!tests[j].fct(arg)) break;
5334 if(t[1]!=0) {/* last test is replicated as necessary */
5337 arglist=cdr(arglist);
5342 snprintf(msg, STRBUFFSIZE, "%s: argument %d must be: %s, got: %s",
5346 type_to_string(type(car(arglist))));
5351 if(_Error_1(sc,msg,0)==sc->NIL) {
5354 pcd=dispatch_table+sc->op;
5357 ok_to_freely_gc(sc);
5358 if (pcd->func(sc, (enum scheme_opcodes)sc->op) == sc->NIL) {
5362 fprintf(stderr,"No memory!\n");
5368 /* ========== Initialization of internal keywords ========== */
5370 static void assign_syntax(scheme *sc, char *name) {
5374 x = oblist_find_by_name(sc, name, &slot);
5375 assert (x == sc->NIL);
5377 x = oblist_add_by_name(sc, name, slot);
5378 typeflag(x) |= T_SYNTAX;
5381 static void assign_proc(scheme *sc, enum scheme_opcodes op, char *name) {
5384 x = mk_symbol(sc, name);
5386 new_slot_in_env(sc, x, y);
5389 static pointer mk_proc(scheme *sc, enum scheme_opcodes op) {
5392 y = get_cell(sc, sc->NIL, sc->NIL);
5393 typeflag(y) = (T_PROC | T_ATOM);
5394 ivalue_unchecked(y) = (long) op;
5399 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5400 static int syntaxnum(pointer p) {
5401 const char *s=strvalue(car(p));
5402 switch(strlength(car(p))) {
5404 if(s[0]=='i') return OP_IF0; /* if */
5405 else return OP_OR0; /* or */
5407 if(s[0]=='a') return OP_AND0; /* and */
5408 else return OP_LET0; /* let */
5411 case 'e': return OP_CASE0; /* case */
5412 case 'd': return OP_COND0; /* cond */
5413 case '*': return OP_LET0AST; /* let* */
5414 default: return OP_SET0; /* set! */
5418 case 'g': return OP_BEGIN; /* begin */
5419 case 'l': return OP_DELAY; /* delay */
5420 case 'c': return OP_MACRO0; /* macro */
5421 default: return OP_QUOTE; /* quote */
5425 case 'm': return OP_LAMBDA; /* lambda */
5426 case 'f': return OP_DEF0; /* define */
5427 default: return OP_LET0REC; /* letrec */
5430 return OP_C0STREAM; /* cons-stream */
5434 /* initialization of TinyScheme */
5436 INTERFACE static pointer s_cons(scheme *sc, pointer a, pointer b) {
5437 return cons(sc,a,b);
5439 INTERFACE static pointer s_immutable_cons(scheme *sc, pointer a, pointer b) {
5440 return immutable_cons(sc,a,b);
5443 static struct scheme_interface vtbl ={
5458 get_foreign_object_vtable,
5459 get_foreign_object_data,
5511 scheme *scheme_init_new() {
5512 scheme *sc=(scheme*)malloc(sizeof(scheme));
5513 if(!scheme_init(sc)) {
5521 scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free) {
5522 scheme *sc=(scheme*)malloc(sizeof(scheme));
5523 if(!scheme_init_custom_alloc(sc,malloc,free)) {
5532 int scheme_init(scheme *sc) {
5533 return scheme_init_custom_alloc(sc,malloc,free);
5536 int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
5537 int i, n=sizeof(dispatch_table)/sizeof(dispatch_table[0]);
5540 num_zero.is_fixnum=1;
5541 num_zero.value.ivalue=0;
5542 num_one.is_fixnum=1;
5543 num_one.value.ivalue=1;
5551 sc->last_cell_seg = -1;
5552 sc->sink = &sc->_sink;
5553 sc->NIL = &sc->_NIL;
5554 sc->T = &sc->_HASHT;
5555 sc->F = &sc->_HASHF;
5556 sc->EOF_OBJ=&sc->_EOF_OBJ;
5558 #if USE_SMALL_INTEGERS
5559 if (initialize_small_integers(sc)) {
5565 sc->free_cell = &sc->_NIL;
5567 sc->inhibit_gc = GC_ENABLED;
5568 sc->reserved_cells = 0;
5569 sc->reserved_lineno = 0;
5572 sc->outport=sc->NIL;
5573 sc->save_inport=sc->NIL;
5574 sc->loadport=sc->NIL;
5576 memset (sc->nesting_stack, 0, sizeof sc->nesting_stack);
5577 sc->interactive_repl=0;
5578 sc->strbuff = sc->malloc(STRBUFFSIZE);
5579 if (sc->strbuff == 0) {
5583 sc->strbuff_size = STRBUFFSIZE;
5585 if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
5590 dump_stack_initialize(sc);
5597 typeflag(sc->NIL) = (T_NIL | T_ATOM | MARK);
5598 car(sc->NIL) = cdr(sc->NIL) = sc->NIL;
5600 typeflag(sc->T) = (T_BOOLEAN | T_ATOM | MARK);
5601 car(sc->T) = cdr(sc->T) = sc->T;
5603 typeflag(sc->F) = (T_BOOLEAN | T_ATOM | MARK);
5604 car(sc->F) = cdr(sc->F) = sc->F;
5606 typeflag(sc->EOF_OBJ) = (T_EOF_OBJ | T_ATOM | MARK);
5607 car(sc->EOF_OBJ) = cdr(sc->EOF_OBJ) = sc->EOF_OBJ;
5609 typeflag(sc->sink) = (T_SINK | T_PAIR | MARK);
5610 car(sc->sink) = cdr(sc->sink) = sc->NIL;
5612 sc->c_nest = sc->NIL;
5614 sc->oblist = oblist_initial_value(sc);
5615 /* init global_env */
5616 new_frame_in_env(sc, sc->NIL);
5617 sc->global_env = sc->envir;
5619 x = mk_symbol(sc,"else");
5620 new_slot_in_env(sc, x, sc->T);
5622 assign_syntax(sc, "lambda");
5623 assign_syntax(sc, "quote");
5624 assign_syntax(sc, "define");
5625 assign_syntax(sc, "if");
5626 assign_syntax(sc, "begin");
5627 assign_syntax(sc, "set!");
5628 assign_syntax(sc, "let");
5629 assign_syntax(sc, "let*");
5630 assign_syntax(sc, "letrec");
5631 assign_syntax(sc, "cond");
5632 assign_syntax(sc, "delay");
5633 assign_syntax(sc, "and");
5634 assign_syntax(sc, "or");
5635 assign_syntax(sc, "cons-stream");
5636 assign_syntax(sc, "macro");
5637 assign_syntax(sc, "case");
5639 for(i=0; i<n; i++) {
5640 if(dispatch_table[i].name!=0) {
5641 assign_proc(sc, (enum scheme_opcodes)i, dispatch_table[i].name);
5645 history_init(sc, 8, 8);
5647 /* initialization of global pointers to special symbols */
5648 sc->LAMBDA = mk_symbol(sc, "lambda");
5649 sc->QUOTE = mk_symbol(sc, "quote");
5650 sc->QQUOTE = mk_symbol(sc, "quasiquote");
5651 sc->UNQUOTE = mk_symbol(sc, "unquote");
5652 sc->UNQUOTESP = mk_symbol(sc, "unquote-splicing");
5653 sc->FEED_TO = mk_symbol(sc, "=>");
5654 sc->COLON_HOOK = mk_symbol(sc,"*colon-hook*");
5655 sc->ERROR_HOOK = mk_symbol(sc, "*error-hook*");
5656 sc->SHARP_HOOK = mk_symbol(sc, "*sharp-hook*");
5657 #if USE_COMPILE_HOOK
5658 sc->COMPILE_HOOK = mk_symbol(sc, "*compile-hook*");
5661 return !sc->no_memory;
5664 void scheme_set_input_port_file(scheme *sc, FILE *fin) {
5665 sc->inport=port_from_file(sc,fin,port_input);
5668 void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end) {
5669 sc->inport=port_from_string(sc,start,past_the_end,port_input);
5672 void scheme_set_output_port_file(scheme *sc, FILE *fout) {
5673 sc->outport=port_from_file(sc,fout,port_output);
5676 void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end) {
5677 sc->outport=port_from_string(sc,start,past_the_end,port_output);
5680 void scheme_set_external_data(scheme *sc, void *p) {
5684 void scheme_deinit(scheme *sc) {
5688 sc->global_env=sc->NIL;
5689 dump_stack_free(sc);
5695 if(is_port(sc->inport)) {
5696 typeflag(sc->inport) = T_ATOM;
5699 sc->outport=sc->NIL;
5700 if(is_port(sc->save_inport)) {
5701 typeflag(sc->save_inport) = T_ATOM;
5703 sc->save_inport=sc->NIL;
5704 if(is_port(sc->loadport)) {
5705 typeflag(sc->loadport) = T_ATOM;
5707 sc->loadport=sc->NIL;
5709 for(i=0; i<=sc->file_i; i++) {
5710 port_clear_location(sc, &sc->load_stack[i]);
5714 gc(sc,sc->NIL,sc->NIL);
5716 #if USE_SMALL_INTEGERS
5717 sc->free(sc->integer_alloc);
5720 for(i=0; i<=sc->last_cell_seg; i++) {
5721 sc->free(sc->alloc_seg[i]);
5723 sc->free(sc->strbuff);
5726 void scheme_load_file(scheme *sc, FILE *fin)
5727 { scheme_load_named_file(sc,fin,0); }
5729 void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename) {
5730 dump_stack_reset(sc);
5731 sc->envir = sc->global_env;
5733 sc->load_stack[0].kind=port_input|port_file;
5734 sc->load_stack[0].rep.stdio.file=fin;
5735 sc->loadport=mk_port(sc,sc->load_stack);
5738 sc->interactive_repl=1;
5741 port_init_location(sc, &sc->load_stack[0],
5742 (fin != stdin && filename)
5743 ? mk_string(sc, filename)
5746 sc->inport=sc->loadport;
5747 sc->args = mk_integer(sc,sc->file_i);
5748 Eval_Cycle(sc, OP_T0LVL);
5749 typeflag(sc->loadport)=T_ATOM;
5750 if(sc->retcode==0) {
5751 sc->retcode=sc->nesting!=0;
5754 port_clear_location(sc, &sc->load_stack[0]);
5757 void scheme_load_string(scheme *sc, const char *cmd) {
5758 dump_stack_reset(sc);
5759 sc->envir = sc->global_env;
5761 sc->load_stack[0].kind=port_input|port_string;
5762 sc->load_stack[0].rep.string.start=(char*)cmd; /* This func respects const */
5763 sc->load_stack[0].rep.string.past_the_end=(char*)cmd+strlen(cmd);
5764 sc->load_stack[0].rep.string.curr=(char*)cmd;
5765 port_init_location(sc, &sc->load_stack[0], NULL);
5766 sc->loadport=mk_port(sc,sc->load_stack);
5768 sc->interactive_repl=0;
5769 sc->inport=sc->loadport;
5770 sc->args = mk_integer(sc,sc->file_i);
5771 Eval_Cycle(sc, OP_T0LVL);
5772 typeflag(sc->loadport)=T_ATOM;
5773 if(sc->retcode==0) {
5774 sc->retcode=sc->nesting!=0;
5777 port_clear_location(sc, &sc->load_stack[0]);
5780 void scheme_define(scheme *sc, pointer envir, pointer symbol, pointer value) {
5783 x = find_slot_spec_in_env(sc, envir, symbol, 0, &sslot);
5785 set_slot_in_env(sc, x, value);
5787 new_slot_spec_in_env(sc, symbol, value, sslot);
5792 void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr)
5796 mk_symbol(sc,sr->name),
5797 mk_foreign_func(sc, sr->f));
5800 void scheme_register_foreign_func_list(scheme * sc,
5801 scheme_registerable * list,
5805 for(i = 0; i < count; i++)
5807 scheme_register_foreign_func(sc, list + i);
5811 pointer scheme_apply0(scheme *sc, const char *procname)
5812 { return scheme_eval(sc, cons(sc,mk_symbol(sc,procname),sc->NIL)); }
5814 void save_from_C_call(scheme *sc)
5816 pointer saved_data =
5823 sc->c_nest = cons(sc, saved_data, sc->c_nest);
5824 /* Truncate the dump stack so TS will return here when done, not
5825 directly resume pre-C-call operations. */
5826 dump_stack_reset(sc);
5828 void restore_from_C_call(scheme *sc)
5830 car(sc->sink) = caar(sc->c_nest);
5831 sc->envir = cadar(sc->c_nest);
5832 sc->dump = cdr(cdar(sc->c_nest));
5834 sc->c_nest = cdr(sc->c_nest);
5837 /* "func" and "args" are assumed to be already eval'ed. */
5838 pointer scheme_call(scheme *sc, pointer func, pointer args)
5840 int old_repl = sc->interactive_repl;
5841 sc->interactive_repl = 0;
5842 save_from_C_call(sc);
5843 sc->envir = sc->global_env;
5847 Eval_Cycle(sc, OP_APPLY);
5848 sc->interactive_repl = old_repl;
5849 restore_from_C_call(sc);
5853 pointer scheme_eval(scheme *sc, pointer obj)
5855 int old_repl = sc->interactive_repl;
5856 sc->interactive_repl = 0;
5857 save_from_C_call(sc);
5861 Eval_Cycle(sc, OP_EVAL);
5862 sc->interactive_repl = old_repl;
5863 restore_from_C_call(sc);
5870 /* ========== Main ========== */
5874 #if defined(__APPLE__) && !defined (OSX)
5877 extern MacTS_main(int argc, char **argv);
5879 int argc = ccommand(&argv);
5880 MacTS_main(argc,argv);
5883 int MacTS_main(int argc, char **argv) {
5885 int main(int argc, char **argv) {
5889 char *file_name=InitFile;
5896 if(argc==2 && strcmp(argv[1],"-?")==0) {
5897 printf("Usage: tinyscheme -?\n");
5898 printf("or: tinyscheme [<file1> <file2> ...]\n");
5899 printf("followed by\n");
5900 printf(" -1 <file> [<arg1> <arg2> ...]\n");
5901 printf(" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5902 printf("assuming that the executable is named tinyscheme.\n");
5903 printf("Use - as filename for stdin.\n");
5906 if(!scheme_init(&sc)) {
5907 fprintf(stderr,"Could not initialize!\n");
5910 scheme_set_input_port_file(&sc, stdin);
5911 scheme_set_output_port_file(&sc, stdout);
5913 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"load-extension"),mk_foreign_func(&sc, scm_load_ext));
5916 if(access(file_name,0)!=0) {
5917 char *p=getenv("TINYSCHEMEINIT");
5923 if(strcmp(file_name,"-")==0) {
5925 } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0) {
5926 pointer args=sc.NIL;
5927 isfile=file_name[1]=='1';
5929 if(strcmp(file_name,"-")==0) {
5932 fin=fopen(file_name,"r");
5934 for(;*argv;argv++) {
5935 pointer value=mk_string(&sc,*argv);
5936 args=cons(&sc,value,args);
5938 args=reverse_in_place(&sc,sc.NIL,args);
5939 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args);
5942 fin=fopen(file_name,"r");
5944 if(isfile && fin==0) {
5945 fprintf(stderr,"Could not open file %s\n",file_name);
5948 scheme_load_named_file(&sc,fin,file_name);
5950 scheme_load_string(&sc,file_name);
5952 if(!isfile || fin!=stdin) {
5954 fprintf(stderr,"Errors encountered reading %s\n",file_name);
5962 } while(file_name!=0);
5964 scheme_load_named_file(&sc,stdin,0);