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_FRAME = 20 << 1 | 1,
143 T_LAST_SYSTEM_TYPE = 20 << 1 | 1
147 type_to_string (enum scheme_types typ)
151 case T_STRING: return "string";
152 case T_NUMBER: return "number";
153 case T_SYMBOL: return "symbol";
154 case T_PROC: return "proc";
155 case T_PAIR: return "pair";
156 case T_CLOSURE: return "closure";
157 case T_CONTINUATION: return "continuation";
158 case T_FOREIGN: return "foreign";
159 case T_CHARACTER: return "character";
160 case T_PORT: return "port";
161 case T_VECTOR: return "vector";
162 case T_MACRO: return "macro";
163 case T_PROMISE: return "promise";
164 case T_ENVIRONMENT: return "environment";
165 case T_FOREIGN_OBJECT: return "foreign object";
166 case T_BOOLEAN: return "boolean";
167 case T_NIL: return "nil";
168 case T_EOF_OBJ: return "eof object";
169 case T_SINK: return "sink";
170 case T_FRAME: return "frame";
172 assert (! "not reached");
175 /* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */
177 #define ADJ (1 << TYPE_BITS)
178 #define T_MASKTYPE (ADJ - 1)
179 /* 0000000000111111 */
180 #define T_TAGGED 1024 /* 0000010000000000 */
181 #define T_FINALIZE 2048 /* 0000100000000000 */
182 #define T_SYNTAX 4096 /* 0001000000000000 */
183 #define T_IMMUTABLE 8192 /* 0010000000000000 */
184 #define T_ATOM 16384 /* 0100000000000000 */ /* only for gc */
185 #define CLRATOM 49151 /* 1011111111111111 */ /* only for gc */
186 #define MARK 32768 /* 1000000000000000 */
187 #define UNMARK 32767 /* 0111111111111111 */
190 static num num_add(num a, num b);
191 static num num_mul(num a, num b);
192 static num num_div(num a, num b);
193 static num num_intdiv(num a, num b);
194 static num num_sub(num a, num b);
195 static num num_rem(num a, num b);
196 static num num_mod(num a, num b);
197 static int num_eq(num a, num b);
198 static int num_gt(num a, num b);
199 static int num_ge(num a, num b);
200 static int num_lt(num a, num b);
201 static int num_le(num a, num b);
204 static double round_per_R5RS(double x);
206 static int is_zero_double(double x);
207 static INLINE int num_is_integer(pointer p) {
208 return ((p)->_object._number.is_fixnum);
211 static const struct num num_zero = { 1, {0} };
212 static const struct num num_one = { 1, {1} };
214 /* macros for cell operations */
215 #define typeflag(p) ((p)->_flag)
216 #define type(p) (typeflag(p)&T_MASKTYPE)
217 #define settype(p, typ) (typeflag(p) = (typeflag(p) & ~T_MASKTYPE) | (typ))
219 INTERFACE INLINE int is_string(pointer p) { return (type(p)==T_STRING); }
220 #define strvalue(p) ((p)->_object._string._svalue)
221 #define strlength(p) ((p)->_object._string._length)
223 INTERFACE static int is_list(scheme *sc, pointer p);
224 INTERFACE INLINE int is_vector(pointer p) { return (type(p)==T_VECTOR); }
225 /* Given a vector, return it's length. */
226 #define vector_length(v) (v)->_object._vector._length
227 /* Given a vector length, compute the amount of cells required to
229 #define vector_size(len) (1 + ((len) - 1 + 2) / 3)
230 INTERFACE static void fill_vector(pointer vec, pointer obj);
231 INTERFACE static pointer *vector_elem_slot(pointer vec, int ielem);
232 INTERFACE static pointer vector_elem(pointer vec, int ielem);
233 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a);
234 INTERFACE INLINE int is_number(pointer p) { return (type(p)==T_NUMBER); }
235 INTERFACE INLINE int is_integer(pointer p) {
238 if (num_is_integer(p) || (double)ivalue(p) == rvalue(p))
243 INTERFACE INLINE int is_real(pointer p) {
244 return is_number(p) && (!(p)->_object._number.is_fixnum);
247 INTERFACE INLINE int is_character(pointer p) { return (type(p)==T_CHARACTER); }
248 INTERFACE INLINE char *string_value(pointer p) { return strvalue(p); }
249 INLINE num nvalue(pointer p) { return ((p)->_object._number); }
250 INTERFACE long ivalue(pointer p) { return (num_is_integer(p)?(p)->_object._number.value.ivalue:(long)(p)->_object._number.value.rvalue); }
251 INTERFACE double rvalue(pointer p) { return (!num_is_integer(p)?(p)->_object._number.value.rvalue:(double)(p)->_object._number.value.ivalue); }
252 #define ivalue_unchecked(p) ((p)->_object._number.value.ivalue)
253 #define rvalue_unchecked(p) ((p)->_object._number.value.rvalue)
254 #define set_num_integer(p) (p)->_object._number.is_fixnum=1;
255 #define set_num_real(p) (p)->_object._number.is_fixnum=0;
256 INTERFACE long charvalue(pointer p) { return ivalue_unchecked(p); }
258 INTERFACE INLINE int is_port(pointer p) { return (type(p)==T_PORT); }
259 INTERFACE INLINE int is_inport(pointer p) { return is_port(p) && p->_object._port->kind & port_input; }
260 INTERFACE INLINE int is_outport(pointer p) { return is_port(p) && p->_object._port->kind & port_output; }
262 INTERFACE INLINE int is_pair(pointer p) { return (type(p)==T_PAIR); }
263 #define car(p) ((p)->_object._cons._car)
264 #define cdr(p) ((p)->_object._cons._cdr)
265 INTERFACE pointer pair_car(pointer p) { return car(p); }
266 INTERFACE pointer pair_cdr(pointer p) { return cdr(p); }
267 INTERFACE pointer set_car(pointer p, pointer q) { return car(p)=q; }
268 INTERFACE pointer set_cdr(pointer p, pointer q) { return cdr(p)=q; }
270 INTERFACE INLINE int is_symbol(pointer p) { return (type(p)==T_SYMBOL); }
271 INTERFACE INLINE char *symname(pointer p) { return strvalue(car(p)); }
273 SCHEME_EXPORT INLINE int hasprop(pointer p) { return (is_symbol(p)); }
274 #define symprop(p) cdr(p)
277 INTERFACE INLINE int is_syntax(pointer p) { return (typeflag(p)&T_SYNTAX); }
278 INTERFACE INLINE int is_proc(pointer p) { return (type(p)==T_PROC); }
279 INTERFACE INLINE int is_foreign(pointer p) { return (type(p)==T_FOREIGN); }
280 INTERFACE INLINE char *syntaxname(pointer p) { return strvalue(car(p)); }
281 #define procnum(p) ivalue_unchecked(p)
282 static const char *procname(pointer x);
284 INTERFACE INLINE int is_closure(pointer p) { return (type(p)==T_CLOSURE); }
285 INTERFACE INLINE int is_macro(pointer p) { return (type(p)==T_MACRO); }
286 INTERFACE INLINE pointer closure_code(pointer p) { return car(p); }
287 INTERFACE INLINE pointer closure_env(pointer p) { return cdr(p); }
289 INTERFACE INLINE int is_continuation(pointer p) { return (type(p)==T_CONTINUATION); }
290 #define cont_dump(p) cdr(p)
292 INTERFACE INLINE int is_foreign_object(pointer p) { return (type(p)==T_FOREIGN_OBJECT); }
293 INTERFACE const foreign_object_vtable *get_foreign_object_vtable(pointer p) {
294 return p->_object._foreign_object._vtable;
296 INTERFACE void *get_foreign_object_data(pointer p) {
297 return p->_object._foreign_object._data;
300 /* To do: promise should be forced ONCE only */
301 INTERFACE INLINE int is_promise(pointer p) { return (type(p)==T_PROMISE); }
303 INTERFACE INLINE int is_environment(pointer p) { return (type(p)==T_ENVIRONMENT); }
304 #define setenvironment(p) typeflag(p) = T_ENVIRONMENT
306 INTERFACE INLINE int is_frame(pointer p) { return (type(p) == T_FRAME); }
307 #define setframe(p) settype(p, T_FRAME)
309 #define is_atom(p) (typeflag(p)&T_ATOM)
310 #define setatom(p) typeflag(p) |= T_ATOM
311 #define clratom(p) typeflag(p) &= CLRATOM
313 #define is_mark(p) (typeflag(p)&MARK)
314 #define setmark(p) typeflag(p) |= MARK
315 #define clrmark(p) typeflag(p) &= UNMARK
317 INTERFACE INLINE int is_immutable(pointer p) { return (typeflag(p)&T_IMMUTABLE); }
318 /*#define setimmutable(p) typeflag(p) |= T_IMMUTABLE*/
319 INTERFACE INLINE void setimmutable(pointer p) { typeflag(p) |= T_IMMUTABLE; }
321 #define caar(p) car(car(p))
322 #define cadr(p) car(cdr(p))
323 #define cdar(p) cdr(car(p))
324 #define cddr(p) cdr(cdr(p))
325 #define cadar(p) car(cdr(car(p)))
326 #define caddr(p) car(cdr(cdr(p)))
327 #define cdaar(p) cdr(car(car(p)))
328 #define cadaar(p) car(cdr(car(car(p))))
329 #define cadddr(p) car(cdr(cdr(cdr(p))))
330 #define cddddr(p) cdr(cdr(cdr(cdr(p))))
333 static pointer history_flatten(scheme *sc);
334 static void history_mark(scheme *sc);
336 # define history_mark(SC) (void) 0
337 # define history_flatten(SC) (SC)->NIL
340 #if USE_CHAR_CLASSIFIERS
341 static INLINE int Cisalpha(int c) { return isascii(c) && isalpha(c); }
342 static INLINE int Cisdigit(int c) { return isascii(c) && isdigit(c); }
343 static INLINE int Cisspace(int c) { return isascii(c) && isspace(c); }
344 static INLINE int Cisupper(int c) { return isascii(c) && isupper(c); }
345 static INLINE int Cislower(int c) { return isascii(c) && islower(c); }
349 static const char charnames[32][3]={
384 static int is_ascii_name(const char *name, int *pc) {
386 for(i=0; i<32; i++) {
387 if (strncasecmp(name, charnames[i], 3) == 0) {
392 if (strcasecmp(name, "del") == 0) {
401 static int file_push(scheme *sc, pointer fname);
402 static void file_pop(scheme *sc);
403 static int file_interactive(scheme *sc);
404 static INLINE int is_one_of(char *s, int c);
405 static int alloc_cellseg(scheme *sc, int n);
406 static long binary_decode(const char *s);
407 static INLINE pointer get_cell(scheme *sc, pointer a, pointer b);
408 static pointer _get_cell(scheme *sc, pointer a, pointer b);
409 static pointer reserve_cells(scheme *sc, int n);
410 static pointer get_consecutive_cells(scheme *sc, int n);
411 static pointer find_consecutive_cells(scheme *sc, int n);
412 static int finalize_cell(scheme *sc, pointer a);
413 static int count_consecutive_cells(pointer x, int needed);
414 static pointer find_slot_in_env(scheme *sc, pointer env, pointer sym, int all);
415 static pointer mk_number(scheme *sc, num n);
416 static char *store_string(scheme *sc, int len, const char *str, char fill);
417 static pointer mk_vector(scheme *sc, int len);
418 static pointer mk_atom(scheme *sc, char *q);
419 static pointer mk_sharp_const(scheme *sc, char *name);
420 static pointer mk_port(scheme *sc, port *p);
421 static pointer port_from_filename(scheme *sc, const char *fn, int prop);
422 static pointer port_from_file(scheme *sc, FILE *, int prop);
423 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop);
424 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop);
425 static port *port_rep_from_file(scheme *sc, FILE *, int prop);
426 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop);
427 static void port_close(scheme *sc, pointer p, int flag);
428 static void mark(pointer a);
429 static void gc(scheme *sc, pointer a, pointer b);
430 static int basic_inchar(port *pt);
431 static int inchar(scheme *sc);
432 static void backchar(scheme *sc, int c);
433 static char *readstr_upto(scheme *sc, char *delim);
434 static pointer readstrexp(scheme *sc);
435 static INLINE int skipspace(scheme *sc);
436 static int token(scheme *sc);
437 static void printslashstring(scheme *sc, char *s, int len);
438 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen);
439 static void printatom(scheme *sc, pointer l, int f);
440 static pointer mk_proc(scheme *sc, enum scheme_opcodes op);
441 static pointer mk_closure(scheme *sc, pointer c, pointer e);
442 static pointer mk_continuation(scheme *sc, pointer d);
443 static pointer reverse(scheme *sc, pointer term, pointer list);
444 static pointer reverse_in_place(scheme *sc, pointer term, pointer list);
445 static pointer revappend(scheme *sc, pointer a, pointer b);
446 static void dump_stack_preallocate_frame(scheme *sc);
447 static void dump_stack_mark(scheme *);
448 struct op_code_info {
449 char name[31]; /* strlen ("call-with-current-continuation") + 1 */
450 unsigned char min_arity;
451 unsigned char max_arity;
452 char arg_tests_encoding[3];
454 static const struct op_code_info dispatch_table[];
455 static int check_arguments (scheme *sc, const struct op_code_info *pcd, char *msg, size_t msg_size);
456 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op);
457 static void assign_syntax(scheme *sc, enum scheme_opcodes op, char *name);
458 static int syntaxnum(scheme *sc, pointer p);
459 static void assign_proc(scheme *sc, enum scheme_opcodes, const char *name);
461 #define num_ivalue(n) (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue)
462 #define num_rvalue(n) (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue)
464 static num num_add(num a, num b) {
466 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
468 ret.value.ivalue= a.value.ivalue+b.value.ivalue;
470 ret.value.rvalue=num_rvalue(a)+num_rvalue(b);
475 static num num_mul(num a, num b) {
477 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
479 ret.value.ivalue= a.value.ivalue*b.value.ivalue;
481 ret.value.rvalue=num_rvalue(a)*num_rvalue(b);
486 static num num_div(num a, num b) {
488 ret.is_fixnum=a.is_fixnum && b.is_fixnum && a.value.ivalue%b.value.ivalue==0;
490 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
492 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
497 static num num_intdiv(num a, num b) {
499 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
501 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
503 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
508 static num num_sub(num a, num b) {
510 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
512 ret.value.ivalue= a.value.ivalue-b.value.ivalue;
514 ret.value.rvalue=num_rvalue(a)-num_rvalue(b);
519 static num num_rem(num a, num b) {
522 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
526 /* remainder should have same sign as second operand */
531 } else if (res < 0) {
536 ret.value.ivalue=res;
540 static num num_mod(num a, num b) {
543 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
547 /* modulo should have same sign as second operand */
551 ret.value.ivalue=res;
555 static int num_eq(num a, num b) {
557 int is_fixnum=a.is_fixnum && b.is_fixnum;
559 ret= a.value.ivalue==b.value.ivalue;
561 ret=num_rvalue(a)==num_rvalue(b);
567 static int num_gt(num a, num b) {
569 int is_fixnum=a.is_fixnum && b.is_fixnum;
571 ret= a.value.ivalue>b.value.ivalue;
573 ret=num_rvalue(a)>num_rvalue(b);
578 static int num_ge(num a, num b) {
582 static int num_lt(num a, num b) {
584 int is_fixnum=a.is_fixnum && b.is_fixnum;
586 ret= a.value.ivalue<b.value.ivalue;
588 ret=num_rvalue(a)<num_rvalue(b);
593 static int num_le(num a, num b) {
598 /* Round to nearest. Round to even if midway */
599 static double round_per_R5RS(double x) {
609 if(fmod(fl,2.0)==0.0) { /* I imagine this holds */
618 static int is_zero_double(double x) {
619 return x<DBL_MIN && x>-DBL_MIN;
622 static long binary_decode(const char *s) {
625 while(*s!=0 && (*s=='1' || *s=='0')) {
639 * Occasionally, we need to copy a value from one location in the
640 * storage to another. Scheme objects are fine. Some primitive
641 * objects, however, require finalization, usually to free resources.
643 * For these values, we either make a copy or acquire a reference.
649 * Copies the representation of SRC to DST. This makes SRC
650 * indistinguishable from DST from the perspective of a Scheme
651 * expression modulo the fact that they reside at a different location
656 * - SRC must not be a vector.
657 * - Caller must ensure that any resources associated with the
658 * value currently stored in DST is accounted for.
661 copy_value(scheme *sc, pointer dst, pointer src)
663 memcpy(dst, src, sizeof *src);
665 /* We may need to make a copy or acquire a reference. */
666 if (typeflag(dst) & T_FINALIZE)
669 strvalue(dst) = store_string(sc, strlength(dst), strvalue(dst), 0);
672 /* XXX acquire reference */
673 assert (!"implemented");
675 case T_FOREIGN_OBJECT:
676 /* XXX acquire reference */
677 assert (!"implemented");
680 assert (!"vectors cannot be copied");
686 /* Tags are like property lists, but can be attached to arbitrary
690 mk_tagged_value(scheme *sc, pointer v, pointer tag_car, pointer tag_cdr)
694 assert(! is_vector(v));
696 r = get_consecutive_cells(sc, 2);
700 copy_value(sc, r, v);
701 typeflag(r) |= T_TAGGED;
704 typeflag(t) = T_PAIR;
714 return !! (typeflag(v) & T_TAGGED);
717 static INLINE pointer
718 get_tag(scheme *sc, pointer v)
727 /* Low-level allocator.
729 * Memory is allocated in segments. Every segment holds a fixed
730 * number of cells. Segments are linked into a list, sorted in
731 * reverse address order (i.e. those with a higher address first).
732 * This is used in the garbage collector to build the freelist in
738 struct cell_segment *next;
744 /* Allocate a new cell segment but do not make it available yet. */
746 _alloc_cellseg(scheme *sc, size_t len, struct cell_segment **segment)
751 if (adj < sizeof(struct cell))
752 adj = sizeof(struct cell);
754 /* The segment header is conveniently allocated with the cells. */
755 cp = sc->malloc(sizeof **segment + len * sizeof(struct cell) + adj);
760 (*segment)->next = NULL;
761 (*segment)->alloc = cp;
762 cp = (void *) ((uintptr_t) cp + sizeof **segment);
764 /* adjust in TYPE_BITS-bit boundary */
765 if (((uintptr_t) cp) % adj != 0)
766 cp = (void *) (adj * ((uintptr_t) cp / adj + 1));
768 (*segment)->cells = cp;
769 (*segment)->cells_len = len;
773 /* Deallocate a cell segment. Returns the next cell segment.
774 * Convenient for deallocation in a loop. */
775 static struct cell_segment *
776 _dealloc_cellseg(scheme *sc, struct cell_segment *segment)
779 struct cell_segment *next;
784 next = segment->next;
785 sc->free(segment->alloc);
789 /* allocate new cell segment */
790 static int alloc_cellseg(scheme *sc, int n) {
795 for (k = 0; k < n; k++) {
796 struct cell_segment *new, **s;
797 if (_alloc_cellseg(sc, CELL_SEGSIZE, &new)) {
800 /* insert new segment in reverse address order */
801 for (s = &sc->cell_segments;
802 *s && (uintptr_t) (*s)->alloc > (uintptr_t) new->alloc;
809 sc->fcells += new->cells_len;
810 last = new->cells + new->cells_len - 1;
811 for (p = new->cells; p <= last; p++) {
816 /* insert new cells in address order on free list */
817 if (sc->free_cell == sc->NIL || p < sc->free_cell) {
818 cdr(last) = sc->free_cell;
819 sc->free_cell = new->cells;
822 while (cdr(p) != sc->NIL && (uintptr_t) new->cells > (uintptr_t) cdr(p))
833 /* Controlling the garbage collector.
835 * Every time a cell is allocated, the interpreter may run out of free
836 * cells and do a garbage collection. This is problematic because it
837 * might garbage collect objects that have been allocated, but are not
838 * yet made available to the interpreter.
840 * Previously, we would plug such newly allocated cells into the list
841 * of newly allocated objects rooted at car(sc->sink), but that
842 * requires allocating yet another cell increasing pressure on the
843 * memory management system.
845 * A faster alternative is to preallocate the cells needed for an
846 * operation and make sure the garbage collection is not run until all
847 * allocated objects are plugged in. This can be done with gc_disable
851 /* The garbage collector is enabled if the inhibit counter is
855 /* For now we provide a way to disable this optimization for
856 * benchmarking and because it produces slightly smaller code. */
857 #ifndef USE_GC_LOCKING
858 # define USE_GC_LOCKING 1
861 /* To facilitate nested calls to gc_disable, functions that allocate
862 * more than one cell may define a macro, e.g. foo_allocates. This
863 * macro can be used to compute the amount of preallocation at the
864 * call site with the help of this macro. */
865 #define gc_reservations(fn) fn ## _allocates
869 /* Report a shortage in reserved cells, and terminate the program. */
871 gc_reservation_failure(struct scheme *sc)
875 "insufficient reservation\n")
878 "insufficient %s reservation in line %d\n",
879 sc->frame_freelist == sc->NIL ? "frame" : "cell",
880 sc->reserved_lineno);
885 /* Disable the garbage collection and reserve the given number of
886 * cells. gc_disable may be nested, but the enclosing reservation
887 * must include the reservations of all nested calls. Note: You must
888 * re-enable the gc before calling Error_X. */
890 _gc_disable(struct scheme *sc, size_t reserve, int lineno)
892 if (sc->inhibit_gc == 0) {
893 reserve_cells(sc, (reserve));
894 sc->reserved_cells = (reserve);
898 sc->reserved_lineno = lineno;
900 } else if (sc->reserved_cells < (reserve))
901 gc_reservation_failure (sc);
904 #define gc_disable(sc, reserve) \
906 if (sc->frame_freelist == sc->NIL) { \
907 if (gc_enabled(sc)) \
908 dump_stack_preallocate_frame(sc); \
910 gc_reservation_failure(sc); \
912 _gc_disable (sc, reserve, __LINE__); \
915 /* Enable the garbage collector. */
916 #define gc_enable(sc) \
918 assert(sc->inhibit_gc); \
919 sc->inhibit_gc -= 1; \
922 /* Test whether the garbage collector is enabled. */
923 #define gc_enabled(sc) \
924 (sc->inhibit_gc == GC_ENABLED)
926 /* Consume a reserved cell. */
927 #define gc_consume(sc) \
929 assert(! gc_enabled (sc)); \
930 if (sc->reserved_cells == 0) \
931 gc_reservation_failure (sc); \
932 sc->reserved_cells -= 1; \
935 #else /* USE_GC_LOCKING */
937 #define gc_reservation_failure(sc) (void) 0
938 #define gc_disable(sc, reserve) \
940 if (sc->frame_freelist == sc->NIL) \
941 dump_stack_preallocate_frame(sc); \
943 #define gc_enable(sc) (void) 0
944 #define gc_enabled(sc) 1
945 #define gc_consume(sc) (void) 0
947 #endif /* USE_GC_LOCKING */
949 static INLINE pointer get_cell_x(scheme *sc, pointer a, pointer b) {
950 if (! gc_enabled (sc) || sc->free_cell != sc->NIL) {
951 pointer x = sc->free_cell;
952 if (! gc_enabled (sc))
954 sc->free_cell = cdr(x);
958 assert (gc_enabled (sc));
959 return _get_cell (sc, a, b);
963 /* get new cell. parameter a, b is marked by gc. */
964 static pointer _get_cell(scheme *sc, pointer a, pointer b) {
971 assert (gc_enabled (sc));
972 if (sc->free_cell == sc->NIL) {
974 if (sc->free_cell == sc->NIL) {
980 sc->free_cell = cdr(x);
985 /* make sure that there is a given number of cells free */
986 static pointer reserve_cells(scheme *sc, int n) {
991 /* Are there enough cells available? */
992 if (sc->fcells < n) {
993 /* If not, try gc'ing some */
994 gc(sc, sc->NIL, sc->NIL);
995 if (sc->fcells < n) {
996 /* If there still aren't, try getting more heap */
997 if (!alloc_cellseg(sc,1)) {
1002 if (sc->fcells < n) {
1003 /* If all fail, report failure */
1011 static pointer get_consecutive_cells(scheme *sc, int n) {
1014 if(sc->no_memory) { return sc->sink; }
1016 /* Are there any cells available? */
1017 x=find_consecutive_cells(sc,n);
1018 if (x != sc->NIL) { return x; }
1020 /* If not, try gc'ing some */
1021 gc(sc, sc->NIL, sc->NIL);
1022 x=find_consecutive_cells(sc,n);
1023 if (x != sc->NIL) { return x; }
1025 /* If there still aren't, try getting more heap */
1026 if (!alloc_cellseg(sc,1))
1032 x=find_consecutive_cells(sc,n);
1033 if (x != sc->NIL) { return x; }
1035 /* If all fail, report failure */
1040 static int count_consecutive_cells(pointer x, int needed) {
1042 while(cdr(x)==x+1) {
1045 if(n>needed) return n;
1050 static pointer find_consecutive_cells(scheme *sc, int n) {
1055 while(*pp!=sc->NIL) {
1056 cnt=count_consecutive_cells(*pp,n);
1068 /* Free a cell. This is dangerous. Only free cells that are not
1071 free_cell(scheme *sc, pointer a)
1073 cdr(a) = sc->free_cell;
1078 /* Free a cell and retrieve its content. This is dangerous. Only
1079 * free cells that are not referenced. */
1081 free_cons(scheme *sc, pointer a, pointer *r_car, pointer *r_cdr)
1088 /* To retain recent allocs before interpreter knows about them -
1091 static void push_recent_alloc(scheme *sc, pointer recent, pointer extra)
1093 pointer holder = get_cell_x(sc, recent, extra);
1094 typeflag(holder) = T_PAIR | T_IMMUTABLE;
1095 car(holder) = recent;
1096 cdr(holder) = car(sc->sink);
1097 car(sc->sink) = holder;
1100 static INLINE void ok_to_freely_gc(scheme *sc)
1102 pointer a = car(sc->sink), next;
1103 car(sc->sink) = sc->NIL;
1104 while (a != sc->NIL)
1112 static pointer get_cell(scheme *sc, pointer a, pointer b)
1114 pointer cell = get_cell_x(sc, a, b);
1115 /* For right now, include "a" and "b" in "cell" so that gc doesn't
1116 think they are garbage. */
1117 /* Tentatively record it as a pair so gc understands it. */
1118 typeflag(cell) = T_PAIR;
1121 if (gc_enabled (sc))
1122 push_recent_alloc(sc, cell, sc->NIL);
1126 static pointer get_vector_object(scheme *sc, int len, pointer init)
1128 pointer cells = get_consecutive_cells(sc, vector_size(len));
1130 int alloc_len = 1 + 3 * (vector_size(len) - 1);
1131 if(sc->no_memory) { return sc->sink; }
1132 /* Record it as a vector so that gc understands it. */
1133 typeflag(cells) = (T_VECTOR | T_ATOM | T_FINALIZE);
1134 vector_length(cells) = len;
1135 fill_vector(cells,init);
1137 /* Initialize the unused slots at the end. */
1138 assert (alloc_len - len < 3);
1139 for (i = len; i < alloc_len; i++)
1140 cells->_object._vector._elements[i] = sc->NIL;
1142 if (gc_enabled (sc))
1143 push_recent_alloc(sc, cells, sc->NIL);
1147 /* Medium level cell allocation */
1149 /* get new cons cell */
1150 pointer _cons(scheme *sc, pointer a, pointer b, int immutable) {
1151 pointer x = get_cell(sc,a, b);
1153 typeflag(x) = T_PAIR;
1163 /* ========== oblist implementation ========== */
1165 #ifndef USE_OBJECT_LIST
1167 static int hash_fn(const char *key, int table_size);
1169 static pointer oblist_initial_value(scheme *sc)
1171 /* There are about 768 symbols used after loading the
1173 return mk_vector(sc, 1009);
1176 /* Lookup the symbol NAME. Returns the symbol, or NIL if it does not
1177 * exist. In that case, SLOT points to the point where the new symbol
1178 * is to be inserted. */
1179 static INLINE pointer
1180 oblist_find_by_name(scheme *sc, const char *name, pointer **slot)
1187 location = hash_fn(name, vector_length(sc->oblist));
1188 for (*slot = vector_elem_slot(sc->oblist, location), x = **slot;
1189 x != sc->NIL; *slot = &cdr(x), x = **slot) {
1190 s = symname(car(x));
1191 /* case-insensitive, per R5RS section 2. */
1192 d = stricmp(name, s);
1194 return car(x); /* Hit. */
1201 static pointer oblist_all_symbols(scheme *sc)
1205 pointer ob_list = sc->NIL;
1207 for (i = 0; i < vector_length(sc->oblist); i++) {
1208 for (x = vector_elem(sc->oblist, i); x != sc->NIL; x = cdr(x)) {
1209 ob_list = cons(sc, x, ob_list);
1217 static pointer oblist_initial_value(scheme *sc)
1222 /* Lookup the symbol NAME. Returns the symbol, or NIL if it does not
1223 * exist. In that case, SLOT points to the point where the new symbol
1224 * is to be inserted. */
1225 static INLINE pointer
1226 oblist_find_by_name(scheme *sc, const char *name, pointer **slot)
1232 for (*slot = &sc->oblist, x = **slot; x != sc->NIL; *slot = &cdr(x), x = **slot) {
1233 s = symname(car(x));
1234 /* case-insensitive, per R5RS section 2. */
1235 d = stricmp(name, s);
1237 return car(x); /* Hit. */
1244 static pointer oblist_all_symbols(scheme *sc)
1251 /* Add a new symbol NAME at SLOT. SLOT must be obtained using
1252 * oblist_find_by_name, and no insertion must be done between
1253 * obtaining the SLOT and calling this function. Returns the new
1255 static pointer oblist_add_by_name(scheme *sc, const char *name, pointer *slot)
1257 #define oblist_add_by_name_allocates 3
1260 gc_disable(sc, gc_reservations (oblist_add_by_name));
1261 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
1262 typeflag(x) = T_SYMBOL;
1263 setimmutable(car(x));
1264 *slot = immutable_cons(sc, x, *slot);
1271 static pointer mk_port(scheme *sc, port *p) {
1272 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1274 typeflag(x) = T_PORT|T_ATOM|T_FINALIZE;
1279 pointer mk_foreign_func(scheme *sc, foreign_func f) {
1280 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1282 typeflag(x) = (T_FOREIGN | T_ATOM);
1287 pointer mk_foreign_object(scheme *sc, const foreign_object_vtable *vtable, void *data) {
1288 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1290 typeflag(x) = (T_FOREIGN_OBJECT | T_ATOM | T_FINALIZE);
1291 x->_object._foreign_object._vtable=vtable;
1292 x->_object._foreign_object._data = data;
1296 INTERFACE pointer mk_character(scheme *sc, int c) {
1297 pointer x = get_cell(sc,sc->NIL, sc->NIL);
1299 typeflag(x) = (T_CHARACTER | T_ATOM);
1300 ivalue_unchecked(x)= c;
1307 #if USE_SMALL_INTEGERS
1309 static const struct cell small_integers[] = {
1310 #define DEFINE_INTEGER(n) { T_NUMBER | T_ATOM | MARK, {{ 1, {n}}}},
1311 #include "small-integers.h"
1312 #undef DEFINE_INTEGER
1316 #define MAX_SMALL_INTEGER (sizeof small_integers / sizeof *small_integers - 1)
1318 static INLINE pointer
1319 mk_small_integer(scheme *sc, long n)
1321 #define mk_small_integer_allocates 0
1323 assert(0 <= n && n < MAX_SMALL_INTEGER);
1324 return (pointer) &small_integers[n];
1328 #define mk_small_integer_allocates 1
1329 #define mk_small_integer mk_integer
1333 /* get number atom (integer) */
1334 INTERFACE pointer mk_integer(scheme *sc, long n) {
1337 #if USE_SMALL_INTEGERS
1338 if (0 <= n && n < MAX_SMALL_INTEGER)
1339 return mk_small_integer(sc, n);
1342 x = get_cell(sc,sc->NIL, sc->NIL);
1343 typeflag(x) = (T_NUMBER | T_ATOM);
1344 ivalue_unchecked(x)= n;
1351 INTERFACE pointer mk_real(scheme *sc, double n) {
1352 pointer x = get_cell(sc,sc->NIL, sc->NIL);
1354 typeflag(x) = (T_NUMBER | T_ATOM);
1355 rvalue_unchecked(x)= n;
1360 static pointer mk_number(scheme *sc, num n) {
1362 return mk_integer(sc,n.value.ivalue);
1364 return mk_real(sc,n.value.rvalue);
1368 /* allocate name to string area */
1369 static char *store_string(scheme *sc, int len_str, const char *str, char fill) {
1372 q=(char*)sc->malloc(len_str+1);
1378 memcpy (q, str, len_str);
1381 memset(q, fill, len_str);
1387 /* get new string */
1388 INTERFACE pointer mk_string(scheme *sc, const char *str) {
1389 return mk_counted_string(sc,str,strlen(str));
1392 INTERFACE pointer mk_counted_string(scheme *sc, const char *str, int len) {
1393 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1394 typeflag(x) = (T_STRING | T_ATOM | T_FINALIZE);
1395 strvalue(x) = store_string(sc,len,str,0);
1400 INTERFACE pointer mk_empty_string(scheme *sc, int len, char fill) {
1401 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1402 typeflag(x) = (T_STRING | T_ATOM | T_FINALIZE);
1403 strvalue(x) = store_string(sc,len,0,fill);
1408 INTERFACE static pointer mk_vector(scheme *sc, int len)
1409 { return get_vector_object(sc,len,sc->NIL); }
1411 INTERFACE static void fill_vector(pointer vec, pointer obj) {
1413 assert (is_vector (vec));
1414 for(i = 0; i < vector_length(vec); i++) {
1415 vec->_object._vector._elements[i] = obj;
1419 INTERFACE static pointer *vector_elem_slot(pointer vec, int ielem) {
1420 assert (is_vector (vec));
1421 assert (ielem < vector_length(vec));
1422 return &vec->_object._vector._elements[ielem];
1425 INTERFACE static pointer vector_elem(pointer vec, int ielem) {
1426 assert (is_vector (vec));
1427 assert (ielem < vector_length(vec));
1428 return vec->_object._vector._elements[ielem];
1431 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a) {
1432 assert (is_vector (vec));
1433 assert (ielem < vector_length(vec));
1434 vec->_object._vector._elements[ielem] = a;
1438 /* get new symbol */
1439 INTERFACE pointer mk_symbol(scheme *sc, const char *name) {
1440 #define mk_symbol_allocates oblist_add_by_name_allocates
1444 /* first check oblist */
1445 x = oblist_find_by_name(sc, name, &slot);
1449 x = oblist_add_by_name(sc, name, slot);
1454 INTERFACE pointer gensym(scheme *sc) {
1459 for(; sc->gensym_cnt<LONG_MAX; sc->gensym_cnt++) {
1460 snprintf(name,40,"gensym-%ld",sc->gensym_cnt);
1462 /* first check oblist */
1463 x = oblist_find_by_name(sc, name, &slot);
1468 x = oblist_add_by_name(sc, name, slot);
1476 /* double the size of the string buffer */
1477 static int expand_strbuff(scheme *sc) {
1478 size_t new_size = sc->strbuff_size * 2;
1479 char *new_buffer = sc->malloc(new_size);
1480 if (new_buffer == 0) {
1484 memcpy(new_buffer, sc->strbuff, sc->strbuff_size);
1485 sc->free(sc->strbuff);
1486 sc->strbuff = new_buffer;
1487 sc->strbuff_size = new_size;
1491 /* make symbol or number atom from string */
1492 static pointer mk_atom(scheme *sc, char *q) {
1494 int has_dec_point=0;
1500 while ((next = strstr(next, "::")) != 0) {
1501 /* Keep looking for the last occurrence. */
1508 return cons(sc, sc->COLON_HOOK,
1512 cons(sc, mk_symbol(sc, strlwr(p + 2)),
1514 cons(sc, mk_atom(sc, q), sc->NIL)));
1520 if ((c == '+') || (c == '-')) {
1527 return (mk_symbol(sc, strlwr(q)));
1529 } else if (c == '.') {
1533 return (mk_symbol(sc, strlwr(q)));
1535 } else if (!isdigit(c)) {
1536 return (mk_symbol(sc, strlwr(q)));
1539 for ( ; (c = *p) != 0; ++p) {
1542 if(!has_dec_point) {
1547 else if ((c == 'e') || (c == 'E')) {
1549 has_dec_point = 1; /* decimal point illegal
1552 if ((*p == '-') || (*p == '+') || isdigit(*p)) {
1557 return (mk_symbol(sc, strlwr(q)));
1561 return mk_real(sc,atof(q));
1563 return (mk_integer(sc, atol(q)));
1567 static pointer mk_sharp_const(scheme *sc, char *name) {
1569 char tmp[STRBUFFSIZE];
1571 if (!strcmp(name, "t"))
1573 else if (!strcmp(name, "f"))
1575 else if (*name == 'o') {/* #o (octal) */
1576 snprintf(tmp, STRBUFFSIZE, "0%s", name+1);
1577 sscanf(tmp, "%lo", (long unsigned *)&x);
1578 return (mk_integer(sc, x));
1579 } else if (*name == 'd') { /* #d (decimal) */
1580 sscanf(name+1, "%ld", (long int *)&x);
1581 return (mk_integer(sc, x));
1582 } else if (*name == 'x') { /* #x (hex) */
1583 snprintf(tmp, STRBUFFSIZE, "0x%s", name+1);
1584 sscanf(tmp, "%lx", (long unsigned *)&x);
1585 return (mk_integer(sc, x));
1586 } else if (*name == 'b') { /* #b (binary) */
1587 x = binary_decode(name+1);
1588 return (mk_integer(sc, x));
1589 } else if (*name == '\\') { /* #\w (character) */
1591 if(stricmp(name+1,"space")==0) {
1593 } else if(stricmp(name+1,"newline")==0) {
1595 } else if(stricmp(name+1,"return")==0) {
1597 } else if(stricmp(name+1,"tab")==0) {
1599 } else if(name[1]=='x' && name[2]!=0) {
1601 if(sscanf(name+2,"%x",(unsigned int *)&c1)==1 && c1 < UCHAR_MAX) {
1607 } else if(is_ascii_name(name+1,&c)) {
1610 } else if(name[2]==0) {
1615 return mk_character(sc,c);
1620 /* ========== garbage collector ========== */
1622 const int frame_length;
1623 static void dump_stack_deallocate_frame(scheme *sc, pointer frame);
1626 * We use algorithm E (Knuth, The Art of Computer Programming Vol.1,
1627 * sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm,
1630 static void mark(pointer a) {
1635 E2: if (! is_mark(p))
1637 if (is_vector(p) || is_frame(p)) {
1639 int len = is_vector(p) ? vector_length(p) : frame_length;
1640 for (i = 0; i < len; i++) {
1641 mark(p->_object._vector._elements[i]);
1645 else if (is_port(p)) {
1646 port *pt = p->_object._port;
1647 mark(pt->curr_line);
1651 /* Mark tag if p has one. */
1658 if (q && !is_mark(q)) {
1659 setatom(p); /* a note that we have moved car */
1665 E5: q = cdr(p); /* down cdr */
1666 if (q && !is_mark(q)) {
1672 E6: /* up. Undo the link switching from steps E4 and E5. */
1690 /* garbage collection. parameter a, b is marked. */
1691 static void gc(scheme *sc, pointer a, pointer b) {
1693 struct cell_segment *s;
1696 assert (gc_enabled (sc));
1698 if(sc->gc_verbose) {
1699 putstr(sc, "gc...");
1702 /* mark system globals */
1704 mark(sc->global_env);
1706 /* mark current registers */
1711 dump_stack_mark(sc);
1714 mark(sc->save_inport);
1717 for (i = 0; i <= sc->file_i; i++) {
1718 mark(sc->load_stack[i].filename);
1719 mark(sc->load_stack[i].curr_line);
1722 /* Mark recent objects the interpreter doesn't know about yet. */
1723 mark(car(sc->sink));
1724 /* Mark any older stuff above nested C calls */
1727 /* mark variables a, b */
1731 /* garbage collect */
1734 sc->free_cell = sc->NIL;
1735 /* free-list is kept sorted by address so as to maintain consecutive
1736 ranges, if possible, for use with vectors. Here we scan the cells
1737 (which are also kept sorted by address) downwards to build the
1738 free-list in sorted order.
1740 for (s = sc->cell_segments; s; s = s->next) {
1741 p = s->cells + s->cells_len;
1742 while (--p >= s->cells) {
1743 if ((typeflag(p) & 1) == 0)
1744 /* All types have the LSB set. This is not a typeflag. */
1750 if ((typeflag(p) & T_FINALIZE) == 0
1751 || finalize_cell(sc, p)) {
1756 cdr(p) = sc->free_cell;
1763 if (sc->gc_verbose) {
1765 snprintf(msg,80,"done: %ld cells were recovered.\n", sc->fcells);
1769 /* if only a few recovered, get more to avoid fruitless gc's */
1770 if (sc->fcells < CELL_MINRECOVER
1771 && alloc_cellseg(sc, 1) == 0)
1775 /* Finalize A. Returns true if a can be added to the list of free
1778 finalize_cell(scheme *sc, pointer a)
1782 sc->free(strvalue(a));
1786 if(a->_object._port->kind&port_file
1787 && a->_object._port->rep.stdio.closeit) {
1788 port_close(sc,a,port_input|port_output);
1789 } else if (a->_object._port->kind & port_srfi6) {
1790 sc->free(a->_object._port->rep.string.start);
1792 sc->free(a->_object._port);
1795 case T_FOREIGN_OBJECT:
1796 a->_object._foreign_object._vtable->finalize(sc, a->_object._foreign_object._data);
1802 for (i = vector_size(vector_length(a)) - 1; i > 0; i--) {
1806 cdr(p) = sc->free_cell;
1814 dump_stack_deallocate_frame(sc, a);
1815 return 0; /* Do not free cell. */
1818 return 1; /* Free cell. */
1823 port_clear_location (scheme *sc, port *p)
1825 p->curr_line = sc->NIL;
1826 p->filename = sc->NIL;
1830 port_increment_current_line (scheme *sc, port *p, long delta)
1836 mk_integer(sc, ivalue_unchecked(p->curr_line) + delta);
1840 port_init_location (scheme *sc, port *p, pointer name)
1842 p->curr_line = mk_integer(sc, 0);
1843 p->filename = name ? name : mk_string(sc, "<unknown>");
1849 port_clear_location (scheme *sc, port *p)
1854 port_increment_current_line (scheme *sc, port *p, long delta)
1859 port_init_location (scheme *sc, port *p, pointer name)
1865 /* ========== Routines for Reading ========== */
1867 static int file_push(scheme *sc, pointer fname) {
1870 if (sc->file_i == MAXFIL-1)
1872 fin = fopen(string_value(fname), "r");
1875 sc->load_stack[sc->file_i].kind=port_file|port_input;
1876 sc->load_stack[sc->file_i].rep.stdio.file=fin;
1877 sc->load_stack[sc->file_i].rep.stdio.closeit=1;
1878 sc->nesting_stack[sc->file_i]=0;
1879 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1880 port_init_location(sc, &sc->load_stack[sc->file_i], fname);
1885 static void file_pop(scheme *sc) {
1886 if(sc->file_i != 0) {
1887 sc->nesting=sc->nesting_stack[sc->file_i];
1888 port_close(sc,sc->loadport,port_input);
1889 port_clear_location(sc, &sc->load_stack[sc->file_i]);
1891 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1895 static int file_interactive(scheme *sc) {
1896 return sc->file_i==0 && sc->load_stack[0].rep.stdio.file==stdin
1897 && sc->inport->_object._port->kind&port_file;
1900 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop) {
1904 if(prop==(port_input|port_output)) {
1906 } else if(prop==port_output) {
1915 pt=port_rep_from_file(sc,f,prop);
1916 pt->rep.stdio.closeit=1;
1917 port_init_location(sc, pt, mk_string(sc, fn));
1921 static pointer port_from_filename(scheme *sc, const char *fn, int prop) {
1923 pt=port_rep_from_filename(sc,fn,prop);
1927 return mk_port(sc,pt);
1930 static port *port_rep_from_file(scheme *sc, FILE *f, int prop)
1934 pt = (port *)sc->malloc(sizeof *pt);
1938 pt->kind = port_file | prop;
1939 pt->rep.stdio.file = f;
1940 pt->rep.stdio.closeit = 0;
1941 port_init_location(sc, pt, NULL);
1945 static pointer port_from_file(scheme *sc, FILE *f, int prop) {
1947 pt=port_rep_from_file(sc,f,prop);
1951 return mk_port(sc,pt);
1954 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1956 pt=(port*)sc->malloc(sizeof(port));
1960 pt->kind=port_string|prop;
1961 pt->rep.string.start=start;
1962 pt->rep.string.curr=start;
1963 pt->rep.string.past_the_end=past_the_end;
1964 port_init_location(sc, pt, NULL);
1968 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1970 pt=port_rep_from_string(sc,start,past_the_end,prop);
1974 return mk_port(sc,pt);
1977 #define BLOCK_SIZE 256
1979 static port *port_rep_from_scratch(scheme *sc) {
1982 pt=(port*)sc->malloc(sizeof(port));
1986 start=sc->malloc(BLOCK_SIZE);
1990 memset(start,' ',BLOCK_SIZE-1);
1991 start[BLOCK_SIZE-1]='\0';
1992 pt->kind=port_string|port_output|port_srfi6;
1993 pt->rep.string.start=start;
1994 pt->rep.string.curr=start;
1995 pt->rep.string.past_the_end=start+BLOCK_SIZE-1;
1996 port_init_location(sc, pt, NULL);
2000 static pointer port_from_scratch(scheme *sc) {
2002 pt=port_rep_from_scratch(sc);
2006 return mk_port(sc,pt);
2009 static void port_close(scheme *sc, pointer p, int flag) {
2010 port *pt=p->_object._port;
2012 if((pt->kind & (port_input|port_output))==0) {
2013 /* Cleanup is here so (close-*-port) functions could work too */
2014 port_clear_location(sc, pt);
2015 if(pt->kind&port_file) {
2016 fclose(pt->rep.stdio.file);
2022 /* get new character from input file */
2023 static int inchar(scheme *sc) {
2027 pt = sc->inport->_object._port;
2028 if(pt->kind & port_saw_EOF)
2030 c = basic_inchar(pt);
2031 if(c == EOF && sc->inport == sc->loadport) {
2032 /* Instead, set port_saw_EOF */
2033 pt->kind |= port_saw_EOF;
2042 static int basic_inchar(port *pt) {
2043 if(pt->kind & port_file) {
2044 return fgetc(pt->rep.stdio.file);
2046 if(*pt->rep.string.curr == 0 ||
2047 pt->rep.string.curr == pt->rep.string.past_the_end) {
2050 return *pt->rep.string.curr++;
2055 /* back character to input buffer */
2056 static void backchar(scheme *sc, int c) {
2059 pt=sc->inport->_object._port;
2060 if(pt->kind&port_file) {
2061 ungetc(c,pt->rep.stdio.file);
2063 if(pt->rep.string.curr!=pt->rep.string.start) {
2064 --pt->rep.string.curr;
2069 static int realloc_port_string(scheme *sc, port *p)
2071 char *start=p->rep.string.start;
2072 size_t old_size = p->rep.string.past_the_end - start;
2073 size_t new_size=p->rep.string.past_the_end-start+1+BLOCK_SIZE;
2074 char *str=sc->malloc(new_size);
2076 memset(str,' ',new_size-1);
2077 str[new_size-1]='\0';
2078 memcpy(str, start, old_size);
2079 p->rep.string.start=str;
2080 p->rep.string.past_the_end=str+new_size-1;
2081 p->rep.string.curr-=start-str;
2089 INTERFACE void putstr(scheme *sc, const char *s) {
2090 port *pt=sc->outport->_object._port;
2091 if(pt->kind&port_file) {
2092 fputs(s,pt->rep.stdio.file);
2095 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
2096 *pt->rep.string.curr++=*s;
2097 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
2098 *pt->rep.string.curr++=*s;
2104 static void putchars(scheme *sc, const char *s, int len) {
2105 port *pt=sc->outport->_object._port;
2106 if(pt->kind&port_file) {
2107 fwrite(s,1,len,pt->rep.stdio.file);
2110 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
2111 *pt->rep.string.curr++=*s++;
2112 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
2113 *pt->rep.string.curr++=*s++;
2119 INTERFACE void putcharacter(scheme *sc, int c) {
2120 port *pt=sc->outport->_object._port;
2121 if(pt->kind&port_file) {
2122 fputc(c,pt->rep.stdio.file);
2124 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
2125 *pt->rep.string.curr++=c;
2126 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
2127 *pt->rep.string.curr++=c;
2132 /* read characters up to delimiter, but cater to character constants */
2133 static char *readstr_upto(scheme *sc, char *delim) {
2134 char *p = sc->strbuff;
2136 while ((p - sc->strbuff < sc->strbuff_size) &&
2137 !is_one_of(delim, (*p++ = inchar(sc))));
2139 if(p == sc->strbuff+2 && p[-2] == '\\') {
2148 /* read string expression "xxx...xxx" */
2149 static pointer readstrexp(scheme *sc) {
2150 char *p = sc->strbuff;
2153 enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state=st_ok;
2160 if(p-sc->strbuff > (sc->strbuff_size)-1) {
2161 ptrdiff_t offset = p - sc->strbuff;
2162 if (expand_strbuff(sc) != 0) {
2165 p = sc->strbuff + offset;
2175 return mk_counted_string(sc,sc->strbuff,p-sc->strbuff);
2224 if(c>='0' && c<='F') {
2228 c1=(c1<<4)+c-'A'+10;
2242 if (c < '0' || c > '7')
2250 if (state==st_oct2 && c1 >= 32)
2255 if (state == st_oct1)
2269 /* check c is in chars */
2270 static INLINE int is_one_of(char *s, int c) {
2271 if(c==EOF) return 1;
2278 /* skip white characters */
2279 static INLINE int skipspace(scheme *sc) {
2280 int c = 0, curr_line = 0;
2288 } while (isspace(c));
2291 port_increment_current_line(sc, &sc->load_stack[sc->file_i], curr_line);
2302 static int token(scheme *sc) {
2305 if(c == EOF) { return (TOK_EOF); }
2306 switch (c=inchar(sc)) {
2310 return (TOK_LPAREN);
2312 return (TOK_RPAREN);
2315 if(is_one_of(" \n\t",c)) {
2325 while ((c=inchar(sc)) != '\n' && c!=EOF)
2329 port_increment_current_line(sc, &sc->load_stack[sc->file_i], 1);
2332 { return (TOK_EOF); }
2334 { return (token(sc));}
2336 return (TOK_DQUOTE);
2338 return (TOK_BQUOTE);
2340 if ((c=inchar(sc)) == '@') {
2341 return (TOK_ATMARK);
2350 } else if(c == '!') {
2351 while ((c=inchar(sc)) != '\n' && c!=EOF)
2355 port_increment_current_line(sc, &sc->load_stack[sc->file_i], 1);
2358 { return (TOK_EOF); }
2360 { return (token(sc));}
2363 if(is_one_of(" tfodxb\\",c)) {
2364 return TOK_SHARP_CONST;
2375 /* ========== Routines for Printing ========== */
2376 #define ok_abbrev(x) (is_pair(x) && cdr(x) == sc->NIL)
2378 static void printslashstring(scheme *sc, char *p, int len) {
2380 unsigned char *s=(unsigned char*)p;
2381 putcharacter(sc,'"');
2382 for ( i=0; i<len; i++) {
2383 if(*s==0xff || *s=='"' || *s<' ' || *s=='\\') {
2384 putcharacter(sc,'\\');
2387 putcharacter(sc,'"');
2390 putcharacter(sc,'n');
2393 putcharacter(sc,'t');
2396 putcharacter(sc,'r');
2399 putcharacter(sc,'\\');
2403 putcharacter(sc,'x');
2405 putcharacter(sc,d+'0');
2407 putcharacter(sc,d-10+'A');
2411 putcharacter(sc,d+'0');
2413 putcharacter(sc,d-10+'A');
2418 putcharacter(sc,*s);
2422 putcharacter(sc,'"');
2427 static void printatom(scheme *sc, pointer l, int f) {
2430 atom2str(sc,l,f,&p,&len);
2435 /* Uses internal buffer unless string pointer is already available */
2436 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen) {
2441 } else if (l == sc->T) {
2443 } else if (l == sc->F) {
2445 } else if (l == sc->EOF_OBJ) {
2447 } else if (is_port(l)) {
2449 } else if (is_number(l)) {
2451 if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */ {
2452 if(num_is_integer(l)) {
2453 snprintf(p, STRBUFFSIZE, "%ld", ivalue_unchecked(l));
2455 snprintf(p, STRBUFFSIZE, "%.10g", rvalue_unchecked(l));
2456 /* r5rs says there must be a '.' (unless 'e'?) */
2457 f = strcspn(p, ".e");
2459 p[f] = '.'; /* not found, so add '.0' at the end */
2468 snprintf(p, STRBUFFSIZE, "%lx", v);
2470 snprintf(p, STRBUFFSIZE, "-%lx", -v);
2471 } else if (f == 8) {
2473 snprintf(p, STRBUFFSIZE, "%lo", v);
2475 snprintf(p, STRBUFFSIZE, "-%lo", -v);
2476 } else if (f == 2) {
2477 unsigned long b = (v < 0) ? -v : v;
2478 p = &p[STRBUFFSIZE-1];
2480 do { *--p = (b&1) ? '1' : '0'; b >>= 1; } while (b != 0);
2481 if (v < 0) *--p = '-';
2484 } else if (is_string(l)) {
2487 *plen = strlength(l);
2489 } else { /* Hack, uses the fact that printing is needed */
2492 printslashstring(sc, strvalue(l), strlength(l));
2495 } else if (is_character(l)) {
2521 snprintf(p,STRBUFFSIZE, "#\\%s",charnames[c]);
2526 snprintf(p,STRBUFFSIZE,"#\\x%x",c);
2530 snprintf(p,STRBUFFSIZE,"#\\%c",c);
2534 } else if (is_symbol(l)) {
2536 } else if (is_proc(l)) {
2538 snprintf(p,STRBUFFSIZE,"#<%s PROCEDURE %ld>", procname(l),procnum(l));
2539 } else if (is_macro(l)) {
2541 } else if (is_closure(l)) {
2543 } else if (is_promise(l)) {
2545 } else if (is_foreign(l)) {
2547 snprintf(p,STRBUFFSIZE,"#<FOREIGN PROCEDURE %ld>", procnum(l));
2548 } else if (is_continuation(l)) {
2549 p = "#<CONTINUATION>";
2550 } else if (is_foreign_object(l)) {
2552 l->_object._foreign_object._vtable->to_string(sc, p, STRBUFFSIZE, l->_object._foreign_object._data);
2559 /* ========== Routines for Evaluation Cycle ========== */
2561 /* make closure. c is code. e is environment */
2562 static pointer mk_closure(scheme *sc, pointer c, pointer e) {
2563 pointer x = get_cell(sc, c, e);
2565 typeflag(x) = T_CLOSURE;
2571 /* make continuation. */
2572 static pointer mk_continuation(scheme *sc, pointer d) {
2573 pointer x = get_cell(sc, sc->NIL, d);
2575 typeflag(x) = T_CONTINUATION;
2580 static pointer list_star(scheme *sc, pointer d) {
2582 if(cdr(d)==sc->NIL) {
2585 p=cons(sc,car(d),cdr(d));
2587 while(cdr(cdr(p))!=sc->NIL) {
2588 d=cons(sc,car(p),cdr(p));
2589 if(cdr(cdr(p))!=sc->NIL) {
2597 /* reverse list -- produce new list */
2598 static pointer reverse(scheme *sc, pointer term, pointer list) {
2599 /* a must be checked by gc */
2600 pointer a = list, p = term;
2602 for ( ; is_pair(a); a = cdr(a)) {
2603 p = cons(sc, car(a), p);
2608 /* reverse list --- in-place */
2609 static pointer reverse_in_place(scheme *sc, pointer term, pointer list) {
2610 pointer p = list, result = term, q;
2612 while (p != sc->NIL) {
2621 /* append list -- produce new list (in reverse order) */
2622 static pointer revappend(scheme *sc, pointer a, pointer b) {
2626 while (is_pair(p)) {
2627 result = cons(sc, car(p), result);
2635 return sc->F; /* signal an error */
2638 /* equivalence of atoms */
2639 int eqv(pointer a, pointer b) {
2642 return (strvalue(a) == strvalue(b));
2645 } else if (is_number(a)) {
2647 if (num_is_integer(a) == num_is_integer(b))
2648 return num_eq(nvalue(a),nvalue(b));
2651 } else if (is_character(a)) {
2652 if (is_character(b))
2653 return charvalue(a)==charvalue(b);
2656 } else if (is_port(a)) {
2661 } else if (is_proc(a)) {
2663 return procnum(a)==procnum(b);
2671 /* true or false value macro */
2672 /* () is #t in R5RS */
2673 #define is_true(p) ((p) != sc->F)
2674 #define is_false(p) ((p) == sc->F)
2677 /* ========== Environment implementation ========== */
2679 #if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
2681 static int hash_fn(const char *key, int table_size)
2683 unsigned int hashed = 0;
2685 int bits_per_int = sizeof(unsigned int)*8;
2687 for (c = key; *c; c++) {
2688 /* letters have about 5 bits in them */
2689 hashed = (hashed<<5) | (hashed>>(bits_per_int-5));
2692 return hashed % table_size;
2696 /* Compares A and B. Returns an integer less than, equal to, or
2697 * greater than zero if A is stored at a memory location that is
2698 * numerical less than, equal to, or greater than that of B. */
2700 pointercmp(pointer a, pointer b)
2702 uintptr_t a_n = (uintptr_t) a;
2703 uintptr_t b_n = (uintptr_t) b;
2712 #ifndef USE_ALIST_ENV
2715 * In this implementation, each frame of the environment may be
2716 * a hash table: a vector of alists hashed by variable name.
2717 * In practice, we use a vector only for the initial frame;
2718 * subsequent frames are too small and transient for the lookup
2719 * speed to out-weigh the cost of making a new vector.
2722 static void new_frame_in_env(scheme *sc, pointer old_env)
2726 /* The interaction-environment has about 480 variables in it. */
2727 if (old_env == sc->NIL) {
2728 new_frame = mk_vector(sc, 751);
2730 new_frame = sc->NIL;
2734 sc->envir = immutable_cons(sc, new_frame, old_env);
2736 setenvironment(sc->envir);
2739 /* Find the slot in ENV under the key HDL. If ALL is given, look in
2740 * all environments enclosing ENV. If the lookup fails, and SSLOT is
2741 * given, the position where the new slot has to be inserted is stored
2744 find_slot_spec_in_env(scheme *sc, pointer env, pointer hdl, int all, pointer **sslot)
2750 assert(is_symbol(hdl));
2752 for (x = env; x != sc->NIL; x = cdr(x)) {
2753 if (is_vector(car(x))) {
2754 location = hash_fn(symname(hdl), vector_length(car(x)));
2755 sl = vector_elem_slot(car(x), location);
2759 for (y = *sl ; y != sc->NIL; sl = &cdr(y), y = *sl) {
2760 d = pointercmp(caar(y), hdl);
2762 return car(y); /* Hit. */
2767 if (x == env && sslot)
2768 *sslot = sl; /* Insert here. */
2771 return sc->NIL; /* Miss, and stop looking. */
2774 return sc->NIL; /* Not found in any environment. */
2777 #else /* USE_ALIST_ENV */
2779 static INLINE void new_frame_in_env(scheme *sc, pointer old_env)
2781 sc->envir = immutable_cons(sc, sc->NIL, old_env);
2782 setenvironment(sc->envir);
2785 /* Find the slot in ENV under the key HDL. If ALL is given, look in
2786 * all environments enclosing ENV. If the lookup fails, and SSLOT is
2787 * given, the position where the new slot has to be inserted is stored
2790 find_slot_spec_in_env(scheme *sc, pointer env, pointer hdl, int all, pointer **sslot)
2795 assert(is_symbol(hdl));
2797 for (x = env; x != sc->NIL; x = cdr(x)) {
2798 for (sl = &car(x), y = *sl; y != sc->NIL; sl = &cdr(y), y = *sl) {
2799 d = pointercmp(caar(y), hdl);
2801 return car(y); /* Hit. */
2806 if (x == env && sslot)
2807 *sslot = sl; /* Insert here. */
2810 return sc->NIL; /* Miss, and stop looking. */
2813 return sc->NIL; /* Not found in any environment. */
2816 #endif /* USE_ALIST_ENV else */
2818 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
2820 return find_slot_spec_in_env(sc, env, hdl, all, NULL);
2823 /* Insert (VARIABLE, VALUE) at SSLOT. SSLOT must be obtained using
2824 * find_slot_spec_in_env, and no insertion must be done between
2825 * obtaining SSLOT and the call to this function. */
2826 static INLINE void new_slot_spec_in_env(scheme *sc,
2827 pointer variable, pointer value,
2830 #define new_slot_spec_in_env_allocates 2
2832 gc_disable(sc, gc_reservations (new_slot_spec_in_env));
2833 slot = immutable_cons(sc, variable, value);
2834 *sslot = immutable_cons(sc, slot, *sslot);
2838 static INLINE void new_slot_in_env(scheme *sc, pointer variable, pointer value)
2840 #define new_slot_in_env_allocates new_slot_spec_in_env_allocates
2843 assert(is_symbol(variable));
2844 slot = find_slot_spec_in_env(sc, sc->envir, variable, 0, &sslot);
2845 assert(slot == sc->NIL);
2846 new_slot_spec_in_env(sc, variable, value, sslot);
2849 static INLINE void set_slot_in_env(scheme *sc, pointer slot, pointer value)
2855 static INLINE pointer slot_value_in_env(pointer slot)
2861 /* ========== Evaluation Cycle ========== */
2864 static enum scheme_opcodes
2865 _Error_1(scheme *sc, const char *s, pointer a) {
2866 const char *str = s;
2870 pointer hdl=sc->ERROR_HOOK;
2874 char sbuf[STRBUFFSIZE];
2877 history = history_flatten(sc);
2880 /* make sure error is not in REPL */
2881 if (((sc->load_stack[sc->file_i].kind & port_file) == 0
2882 || sc->load_stack[sc->file_i].rep.stdio.file != stdin)) {
2887 if (history != sc->NIL && has_tag(car(history))
2888 && (tag = get_tag(sc, car(history)))
2889 && is_string(car(tag)) && is_integer(cdr(tag))) {
2890 fname = string_value(car(tag));
2891 ln = ivalue_unchecked(cdr(tag));
2893 fname = string_value(sc->load_stack[sc->file_i].filename);
2894 ln = ivalue_unchecked(sc->load_stack[sc->file_i].curr_line);
2897 /* should never happen */
2898 if(!fname) fname = "<unknown>";
2900 /* we started from 0 */
2902 snprintf(sbuf, STRBUFFSIZE, "%s:%i: %s", fname, ln, s);
2904 str = (const char*)sbuf;
2909 x=find_slot_in_env(sc,sc->envir,hdl,1);
2911 sc->code = cons(sc, cons(sc, sc->QUOTE,
2912 cons(sc, history, sc->NIL)),
2915 sc->code = cons(sc, cons(sc, sc->QUOTE, cons(sc, a, sc->NIL)),
2918 sc->code = cons(sc, sc->F, sc->code);
2920 sc->code = cons(sc, mk_string(sc, str), sc->code);
2921 setimmutable(car(sc->code));
2922 sc->code = cons(sc, slot_value_in_env(x), sc->code);
2928 sc->args = cons(sc, (a), sc->NIL);
2932 sc->args = cons(sc, mk_string(sc, str), sc->args);
2933 setimmutable(car(sc->args));
2936 #define Error_1(sc,s, a) { op = _Error_1(sc,s,a); goto dispatch; }
2937 #define Error_0(sc,s) { op = _Error_1(sc,s,0); goto dispatch; }
2939 /* Too small to turn into function */
2941 # define END } while (0)
2945 /* Flags. The interpreter has a flags field. When the interpreter
2946 * pushes a frame to the dump stack, it is encoded with the opcode.
2947 * Therefore, we do not use the least significant byte. */
2949 /* Masks used to encode and decode opcode and flags. */
2950 #define S_OP_MASK 0x000000ff
2951 #define S_FLAG_MASK 0xffffff00
2953 /* Set if the interpreter evaluates an expression in a tail context
2954 * (see R5RS, section 3.5). If a function, procedure, or continuation
2955 * is invoked while this flag is set, the call is recorded as tail
2956 * call in the history buffer. */
2957 #define S_FLAG_TAIL_CONTEXT 0x00000100
2960 #define s_set_flag(sc, f) \
2962 (sc)->flags |= S_FLAG_ ## f; \
2966 #define s_clear_flag(sc, f) \
2968 (sc)->flags &= ~ S_FLAG_ ## f; \
2971 /* Check if flag F is set. */
2972 #define s_get_flag(sc, f) \
2973 !!((sc)->flags & S_FLAG_ ## f)
2977 /* Bounce back to Eval_Cycle and execute A. */
2978 #define s_goto(sc, a) { op = (a); goto dispatch; }
2980 #if USE_THREADED_CODE
2982 /* Do not bounce back to Eval_Cycle but execute A by jumping directly
2984 #define s_thread_to(sc, a) \
2990 /* Define a label OP and emit a case statement for OP. For use in the
2991 * dispatch function. The slightly peculiar goto that is never
2992 * executed avoids warnings about unused labels. */
2993 #define CASE(OP) case OP: if (0) goto OP; OP
2995 #else /* USE_THREADED_CODE */
2996 #define s_thread_to(sc, a) s_goto(sc, a)
2997 #define CASE(OP) case OP
2998 #endif /* USE_THREADED_CODE */
3000 /* Return to the previous frame on the dump stack, setting the current
3002 #define s_return(sc, a) s_goto(sc, _s_return(sc, a, 0))
3004 /* Return to the previous frame on the dump stack, setting the current
3005 * value to A, and re-enable the garbage collector. */
3006 #define s_return_enable_gc(sc, a) s_goto(sc, _s_return(sc, a, 1))
3008 static INLINE void dump_stack_reset(scheme *sc)
3013 static INLINE void dump_stack_initialize(scheme *sc)
3015 dump_stack_reset(sc);
3016 sc->frame_freelist = sc->NIL;
3019 static void dump_stack_free(scheme *sc)
3021 dump_stack_initialize(sc);
3024 const int frame_length = 4;
3027 dump_stack_make_frame(scheme *sc)
3031 frame = mk_vector(sc, frame_length);
3032 if (! sc->no_memory)
3038 static INLINE pointer *
3039 frame_slots(pointer frame)
3041 return &frame->_object._vector._elements[0];
3044 #define frame_payload vector_length
3047 dump_stack_allocate_frame(scheme *sc)
3049 pointer frame = sc->frame_freelist;
3050 if (frame == sc->NIL) {
3052 frame = dump_stack_make_frame(sc);
3054 gc_reservation_failure(sc);
3056 sc->frame_freelist = *frame_slots(frame);
3061 dump_stack_deallocate_frame(scheme *sc, pointer frame)
3063 pointer *p = frame_slots(frame);
3064 *p++ = sc->frame_freelist;
3068 sc->frame_freelist = frame;
3072 dump_stack_preallocate_frame(scheme *sc)
3074 pointer frame = dump_stack_make_frame(sc);
3075 if (! sc->no_memory)
3076 dump_stack_deallocate_frame(sc, frame);
3079 static enum scheme_opcodes
3080 _s_return(scheme *sc, pointer a, int enable_gc) {
3081 pointer dump = sc->dump;
3084 enum scheme_opcodes next_op;
3088 if (dump == sc->NIL)
3090 v = frame_payload(dump);
3091 next_op = (int) (v & S_OP_MASK);
3092 sc->flags = v & S_FLAG_MASK;
3093 p = frame_slots(dump);
3098 dump_stack_deallocate_frame(sc, dump);
3102 static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) {
3103 #define s_save_allocates 0
3106 gc_disable(sc, gc_reservations (s_save));
3107 dump = dump_stack_allocate_frame(sc);
3108 frame_payload(dump) = (size_t) (sc->flags | (unsigned long) op);
3109 p = frame_slots(dump);
3118 static INLINE void dump_stack_mark(scheme *sc)
3121 mark(sc->frame_freelist);
3129 history_free(scheme *sc)
3131 sc->free(sc->history.m);
3132 sc->history.tailstacks = sc->NIL;
3133 sc->history.callstack = sc->NIL;
3137 history_init(scheme *sc, size_t N, size_t M)
3140 struct history *h = &sc->history;
3145 assert ((N & h->mask_N) == 0);
3149 assert ((M & h->mask_M) == 0);
3151 h->callstack = mk_vector(sc, N);
3152 if (h->callstack == sc->sink)
3155 h->tailstacks = mk_vector(sc, N);
3156 for (i = 0; i < N; i++) {
3157 pointer tailstack = mk_vector(sc, M);
3158 if (tailstack == sc->sink)
3160 set_vector_elem(h->tailstacks, i, tailstack);
3163 h->m = sc->malloc(N * sizeof *h->m);
3167 for (i = 0; i < N; i++)
3178 history_mark(scheme *sc)
3180 struct history *h = &sc->history;
3182 mark(h->tailstacks);
3185 #define add_mod(a, b, mask) (((a) + (b)) & (mask))
3186 #define sub_mod(a, b, mask) add_mod(a, (mask) + 1 - (b), mask)
3189 tailstack_clear(scheme *sc, pointer v)
3191 assert(is_vector(v));
3193 fill_vector(v, sc->NIL);
3197 callstack_pop(scheme *sc)
3199 struct history *h = &sc->history;
3203 if (h->callstack == sc->NIL)
3206 item = vector_elem(h->callstack, n);
3207 /* Clear our frame so that it can be gc'ed and we don't run into it
3208 * when walking the history. */
3209 set_vector_elem(h->callstack, n, sc->NIL);
3210 tailstack_clear(sc, vector_elem(h->tailstacks, n));
3212 /* Exit from the frame. */
3213 h->n = sub_mod(h->n, 1, h->mask_N);
3219 callstack_push(scheme *sc, pointer item)
3221 struct history *h = &sc->history;
3224 if (h->callstack == sc->NIL)
3227 /* Enter a new frame. */
3228 n = h->n = add_mod(n, 1, h->mask_N);
3230 /* Initialize tail stack. */
3231 tailstack_clear(sc, vector_elem(h->tailstacks, n));
3232 h->m[n] = h->mask_M;
3234 set_vector_elem(h->callstack, n, item);
3238 tailstack_push(scheme *sc, pointer item)
3240 struct history *h = &sc->history;
3244 if (h->callstack == sc->NIL)
3247 /* Enter a new tail frame. */
3248 m = h->m[n] = add_mod(m, 1, h->mask_M);
3249 set_vector_elem(vector_elem(h->tailstacks, n), m, item);
3253 tailstack_flatten(scheme *sc, pointer tailstack, size_t i, size_t n,
3256 struct history *h = &sc->history;
3262 if (acc == sc->sink)
3266 /* We reached the end, but we did not see a unused frame. Signal
3267 this using '... . */
3268 return cons(sc, mk_symbol(sc, "..."), acc);
3271 frame = vector_elem(tailstack, n);
3272 if (frame == sc->NIL) {
3273 /* A unused frame. We reached the end of the history. */
3278 acc = cons(sc, frame, acc);
3280 return tailstack_flatten(sc, tailstack, i - 1, sub_mod(n, 1, h->mask_M),
3285 callstack_flatten(scheme *sc, size_t i, size_t n, pointer acc)
3287 struct history *h = &sc->history;
3293 if (acc == sc->sink)
3297 /* We reached the end, but we did not see a unused frame. Signal
3298 this using '... . */
3299 return cons(sc, mk_symbol(sc, "..."), acc);
3302 frame = vector_elem(h->callstack, n);
3303 if (frame == sc->NIL) {
3304 /* A unused frame. We reached the end of the history. */
3308 /* First, emit the tail calls. */
3309 acc = tailstack_flatten(sc, vector_elem(h->tailstacks, n), h->M, h->m[n],
3313 acc = cons(sc, frame, acc);
3315 return callstack_flatten(sc, i - 1, sub_mod(n, 1, h->mask_N), acc);
3319 history_flatten(scheme *sc)
3321 struct history *h = &sc->history;
3324 if (h->callstack == sc->NIL)
3327 history = callstack_flatten(sc, h->N, h->n, sc->NIL);
3328 if (history == sc->sink)
3331 return reverse_in_place(sc, sc->NIL, history);
3337 #else /* USE_HISTORY */
3339 #define history_init(SC, A, B) (void) 0
3340 #define history_free(SC) (void) 0
3341 #define callstack_pop(SC) (void) 0
3342 #define callstack_push(SC, X) (void) 0
3343 #define tailstack_push(SC, X) (void) 0
3345 #endif /* USE_HISTORY */
3351 get_property(scheme *sc, pointer obj, pointer key)
3355 assert (is_symbol(obj));
3356 assert (is_symbol(key));
3358 for (x = symprop(obj); x != sc->NIL; x = cdr(x)) {
3370 set_property(scheme *sc, pointer obj, pointer key, pointer value)
3372 #define set_property_allocates 2
3375 assert (is_symbol(obj));
3376 assert (is_symbol(key));
3378 for (x = symprop(obj); x != sc->NIL; x = cdr(x)) {
3386 gc_disable(sc, gc_reservations(set_property));
3387 symprop(obj) = cons(sc, cons(sc, key, value), symprop(obj));
3397 static int is_list(scheme *sc, pointer a)
3398 { return list_length(sc,a) >= 0; }
3404 dotted list: -2 minus length before dot
3406 int list_length(scheme *sc, pointer a) {
3413 if (fast == sc->NIL)
3419 if (fast == sc->NIL)
3426 /* Safe because we would have already returned if `fast'
3427 encountered a non-pair. */
3431 /* the fast pointer has looped back around and caught up
3432 with the slow pointer, hence the structure is circular,
3433 not of finite length, and therefore not a list */
3441 #define s_retbool(tf) s_return(sc,(tf) ? sc->T : sc->F)
3443 /* kernel of this interpreter */
3445 Eval_Cycle(scheme *sc, enum scheme_opcodes op) {
3453 int (*comp_func)(num, num) = NULL;
3454 const struct op_code_info *pcd;
3457 pcd = &dispatch_table[op];
3458 if (pcd->name[0] != 0) { /* if built-in function, check arguments */
3459 char msg[STRBUFFSIZE];
3460 if (! check_arguments (sc, pcd, msg, sizeof msg)) {
3461 s_goto(sc, _Error_1(sc, msg, 0));
3466 fprintf(stderr,"No memory!\n");
3469 ok_to_freely_gc(sc);
3472 CASE(OP_LOAD): /* load */
3473 if(file_interactive(sc)) {
3474 fprintf(sc->outport->_object._port->rep.stdio.file,
3475 "Loading %s\n", strvalue(car(sc->args)));
3477 if (!file_push(sc, car(sc->args))) {
3478 Error_1(sc,"unable to open", car(sc->args));
3482 sc->args = mk_integer(sc,sc->file_i);
3483 s_thread_to(sc,OP_T0LVL);
3486 CASE(OP_T0LVL): /* top level */
3487 /* If we reached the end of file, this loop is done. */
3488 if(sc->loadport->_object._port->kind & port_saw_EOF)
3493 sc->nesting = sc->nesting_stack[0];
3494 s_thread_to(sc,OP_QUIT);
3499 s_return(sc,sc->value);
3504 /* If interactive, be nice to user. */
3505 if(file_interactive(sc))
3507 sc->envir = sc->global_env;
3508 dump_stack_reset(sc);
3513 /* Set up another iteration of REPL */
3515 sc->save_inport=sc->inport;
3516 sc->inport = sc->loadport;
3517 s_save(sc,OP_T0LVL, sc->NIL, sc->NIL);
3518 s_save(sc,OP_VALUEPRINT, sc->NIL, sc->NIL);
3519 s_save(sc,OP_T1LVL, sc->NIL, sc->NIL);
3520 s_thread_to(sc,OP_READ_INTERNAL);
3522 CASE(OP_T1LVL): /* top level */
3523 sc->code = sc->value;
3524 sc->inport=sc->save_inport;
3525 s_thread_to(sc,OP_EVAL);
3527 CASE(OP_READ_INTERNAL): /* internal read */
3528 sc->tok = token(sc);
3529 if(sc->tok==TOK_EOF)
3530 { s_return(sc,sc->EOF_OBJ); }
3531 s_thread_to(sc,OP_RDSEXPR);
3534 s_return(sc, gensym(sc));
3536 CASE(OP_VALUEPRINT): /* print evaluation result */
3537 /* OP_VALUEPRINT is always pushed, because when changing from
3538 non-interactive to interactive mode, it needs to be
3539 already on the stack */
3541 putstr(sc,"\nGives: ");
3543 if(file_interactive(sc)) {
3545 sc->args = sc->value;
3546 s_thread_to(sc,OP_P0LIST);
3548 s_return(sc,sc->value);
3551 CASE(OP_EVAL): /* main part of evaluation */
3554 /*s_save(sc,OP_VALUEPRINT,sc->NIL,sc->NIL);*/
3555 s_save(sc,OP_REAL_EVAL,sc->args,sc->code);
3557 putstr(sc,"\nEval: ");
3558 s_thread_to(sc,OP_P0LIST);
3563 if (is_symbol(sc->code)) { /* symbol */
3564 x=find_slot_in_env(sc,sc->envir,sc->code,1);
3566 s_return(sc,slot_value_in_env(x));
3568 Error_1(sc, "eval: unbound variable", sc->code);
3570 } else if (is_pair(sc->code)) {
3571 if (is_syntax(x = car(sc->code))) { /* SYNTAX */
3572 sc->code = cdr(sc->code);
3573 s_goto(sc, syntaxnum(sc, x));
3574 } else {/* first, eval top element and eval arguments */
3575 s_save(sc,OP_E0ARGS, sc->NIL, sc->code);
3576 /* If no macros => s_save(sc,OP_E1ARGS, sc->NIL, cdr(sc->code));*/
3577 sc->code = car(sc->code);
3578 s_clear_flag(sc, TAIL_CONTEXT);
3579 s_thread_to(sc,OP_EVAL);
3582 s_return(sc,sc->code);
3585 CASE(OP_E0ARGS): /* eval arguments */
3586 if (is_macro(sc->value)) { /* macro expansion */
3587 gc_disable(sc, 1 + gc_reservations (s_save));
3588 s_save(sc,OP_DOMACRO, sc->NIL, sc->NIL);
3589 sc->args = cons(sc,sc->code, sc->NIL);
3591 sc->code = sc->value;
3592 s_clear_flag(sc, TAIL_CONTEXT);
3593 s_thread_to(sc,OP_APPLY);
3596 sc->args = cons(sc, sc->code, sc->NIL);
3598 sc->code = cdr(sc->code);
3599 s_thread_to(sc,OP_E1ARGS);
3602 CASE(OP_E1ARGS): /* eval arguments */
3604 sc->args = cons(sc, sc->value, sc->args);
3606 if (is_pair(sc->code)) { /* continue */
3607 s_save(sc,OP_E1ARGS, sc->args, cdr(sc->code));
3608 sc->code = car(sc->code);
3610 s_clear_flag(sc, TAIL_CONTEXT);
3611 s_thread_to(sc,OP_EVAL);
3613 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3614 s_thread_to(sc,OP_APPLY_CODE);
3620 sc->tracing=ivalue(car(sc->args));
3622 s_return_enable_gc(sc, mk_integer(sc, tr));
3627 CASE(OP_CALLSTACK_POP): /* pop the call stack */
3629 s_return(sc, sc->value);
3632 CASE(OP_APPLY_CODE): /* apply 'cadr(args)' to 'cddr(args)',
3633 * record in the history as invoked from
3635 free_cons(sc, sc->args, &callsite, &sc->args);
3636 sc->code = car(sc->args);
3637 sc->args = cdr(sc->args);
3640 CASE(OP_APPLY): /* apply 'code' to 'args' */
3643 s_save(sc,OP_REAL_APPLY,sc->args,sc->code);
3645 /* sc->args=cons(sc,sc->code,sc->args);*/
3646 putstr(sc,"\nApply to: ");
3647 s_thread_to(sc,OP_P0LIST);
3650 CASE(OP_REAL_APPLY):
3653 if (op != OP_APPLY_CODE)
3654 callsite = sc->code;
3655 if (s_get_flag(sc, TAIL_CONTEXT)) {
3656 /* We are evaluating a tail call. */
3657 tailstack_push(sc, callsite);
3659 callstack_push(sc, callsite);
3660 s_save(sc, OP_CALLSTACK_POP, sc->NIL, sc->NIL);
3664 if (is_proc(sc->code)) {
3665 s_goto(sc,procnum(sc->code)); /* PROCEDURE */
3666 } else if (is_foreign(sc->code))
3668 /* Keep nested calls from GC'ing the arglist */
3669 push_recent_alloc(sc,sc->args,sc->NIL);
3670 x=sc->code->_object._ff(sc,sc->args);
3672 } else if (is_closure(sc->code) || is_macro(sc->code)
3673 || is_promise(sc->code)) { /* CLOSURE */
3674 /* Should not accept promise */
3675 /* make environment */
3676 new_frame_in_env(sc, closure_env(sc->code));
3677 for (x = car(closure_code(sc->code)), y = sc->args;
3678 is_pair(x); x = cdr(x), y = cdr(y)) {
3680 Error_1(sc, "not enough arguments, missing", x);
3681 } else if (is_symbol(car(x))) {
3682 new_slot_in_env(sc, car(x), car(y));
3684 Error_1(sc, "syntax error in closure: not a symbol", car(x));
3690 Error_0(sc, "too many arguments");
3692 } else if (is_symbol(x))
3693 new_slot_in_env(sc, x, y);
3695 Error_1(sc, "syntax error in closure: not a symbol", x);
3697 sc->code = cdr(closure_code(sc->code));
3699 s_set_flag(sc, TAIL_CONTEXT);
3700 s_thread_to(sc,OP_BEGIN);
3701 } else if (is_continuation(sc->code)) { /* CONTINUATION */
3702 sc->dump = cont_dump(sc->code);
3703 s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL);
3705 Error_1(sc,"illegal function",sc->code);
3708 CASE(OP_DOMACRO): /* do macro */
3709 sc->code = sc->value;
3710 s_thread_to(sc,OP_EVAL);
3712 #if USE_COMPILE_HOOK
3713 CASE(OP_LAMBDA): /* lambda */
3714 /* If the hook is defined, apply it to sc->code, otherwise
3715 set sc->value fall through */
3717 pointer f=find_slot_in_env(sc,sc->envir,sc->COMPILE_HOOK,1);
3719 sc->value = sc->code;
3722 gc_disable(sc, 1 + gc_reservations (s_save));
3723 s_save(sc,OP_LAMBDA1,sc->args,sc->code);
3724 sc->args=cons(sc,sc->code,sc->NIL);
3726 sc->code=slot_value_in_env(f);
3727 s_thread_to(sc,OP_APPLY);
3732 CASE(OP_LAMBDA): /* lambda */
3733 sc->value = sc->code;
3739 s_return_enable_gc(sc, mk_closure(sc, sc->value, sc->envir));
3742 CASE(OP_MKCLOSURE): /* make-closure */
3744 if(car(x)==sc->LAMBDA) {
3747 if(cdr(sc->args)==sc->NIL) {
3753 s_return_enable_gc(sc, mk_closure(sc, x, y));
3755 CASE(OP_QUOTE): /* quote */
3756 s_return(sc,car(sc->code));
3758 CASE(OP_DEF0): /* define */
3759 if(is_immutable(car(sc->code)))
3760 Error_1(sc,"define: unable to alter immutable", car(sc->code));
3762 if (is_pair(car(sc->code))) {
3765 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
3769 sc->code = cadr(sc->code);
3771 if (!is_symbol(x)) {
3772 Error_0(sc,"variable is not a symbol");
3774 s_save(sc,OP_DEF1, sc->NIL, x);
3775 s_thread_to(sc,OP_EVAL);
3777 CASE(OP_DEF1): { /* define */
3779 x = find_slot_spec_in_env(sc, sc->envir, sc->code, 0, &sslot);
3781 set_slot_in_env(sc, x, sc->value);
3783 new_slot_spec_in_env(sc, sc->code, sc->value, sslot);
3785 s_return(sc,sc->code);
3788 CASE(OP_DEFP): /* defined? */
3790 if(cdr(sc->args)!=sc->NIL) {
3793 s_retbool(find_slot_in_env(sc,x,car(sc->args),1)!=sc->NIL);
3795 CASE(OP_SET0): /* set! */
3796 if(is_immutable(car(sc->code)))
3797 Error_1(sc,"set!: unable to alter immutable variable",car(sc->code));
3798 s_save(sc,OP_SET1, sc->NIL, car(sc->code));
3799 sc->code = cadr(sc->code);
3800 s_thread_to(sc,OP_EVAL);
3802 CASE(OP_SET1): /* set! */
3803 y=find_slot_in_env(sc,sc->envir,sc->code,1);
3805 set_slot_in_env(sc, y, sc->value);
3806 s_return(sc,sc->value);
3808 Error_1(sc, "set!: unbound variable", sc->code);
3812 CASE(OP_BEGIN): /* begin */
3816 if (!is_pair(sc->code)) {
3817 s_return(sc,sc->code);
3820 last = cdr(sc->code) == sc->NIL;
3822 s_save(sc,OP_BEGIN, sc->NIL, cdr(sc->code));
3824 sc->code = car(sc->code);
3826 /* This is not the end of the list. This is not a tail
3828 s_clear_flag(sc, TAIL_CONTEXT);
3829 s_thread_to(sc,OP_EVAL);
3832 CASE(OP_IF0): /* if */
3833 s_save(sc,OP_IF1, sc->NIL, cdr(sc->code));
3834 sc->code = car(sc->code);
3835 s_clear_flag(sc, TAIL_CONTEXT);
3836 s_thread_to(sc,OP_EVAL);
3838 CASE(OP_IF1): /* if */
3839 if (is_true(sc->value))
3840 sc->code = car(sc->code);
3842 sc->code = cadr(sc->code); /* (if #f 1) ==> () because
3843 * car(sc->NIL) = sc->NIL */
3844 s_thread_to(sc,OP_EVAL);
3846 CASE(OP_LET0): /* let */
3848 sc->value = sc->code;
3849 sc->code = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code);
3850 s_thread_to(sc,OP_LET1);
3852 CASE(OP_LET1): /* let (calculate parameters) */
3853 gc_disable(sc, 1 + (is_pair(sc->code) ? gc_reservations (s_save) : 0));
3854 sc->args = cons(sc, sc->value, sc->args);
3855 if (is_pair(sc->code)) { /* continue */
3856 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
3858 Error_1(sc, "Bad syntax of binding spec in let",
3861 s_save(sc,OP_LET1, sc->args, cdr(sc->code));
3863 sc->code = cadar(sc->code);
3865 s_clear_flag(sc, TAIL_CONTEXT);
3866 s_thread_to(sc,OP_EVAL);
3869 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3870 sc->code = car(sc->args);
3871 sc->args = cdr(sc->args);
3872 s_thread_to(sc,OP_LET2);
3875 CASE(OP_LET2): /* let */
3876 new_frame_in_env(sc, sc->envir);
3877 for (x = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code), y = sc->args;
3878 y != sc->NIL; x = cdr(x), y = cdr(y)) {
3879 new_slot_in_env(sc, caar(x), car(y));
3881 if (is_symbol(car(sc->code))) { /* named let */
3882 for (x = cadr(sc->code), sc->args = sc->NIL; x != sc->NIL; x = cdr(x)) {
3884 Error_1(sc, "Bad syntax of binding in let", x);
3885 if (!is_list(sc, car(x)))
3886 Error_1(sc, "Bad syntax of binding in let", car(x));
3888 sc->args = cons(sc, caar(x), sc->args);
3891 gc_disable(sc, 2 + gc_reservations (new_slot_in_env));
3892 x = mk_closure(sc, cons(sc, reverse_in_place(sc, sc->NIL, sc->args), cddr(sc->code)), sc->envir);
3893 new_slot_in_env(sc, car(sc->code), x);
3895 sc->code = cddr(sc->code);
3898 sc->code = cdr(sc->code);
3901 s_thread_to(sc,OP_BEGIN);
3903 CASE(OP_LET0AST): /* let* */
3904 if (car(sc->code) == sc->NIL) {
3905 new_frame_in_env(sc, sc->envir);
3906 sc->code = cdr(sc->code);
3907 s_thread_to(sc,OP_BEGIN);
3909 if(!is_pair(car(sc->code)) || !is_pair(caar(sc->code)) || !is_pair(cdaar(sc->code))) {
3910 Error_1(sc, "Bad syntax of binding spec in let*", car(sc->code));
3912 s_save(sc,OP_LET1AST, cdr(sc->code), car(sc->code));
3913 sc->code = cadaar(sc->code);
3914 s_clear_flag(sc, TAIL_CONTEXT);
3915 s_thread_to(sc,OP_EVAL);
3917 CASE(OP_LET1AST): /* let* (make new frame) */
3918 new_frame_in_env(sc, sc->envir);
3919 s_thread_to(sc,OP_LET2AST);
3921 CASE(OP_LET2AST): /* let* (calculate parameters) */
3922 new_slot_in_env(sc, caar(sc->code), sc->value);
3923 sc->code = cdr(sc->code);
3924 if (is_pair(sc->code)) { /* continue */
3925 s_save(sc,OP_LET2AST, sc->args, sc->code);
3926 sc->code = cadar(sc->code);
3928 s_clear_flag(sc, TAIL_CONTEXT);
3929 s_thread_to(sc,OP_EVAL);
3931 sc->code = sc->args;
3933 s_thread_to(sc,OP_BEGIN);
3936 CASE(OP_LET0REC): /* letrec */
3937 new_frame_in_env(sc, sc->envir);
3939 sc->value = sc->code;
3940 sc->code = car(sc->code);
3941 s_thread_to(sc,OP_LET1REC);
3943 CASE(OP_LET1REC): /* letrec (calculate parameters) */
3945 sc->args = cons(sc, sc->value, sc->args);
3947 if (is_pair(sc->code)) { /* continue */
3948 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
3949 Error_1(sc, "Bad syntax of binding spec in letrec",
3952 s_save(sc,OP_LET1REC, sc->args, cdr(sc->code));
3953 sc->code = cadar(sc->code);
3955 s_clear_flag(sc, TAIL_CONTEXT);
3956 s_thread_to(sc,OP_EVAL);
3958 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3959 sc->code = car(sc->args);
3960 sc->args = cdr(sc->args);
3961 s_thread_to(sc,OP_LET2REC);
3964 CASE(OP_LET2REC): /* letrec */
3965 for (x = car(sc->code), y = sc->args; y != sc->NIL; x = cdr(x), y = cdr(y)) {
3966 new_slot_in_env(sc, caar(x), car(y));
3968 sc->code = cdr(sc->code);
3970 s_thread_to(sc,OP_BEGIN);
3972 CASE(OP_COND0): /* cond */
3973 if (!is_pair(sc->code)) {
3974 Error_0(sc,"syntax error in cond");
3976 s_save(sc,OP_COND1, sc->NIL, sc->code);
3977 sc->code = caar(sc->code);
3978 s_clear_flag(sc, TAIL_CONTEXT);
3979 s_thread_to(sc,OP_EVAL);
3981 CASE(OP_COND1): /* cond */
3982 if (is_true(sc->value)) {
3983 if ((sc->code = cdar(sc->code)) == sc->NIL) {
3984 s_return(sc,sc->value);
3986 if(!sc->code || car(sc->code)==sc->FEED_TO) {
3987 if(!is_pair(cdr(sc->code))) {
3988 Error_0(sc,"syntax error in cond");
3991 x=cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL));
3992 sc->code=cons(sc,cadr(sc->code),cons(sc,x,sc->NIL));
3994 s_thread_to(sc,OP_EVAL);
3996 s_thread_to(sc,OP_BEGIN);
3998 if ((sc->code = cdr(sc->code)) == sc->NIL) {
3999 s_return(sc,sc->NIL);
4001 s_save(sc,OP_COND1, sc->NIL, sc->code);
4002 sc->code = caar(sc->code);
4003 s_clear_flag(sc, TAIL_CONTEXT);
4004 s_thread_to(sc,OP_EVAL);
4008 CASE(OP_DELAY): /* delay */
4010 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
4011 typeflag(x)=T_PROMISE;
4012 s_return_enable_gc(sc,x);
4014 CASE(OP_AND0): /* and */
4015 if (sc->code == sc->NIL) {
4018 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
4019 if (cdr(sc->code) != sc->NIL)
4020 s_clear_flag(sc, TAIL_CONTEXT);
4021 sc->code = car(sc->code);
4022 s_thread_to(sc,OP_EVAL);
4024 CASE(OP_AND1): /* and */
4025 if (is_false(sc->value)) {
4026 s_return(sc,sc->value);
4027 } else if (sc->code == sc->NIL) {
4028 s_return(sc,sc->value);
4030 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
4031 if (cdr(sc->code) != sc->NIL)
4032 s_clear_flag(sc, TAIL_CONTEXT);
4033 sc->code = car(sc->code);
4034 s_thread_to(sc,OP_EVAL);
4037 CASE(OP_OR0): /* or */
4038 if (sc->code == sc->NIL) {
4041 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
4042 if (cdr(sc->code) != sc->NIL)
4043 s_clear_flag(sc, TAIL_CONTEXT);
4044 sc->code = car(sc->code);
4045 s_thread_to(sc,OP_EVAL);
4047 CASE(OP_OR1): /* or */
4048 if (is_true(sc->value)) {
4049 s_return(sc,sc->value);
4050 } else if (sc->code == sc->NIL) {
4051 s_return(sc,sc->value);
4053 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
4054 if (cdr(sc->code) != sc->NIL)
4055 s_clear_flag(sc, TAIL_CONTEXT);
4056 sc->code = car(sc->code);
4057 s_thread_to(sc,OP_EVAL);
4060 CASE(OP_C0STREAM): /* cons-stream */
4061 s_save(sc,OP_C1STREAM, sc->NIL, cdr(sc->code));
4062 sc->code = car(sc->code);
4063 s_thread_to(sc,OP_EVAL);
4065 CASE(OP_C1STREAM): /* cons-stream */
4066 sc->args = sc->value; /* save sc->value to register sc->args for gc */
4068 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
4069 typeflag(x)=T_PROMISE;
4070 s_return_enable_gc(sc, cons(sc, sc->args, x));
4072 CASE(OP_MACRO0): /* macro */
4073 if (is_pair(car(sc->code))) {
4076 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
4080 sc->code = cadr(sc->code);
4082 if (!is_symbol(x)) {
4083 Error_0(sc,"variable is not a symbol");
4085 s_save(sc,OP_MACRO1, sc->NIL, x);
4086 s_thread_to(sc,OP_EVAL);
4088 CASE(OP_MACRO1): { /* macro */
4090 typeflag(sc->value) = T_MACRO;
4091 x = find_slot_spec_in_env(sc, sc->envir, sc->code, 0, &sslot);
4093 set_slot_in_env(sc, x, sc->value);
4095 new_slot_spec_in_env(sc, sc->code, sc->value, sslot);
4097 s_return(sc,sc->code);
4100 CASE(OP_CASE0): /* case */
4101 s_save(sc,OP_CASE1, sc->NIL, cdr(sc->code));
4102 sc->code = car(sc->code);
4103 s_clear_flag(sc, TAIL_CONTEXT);
4104 s_thread_to(sc,OP_EVAL);
4106 CASE(OP_CASE1): /* case */
4107 for (x = sc->code; x != sc->NIL; x = cdr(x)) {
4108 if (!is_pair(y = caar(x))) {
4111 for ( ; y != sc->NIL; y = cdr(y)) {
4112 if (eqv(car(y), sc->value)) {
4121 if (is_pair(caar(x))) {
4123 s_thread_to(sc,OP_BEGIN);
4125 s_save(sc,OP_CASE2, sc->NIL, cdar(x));
4127 s_thread_to(sc,OP_EVAL);
4130 s_return(sc,sc->NIL);
4133 CASE(OP_CASE2): /* case */
4134 if (is_true(sc->value)) {
4135 s_thread_to(sc,OP_BEGIN);
4137 s_return(sc,sc->NIL);
4140 CASE(OP_PAPPLY): /* apply */
4141 sc->code = car(sc->args);
4142 sc->args = list_star(sc,cdr(sc->args));
4143 /*sc->args = cadr(sc->args);*/
4144 s_thread_to(sc,OP_APPLY);
4146 CASE(OP_PEVAL): /* eval */
4147 if(cdr(sc->args)!=sc->NIL) {
4148 sc->envir=cadr(sc->args);
4150 sc->code = car(sc->args);
4151 s_thread_to(sc,OP_EVAL);
4153 CASE(OP_CONTINUATION): /* call-with-current-continuation */
4154 sc->code = car(sc->args);
4156 sc->args = cons(sc, mk_continuation(sc, sc->dump), sc->NIL);
4158 s_thread_to(sc,OP_APPLY);
4161 CASE(OP_INEX2EX): /* inexact->exact */
4163 if(num_is_integer(x)) {
4165 } else if(modf(rvalue_unchecked(x),&dd)==0.0) {
4166 s_return(sc,mk_integer(sc,ivalue(x)));
4168 Error_1(sc, "inexact->exact: not integral", x);
4173 s_return(sc, mk_real(sc, exp(rvalue(x))));
4177 s_return(sc, mk_real(sc, log(rvalue(x))));
4181 s_return(sc, mk_real(sc, sin(rvalue(x))));
4185 s_return(sc, mk_real(sc, cos(rvalue(x))));
4189 s_return(sc, mk_real(sc, tan(rvalue(x))));
4193 s_return(sc, mk_real(sc, asin(rvalue(x))));
4197 s_return(sc, mk_real(sc, acos(rvalue(x))));
4201 if(cdr(sc->args)==sc->NIL) {
4202 s_return(sc, mk_real(sc, atan(rvalue(x))));
4204 pointer y=cadr(sc->args);
4205 s_return(sc, mk_real(sc, atan2(rvalue(x),rvalue(y))));
4210 s_return(sc, mk_real(sc, sqrt(rvalue(x))));
4215 pointer y=cadr(sc->args);
4217 if (num_is_integer(x) && num_is_integer(y))
4219 /* This 'if' is an R5RS compatibility fix. */
4220 /* NOTE: Remove this 'if' fix for R6RS. */
4221 if (rvalue(x) == 0 && rvalue(y) < 0) {
4224 result = pow(rvalue(x),rvalue(y));
4226 /* Before returning integer result make sure we can. */
4227 /* If the test fails, result is too big for integer. */
4230 long result_as_long = (long)result;
4231 if (result != (double)result_as_long)
4235 s_return(sc, mk_real(sc, result));
4237 s_return(sc, mk_integer(sc, result));
4243 s_return(sc, mk_real(sc, floor(rvalue(x))));
4247 s_return(sc, mk_real(sc, ceil(rvalue(x))));
4249 CASE(OP_TRUNCATE ): {
4250 double rvalue_of_x ;
4252 rvalue_of_x = rvalue(x) ;
4253 if (rvalue_of_x > 0) {
4254 s_return(sc, mk_real(sc, floor(rvalue_of_x)));
4256 s_return(sc, mk_real(sc, ceil(rvalue_of_x)));
4262 if (num_is_integer(x))
4264 s_return(sc, mk_real(sc, round_per_R5RS(rvalue(x))));
4267 CASE(OP_ADD): /* + */
4269 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4270 v=num_add(v,nvalue(car(x)));
4273 s_return_enable_gc(sc, mk_number(sc, v));
4275 CASE(OP_MUL): /* * */
4277 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4278 v=num_mul(v,nvalue(car(x)));
4281 s_return_enable_gc(sc, mk_number(sc, v));
4283 CASE(OP_SUB): /* - */
4284 if(cdr(sc->args)==sc->NIL) {
4289 v = nvalue(car(sc->args));
4291 for (; x != sc->NIL; x = cdr(x)) {
4292 v=num_sub(v,nvalue(car(x)));
4295 s_return_enable_gc(sc, mk_number(sc, v));
4297 CASE(OP_DIV): /* / */
4298 if(cdr(sc->args)==sc->NIL) {
4303 v = nvalue(car(sc->args));
4305 for (; x != sc->NIL; x = cdr(x)) {
4306 if (!is_zero_double(rvalue(car(x))))
4307 v=num_div(v,nvalue(car(x)));
4309 Error_0(sc,"/: division by zero");
4313 s_return_enable_gc(sc, mk_number(sc, v));
4315 CASE(OP_INTDIV): /* quotient */
4316 if(cdr(sc->args)==sc->NIL) {
4321 v = nvalue(car(sc->args));
4323 for (; x != sc->NIL; x = cdr(x)) {
4324 if (ivalue(car(x)) != 0)
4325 v=num_intdiv(v,nvalue(car(x)));
4327 Error_0(sc,"quotient: division by zero");
4331 s_return_enable_gc(sc, mk_number(sc, v));
4333 CASE(OP_REM): /* remainder */
4334 v = nvalue(car(sc->args));
4335 if (ivalue(cadr(sc->args)) != 0)
4336 v=num_rem(v,nvalue(cadr(sc->args)));
4338 Error_0(sc,"remainder: division by zero");
4341 s_return_enable_gc(sc, mk_number(sc, v));
4343 CASE(OP_MOD): /* modulo */
4344 v = nvalue(car(sc->args));
4345 if (ivalue(cadr(sc->args)) != 0)
4346 v=num_mod(v,nvalue(cadr(sc->args)));
4348 Error_0(sc,"modulo: division by zero");
4351 s_return_enable_gc(sc, mk_number(sc, v));
4353 CASE(OP_CAR): /* car */
4354 s_return(sc,caar(sc->args));
4356 CASE(OP_CDR): /* cdr */
4357 s_return(sc,cdar(sc->args));
4359 CASE(OP_CONS): /* cons */
4360 cdr(sc->args) = cadr(sc->args);
4361 s_return(sc,sc->args);
4363 CASE(OP_SETCAR): /* set-car! */
4364 if(!is_immutable(car(sc->args))) {
4365 caar(sc->args) = cadr(sc->args);
4366 s_return(sc,car(sc->args));
4368 Error_0(sc,"set-car!: unable to alter immutable pair");
4371 CASE(OP_SETCDR): /* set-cdr! */
4372 if(!is_immutable(car(sc->args))) {
4373 cdar(sc->args) = cadr(sc->args);
4374 s_return(sc,car(sc->args));
4376 Error_0(sc,"set-cdr!: unable to alter immutable pair");
4379 CASE(OP_CHAR2INT): { /* char->integer */
4381 c=(char)ivalue(car(sc->args));
4383 s_return_enable_gc(sc, mk_integer(sc, (unsigned char) c));
4386 CASE(OP_INT2CHAR): { /* integer->char */
4388 c=(unsigned char)ivalue(car(sc->args));
4390 s_return_enable_gc(sc, mk_character(sc, (char) c));
4393 CASE(OP_CHARUPCASE): {
4395 c=(unsigned char)ivalue(car(sc->args));
4398 s_return_enable_gc(sc, mk_character(sc, (char) c));
4401 CASE(OP_CHARDNCASE): {
4403 c=(unsigned char)ivalue(car(sc->args));
4406 s_return_enable_gc(sc, mk_character(sc, (char) c));
4409 CASE(OP_STR2SYM): /* string->symbol */
4410 gc_disable(sc, gc_reservations (mk_symbol));
4411 s_return_enable_gc(sc, mk_symbol(sc, strvalue(car(sc->args))));
4413 CASE(OP_STR2ATOM): /* string->atom */ {
4414 char *s=strvalue(car(sc->args));
4416 if(cdr(sc->args)!=sc->NIL) {
4417 /* we know cadr(sc->args) is a natural number */
4418 /* see if it is 2, 8, 10, or 16, or error */
4419 pf = ivalue_unchecked(cadr(sc->args));
4420 if(pf == 16 || pf == 10 || pf == 8 || pf == 2) {
4428 Error_1(sc, "string->atom: bad base", cadr(sc->args));
4429 } else if(*s=='#') /* no use of base! */ {
4430 s_return(sc, mk_sharp_const(sc, s+1));
4432 if (pf == 0 || pf == 10) {
4433 s_return(sc, mk_atom(sc, s));
4437 long iv = strtol(s,&ep,(int )pf);
4439 s_return(sc, mk_integer(sc, iv));
4442 s_return(sc, sc->F);
4448 CASE(OP_SYM2STR): /* symbol->string */
4450 x=mk_string(sc,symname(car(sc->args)));
4452 s_return_enable_gc(sc, x);
4454 CASE(OP_ATOM2STR): /* atom->string */ {
4457 if(cdr(sc->args)!=sc->NIL) {
4458 /* we know cadr(sc->args) is a natural number */
4459 /* see if it is 2, 8, 10, or 16, or error */
4460 pf = ivalue_unchecked(cadr(sc->args));
4461 if(is_number(x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2)) {
4469 Error_1(sc, "atom->string: bad base", cadr(sc->args));
4470 } else if(is_number(x) || is_character(x) || is_string(x) || is_symbol(x)) {
4473 atom2str(sc,x,(int )pf,&p,&len);
4475 s_return_enable_gc(sc, mk_counted_string(sc, p, len));
4477 Error_1(sc, "atom->string: not an atom", x);
4481 CASE(OP_MKSTRING): { /* make-string */
4485 len=ivalue(car(sc->args));
4487 if(cdr(sc->args)!=sc->NIL) {
4488 fill=charvalue(cadr(sc->args));
4491 s_return_enable_gc(sc, mk_empty_string(sc, len, (char) fill));
4494 CASE(OP_STRLEN): /* string-length */
4496 s_return_enable_gc(sc, mk_integer(sc, strlength(car(sc->args))));
4498 CASE(OP_STRREF): { /* string-ref */
4502 str=strvalue(car(sc->args));
4504 index=ivalue(cadr(sc->args));
4506 if(index>=strlength(car(sc->args))) {
4507 Error_1(sc, "string-ref: out of bounds", cadr(sc->args));
4511 s_return_enable_gc(sc,
4512 mk_character(sc, ((unsigned char*) str)[index]));
4515 CASE(OP_STRSET): { /* string-set! */
4520 if(is_immutable(car(sc->args))) {
4521 Error_1(sc, "string-set!: unable to alter immutable string",
4524 str=strvalue(car(sc->args));
4526 index=ivalue(cadr(sc->args));
4527 if(index>=strlength(car(sc->args))) {
4528 Error_1(sc, "string-set!: out of bounds", cadr(sc->args));
4531 c=charvalue(caddr(sc->args));
4534 s_return(sc,car(sc->args));
4537 CASE(OP_STRAPPEND): { /* string-append */
4538 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4543 /* compute needed length for new string */
4544 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4545 len += strlength(car(x));
4548 newstr = mk_empty_string(sc, len, ' ');
4549 /* store the contents of the argument strings into the new string */
4550 for (pos = strvalue(newstr), x = sc->args; x != sc->NIL;
4551 pos += strlength(car(x)), x = cdr(x)) {
4552 memcpy(pos, strvalue(car(x)), strlength(car(x)));
4554 s_return_enable_gc(sc, newstr);
4557 CASE(OP_SUBSTR): { /* substring */
4562 str=strvalue(car(sc->args));
4564 index0=ivalue(cadr(sc->args));
4566 if(index0>strlength(car(sc->args))) {
4567 Error_1(sc, "substring: start out of bounds", cadr(sc->args));
4570 if(cddr(sc->args)!=sc->NIL) {
4571 index1=ivalue(caddr(sc->args));
4572 if(index1>strlength(car(sc->args)) || index1<index0) {
4573 Error_1(sc, "substring: end out of bounds", caddr(sc->args));
4576 index1=strlength(car(sc->args));
4580 s_return_enable_gc(sc, mk_counted_string(sc, str + index0, index1 - index0));
4583 CASE(OP_VECTOR): { /* vector */
4586 int len=list_length(sc,sc->args);
4588 Error_1(sc, "vector: not a proper list", sc->args);
4590 vec=mk_vector(sc,len);
4591 if(sc->no_memory) { s_return(sc, sc->sink); }
4592 for (x = sc->args, i = 0; is_pair(x); x = cdr(x), i++) {
4593 set_vector_elem(vec,i,car(x));
4598 CASE(OP_MKVECTOR): { /* make-vector */
4599 pointer fill=sc->NIL;
4603 len=ivalue(car(sc->args));
4605 if(cdr(sc->args)!=sc->NIL) {
4606 fill=cadr(sc->args);
4608 vec=mk_vector(sc,len);
4609 if(sc->no_memory) { s_return(sc, sc->sink); }
4611 fill_vector(vec,fill);
4616 CASE(OP_VECLEN): /* vector-length */
4618 s_return_enable_gc(sc, mk_integer(sc, vector_length(car(sc->args))));
4620 CASE(OP_VECREF): { /* vector-ref */
4623 index=ivalue(cadr(sc->args));
4625 if(index >= vector_length(car(sc->args))) {
4626 Error_1(sc, "vector-ref: out of bounds", cadr(sc->args));
4629 s_return(sc,vector_elem(car(sc->args),index));
4632 CASE(OP_VECSET): { /* vector-set! */
4635 if(is_immutable(car(sc->args))) {
4636 Error_1(sc, "vector-set!: unable to alter immutable vector",
4640 index=ivalue(cadr(sc->args));
4641 if(index >= vector_length(car(sc->args))) {
4642 Error_1(sc, "vector-set!: out of bounds", cadr(sc->args));
4645 set_vector_elem(car(sc->args),index,caddr(sc->args));
4646 s_return(sc,car(sc->args));
4649 CASE(OP_NOT): /* not */
4650 s_retbool(is_false(car(sc->args)));
4651 CASE(OP_BOOLP): /* boolean? */
4652 s_retbool(car(sc->args) == sc->F || car(sc->args) == sc->T);
4653 CASE(OP_EOFOBJP): /* boolean? */
4654 s_retbool(car(sc->args) == sc->EOF_OBJ);
4655 CASE(OP_NULLP): /* null? */
4656 s_retbool(car(sc->args) == sc->NIL);
4657 CASE(OP_NUMEQ): /* = */
4659 CASE(OP_LESS): /* < */
4661 CASE(OP_GRE): /* > */
4663 CASE(OP_LEQ): /* <= */
4665 CASE(OP_GEQ): /* >= */
4667 case OP_NUMEQ: comp_func=num_eq; break;
4668 case OP_LESS: comp_func=num_lt; break;
4669 case OP_GRE: comp_func=num_gt; break;
4670 case OP_LEQ: comp_func=num_le; break;
4671 case OP_GEQ: comp_func=num_ge; break;
4672 default: assert (! "reached");
4678 for (; x != sc->NIL; x = cdr(x)) {
4679 if(!comp_func(v,nvalue(car(x)))) {
4685 CASE(OP_SYMBOLP): /* symbol? */
4686 s_retbool(is_symbol(car(sc->args)));
4687 CASE(OP_NUMBERP): /* number? */
4688 s_retbool(is_number(car(sc->args)));
4689 CASE(OP_STRINGP): /* string? */
4690 s_retbool(is_string(car(sc->args)));
4691 CASE(OP_INTEGERP): /* integer? */
4692 s_retbool(is_integer(car(sc->args)));
4693 CASE(OP_REALP): /* real? */
4694 s_retbool(is_number(car(sc->args))); /* All numbers are real */
4695 CASE(OP_CHARP): /* char? */
4696 s_retbool(is_character(car(sc->args)));
4697 #if USE_CHAR_CLASSIFIERS
4698 CASE(OP_CHARAP): /* char-alphabetic? */
4699 s_retbool(Cisalpha(ivalue(car(sc->args))));
4700 CASE(OP_CHARNP): /* char-numeric? */
4701 s_retbool(Cisdigit(ivalue(car(sc->args))));
4702 CASE(OP_CHARWP): /* char-whitespace? */
4703 s_retbool(Cisspace(ivalue(car(sc->args))));
4704 CASE(OP_CHARUP): /* char-upper-case? */
4705 s_retbool(Cisupper(ivalue(car(sc->args))));
4706 CASE(OP_CHARLP): /* char-lower-case? */
4707 s_retbool(Cislower(ivalue(car(sc->args))));
4709 CASE(OP_PORTP): /* port? */
4710 s_retbool(is_port(car(sc->args)));
4711 CASE(OP_INPORTP): /* input-port? */
4712 s_retbool(is_inport(car(sc->args)));
4713 CASE(OP_OUTPORTP): /* output-port? */
4714 s_retbool(is_outport(car(sc->args)));
4715 CASE(OP_PROCP): /* procedure? */
4717 * continuation should be procedure by the example
4718 * (call-with-current-continuation procedure?) ==> #t
4719 * in R^3 report sec. 6.9
4721 s_retbool(is_proc(car(sc->args)) || is_closure(car(sc->args))
4722 || is_continuation(car(sc->args)) || is_foreign(car(sc->args)));
4723 CASE(OP_PAIRP): /* pair? */
4724 s_retbool(is_pair(car(sc->args)));
4725 CASE(OP_LISTP): /* list? */
4726 s_retbool(list_length(sc,car(sc->args)) >= 0);
4728 CASE(OP_ENVP): /* environment? */
4729 s_retbool(is_environment(car(sc->args)));
4730 CASE(OP_VECTORP): /* vector? */
4731 s_retbool(is_vector(car(sc->args)));
4732 CASE(OP_EQ): /* eq? */
4733 s_retbool(car(sc->args) == cadr(sc->args));
4734 CASE(OP_EQV): /* eqv? */
4735 s_retbool(eqv(car(sc->args), cadr(sc->args)));
4737 CASE(OP_FORCE): /* force */
4738 sc->code = car(sc->args);
4739 if (is_promise(sc->code)) {
4740 /* Should change type to closure here */
4741 s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code);
4743 s_thread_to(sc,OP_APPLY);
4745 s_return(sc,sc->code);
4748 CASE(OP_SAVE_FORCED): /* Save forced value replacing promise */
4749 copy_value(sc, sc->code, sc->value);
4750 s_return(sc,sc->value);
4752 CASE(OP_WRITE): /* write */
4754 CASE(OP_DISPLAY): /* display */
4756 CASE(OP_WRITE_CHAR): /* write-char */
4757 if(is_pair(cdr(sc->args))) {
4758 if(cadr(sc->args)!=sc->outport) {
4759 x=cons(sc,sc->outport,sc->NIL);
4760 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
4761 sc->outport=cadr(sc->args);
4764 sc->args = car(sc->args);
4770 s_thread_to(sc,OP_P0LIST);
4772 CASE(OP_NEWLINE): /* newline */
4773 if(is_pair(sc->args)) {
4774 if(car(sc->args)!=sc->outport) {
4775 x=cons(sc,sc->outport,sc->NIL);
4776 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
4777 sc->outport=car(sc->args);
4783 CASE(OP_ERR0): /* error */
4785 if (!is_string(car(sc->args))) {
4786 sc->args=cons(sc,mk_string(sc," -- "),sc->args);
4787 setimmutable(car(sc->args));
4789 putstr(sc, "Error: ");
4790 putstr(sc, strvalue(car(sc->args)));
4791 sc->args = cdr(sc->args);
4792 s_thread_to(sc,OP_ERR1);
4794 CASE(OP_ERR1): /* error */
4796 if (sc->args != sc->NIL) {
4797 s_save(sc,OP_ERR1, cdr(sc->args), sc->NIL);
4798 sc->args = car(sc->args);
4800 s_thread_to(sc,OP_P0LIST);
4803 if(sc->interactive_repl) {
4804 s_thread_to(sc,OP_T0LVL);
4810 CASE(OP_REVERSE): /* reverse */
4811 s_return(sc,reverse(sc, sc->NIL, car(sc->args)));
4813 CASE(OP_REVERSE_IN_PLACE): /* reverse! */
4814 s_return(sc, reverse_in_place(sc, sc->NIL, car(sc->args)));
4816 CASE(OP_LIST_STAR): /* list* */
4817 s_return(sc,list_star(sc,sc->args));
4819 CASE(OP_APPEND): /* append */
4826 /* cdr() in the while condition is not a typo. If car() */
4827 /* is used (append '() 'a) will return the wrong result.*/
4828 while (cdr(y) != sc->NIL) {
4829 x = revappend(sc, x, car(y));
4832 Error_0(sc, "non-list argument to append");
4836 s_return(sc, reverse_in_place(sc, car(y), x));
4839 CASE(OP_SET_SYMBOL_PROPERTY): /* set-symbol-property! */
4840 gc_disable(sc, gc_reservations(set_property));
4841 s_return_enable_gc(sc,
4842 set_property(sc, car(sc->args),
4843 cadr(sc->args), caddr(sc->args)));
4845 CASE(OP_SYMBOL_PROPERTY): /* symbol-property */
4846 s_return(sc, get_property(sc, car(sc->args), cadr(sc->args)));
4847 #endif /* USE_PLIST */
4849 CASE(OP_TAG_VALUE): { /* not exposed */
4850 /* This tags sc->value with car(sc->args). Useful to tag
4851 * results of opcode evaluations. */
4853 free_cons(sc, sc->args, &a, &b);
4854 free_cons(sc, b, &b, &c);
4855 assert(c == sc->NIL);
4856 s_return(sc, mk_tagged_value(sc, sc->value, a, b));
4859 CASE(OP_MK_TAGGED): /* make-tagged-value */
4860 if (is_vector(car(sc->args)))
4861 Error_0(sc, "cannot tag vector");
4862 s_return(sc, mk_tagged_value(sc, car(sc->args),
4863 car(cadr(sc->args)),
4864 cdr(cadr(sc->args))));
4866 CASE(OP_GET_TAG): /* get-tag */
4867 s_return(sc, get_tag(sc, car(sc->args)));
4869 CASE(OP_QUIT): /* quit */
4870 if(is_pair(sc->args)) {
4871 sc->retcode=ivalue(car(sc->args));
4875 CASE(OP_GC): /* gc */
4876 gc(sc, sc->NIL, sc->NIL);
4879 CASE(OP_GCVERB): /* gc-verbose */
4880 { int was = sc->gc_verbose;
4882 sc->gc_verbose = (car(sc->args) != sc->F);
4886 CASE(OP_NEWSEGMENT): /* new-segment */
4887 if (!is_pair(sc->args) || !is_number(car(sc->args))) {
4888 Error_0(sc,"new-segment: argument must be a number");
4890 alloc_cellseg(sc, (int) ivalue(car(sc->args)));
4893 CASE(OP_OBLIST): /* oblist */
4894 s_return(sc, oblist_all_symbols(sc));
4896 CASE(OP_CURR_INPORT): /* current-input-port */
4897 s_return(sc,sc->inport);
4899 CASE(OP_CURR_OUTPORT): /* current-output-port */
4900 s_return(sc,sc->outport);
4902 CASE(OP_OPEN_INFILE): /* open-input-file */
4904 CASE(OP_OPEN_OUTFILE): /* open-output-file */
4906 CASE(OP_OPEN_INOUTFILE): /* open-input-output-file */ {
4910 case OP_OPEN_INFILE: prop=port_input; break;
4911 case OP_OPEN_OUTFILE: prop=port_output; break;
4912 case OP_OPEN_INOUTFILE: prop=port_input|port_output; break;
4913 default: assert (! "reached");
4915 p=port_from_filename(sc,strvalue(car(sc->args)),prop);
4923 #if USE_STRING_PORTS
4924 CASE(OP_OPEN_INSTRING): /* open-input-string */
4926 CASE(OP_OPEN_INOUTSTRING): /* open-input-output-string */ {
4930 case OP_OPEN_INSTRING: prop=port_input; break;
4931 case OP_OPEN_INOUTSTRING: prop=port_input|port_output; break;
4932 default: assert (! "reached");
4934 p=port_from_string(sc, strvalue(car(sc->args)),
4935 strvalue(car(sc->args))+strlength(car(sc->args)), prop);
4941 CASE(OP_OPEN_OUTSTRING): /* open-output-string */ {
4943 if(car(sc->args)==sc->NIL) {
4944 p=port_from_scratch(sc);
4949 p=port_from_string(sc, strvalue(car(sc->args)),
4950 strvalue(car(sc->args))+strlength(car(sc->args)),
4958 CASE(OP_GET_OUTSTRING): /* get-output-string */ {
4961 if ((p=car(sc->args)->_object._port)->kind&port_string) {
4965 mk_counted_string(sc,
4966 p->rep.string.start,
4967 p->rep.string.curr - p->rep.string.start));
4973 CASE(OP_CLOSE_INPORT): /* close-input-port */
4974 port_close(sc,car(sc->args),port_input);
4977 CASE(OP_CLOSE_OUTPORT): /* close-output-port */
4978 port_close(sc,car(sc->args),port_output);
4981 CASE(OP_INT_ENV): /* interaction-environment */
4982 s_return(sc,sc->global_env);
4984 CASE(OP_CURR_ENV): /* current-environment */
4985 s_return(sc,sc->envir);
4988 /* ========== reading part ========== */
4990 if(!is_pair(sc->args)) {
4991 s_thread_to(sc,OP_READ_INTERNAL);
4993 if(!is_inport(car(sc->args))) {
4994 Error_1(sc, "read: not an input port", car(sc->args));
4996 if(car(sc->args)==sc->inport) {
4997 s_thread_to(sc,OP_READ_INTERNAL);
5000 sc->inport=car(sc->args);
5001 x=cons(sc,x,sc->NIL);
5002 s_save(sc,OP_SET_INPORT, x, sc->NIL);
5003 s_thread_to(sc,OP_READ_INTERNAL);
5005 CASE(OP_READ_CHAR): /* read-char */
5007 CASE(OP_PEEK_CHAR): /* peek-char */ {
5009 if(is_pair(sc->args)) {
5010 if(car(sc->args)!=sc->inport) {
5012 x=cons(sc,x,sc->NIL);
5013 s_save(sc,OP_SET_INPORT, x, sc->NIL);
5014 sc->inport=car(sc->args);
5019 s_return(sc,sc->EOF_OBJ);
5021 if(op==OP_PEEK_CHAR) {
5024 s_return(sc,mk_character(sc,c));
5027 CASE(OP_CHAR_READY): /* char-ready? */ {
5028 pointer p=sc->inport;
5030 if(is_pair(sc->args)) {
5033 res=p->_object._port->kind&port_string;
5037 CASE(OP_SET_INPORT): /* set-input-port */
5038 sc->inport=car(sc->args);
5039 s_return(sc,sc->value);
5041 CASE(OP_SET_OUTPORT): /* set-output-port */
5042 sc->outport=car(sc->args);
5043 s_return(sc,sc->value);
5048 s_return(sc,sc->EOF_OBJ);
5051 s_save(sc,OP_RDVEC,sc->NIL,sc->NIL);
5054 sc->tok = token(sc);
5055 if (sc->tok == TOK_RPAREN) {
5056 s_return(sc,sc->NIL);
5057 } else if (sc->tok == TOK_DOT) {
5058 Error_0(sc,"syntax error: illegal dot expression");
5064 sc->nesting_stack[sc->file_i]++;
5066 filename = sc->load_stack[sc->file_i].filename;
5067 lineno = sc->load_stack[sc->file_i].curr_line;
5069 s_save(sc, OP_TAG_VALUE,
5070 cons(sc, filename, cons(sc, lineno, sc->NIL)),
5073 s_save(sc,OP_RDLIST, sc->NIL, sc->NIL);
5074 s_thread_to(sc,OP_RDSEXPR);
5077 s_save(sc,OP_RDQUOTE, sc->NIL, sc->NIL);
5078 sc->tok = token(sc);
5079 s_thread_to(sc,OP_RDSEXPR);
5081 sc->tok = token(sc);
5082 if(sc->tok==TOK_VEC) {
5083 s_save(sc,OP_RDQQUOTEVEC, sc->NIL, sc->NIL);
5085 s_thread_to(sc,OP_RDSEXPR);
5087 s_save(sc,OP_RDQQUOTE, sc->NIL, sc->NIL);
5089 s_thread_to(sc,OP_RDSEXPR);
5091 s_save(sc,OP_RDUNQUOTE, sc->NIL, sc->NIL);
5092 sc->tok = token(sc);
5093 s_thread_to(sc,OP_RDSEXPR);
5095 s_save(sc,OP_RDUQTSP, sc->NIL, sc->NIL);
5096 sc->tok = token(sc);
5097 s_thread_to(sc,OP_RDSEXPR);
5099 s_return(sc,mk_atom(sc, readstr_upto(sc, DELIMITERS)));
5103 Error_0(sc,"Error reading string");
5108 pointer f=find_slot_in_env(sc,sc->envir,sc->SHARP_HOOK,1);
5110 Error_0(sc,"undefined sharp expression");
5112 sc->code=cons(sc,slot_value_in_env(f),sc->NIL);
5113 s_thread_to(sc,OP_EVAL);
5116 case TOK_SHARP_CONST:
5117 if ((x = mk_sharp_const(sc, readstr_upto(sc, DELIMITERS))) == sc->NIL) {
5118 Error_0(sc,"undefined sharp expression");
5123 Error_0(sc,"syntax error: illegal token");
5129 sc->args = cons(sc, sc->value, sc->args);
5131 sc->tok = token(sc);
5132 if (sc->tok == TOK_EOF)
5133 { s_return(sc,sc->EOF_OBJ); }
5134 else if (sc->tok == TOK_RPAREN) {
5139 port_increment_current_line(sc, &sc->load_stack[sc->file_i], 1);
5140 sc->nesting_stack[sc->file_i]--;
5141 s_return(sc,reverse_in_place(sc, sc->NIL, sc->args));
5142 } else if (sc->tok == TOK_DOT) {
5143 s_save(sc,OP_RDDOT, sc->args, sc->NIL);
5144 sc->tok = token(sc);
5145 s_thread_to(sc,OP_RDSEXPR);
5147 s_save(sc,OP_RDLIST, sc->args, sc->NIL);;
5148 s_thread_to(sc,OP_RDSEXPR);
5153 if (token(sc) != TOK_RPAREN) {
5154 Error_0(sc,"syntax error: illegal dot expression");
5156 sc->nesting_stack[sc->file_i]--;
5157 s_return(sc,reverse_in_place(sc, sc->value, sc->args));
5162 s_return_enable_gc(sc, cons(sc, sc->QUOTE,
5163 cons(sc, sc->value, sc->NIL)));
5167 s_return_enable_gc(sc, cons(sc, sc->QQUOTE,
5168 cons(sc, sc->value, sc->NIL)));
5170 CASE(OP_RDQQUOTEVEC):
5171 gc_disable(sc, 5 + 2 * gc_reservations (mk_symbol));
5172 s_return_enable_gc(sc,cons(sc, mk_symbol(sc,"apply"),
5173 cons(sc, mk_symbol(sc,"vector"),
5174 cons(sc,cons(sc, sc->QQUOTE,
5175 cons(sc,sc->value,sc->NIL)),
5180 s_return_enable_gc(sc, cons(sc, sc->UNQUOTE,
5181 cons(sc, sc->value, sc->NIL)));
5185 s_return_enable_gc(sc, cons(sc, sc->UNQUOTESP,
5186 cons(sc, sc->value, sc->NIL)));
5189 /*sc->code=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
5190 s_thread_to(sc,OP_EVAL); Cannot be quoted*/
5191 /*x=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
5192 s_return(sc,x); Cannot be part of pairs*/
5193 /*sc->code=mk_proc(sc,OP_VECTOR);
5195 s_thread_to(sc,OP_APPLY);*/
5197 s_thread_to(sc,OP_VECTOR);
5199 /* ========== printing part ========== */
5201 if(is_vector(sc->args)) {
5203 sc->args=cons(sc,sc->args,mk_integer(sc,0));
5204 s_thread_to(sc,OP_PVECFROM);
5205 } else if(is_environment(sc->args)) {
5206 putstr(sc,"#<ENVIRONMENT>");
5208 } else if (!is_pair(sc->args)) {
5209 printatom(sc, sc->args, sc->print_flag);
5211 } else if (car(sc->args) == sc->QUOTE && ok_abbrev(cdr(sc->args))) {
5213 sc->args = cadr(sc->args);
5214 s_thread_to(sc,OP_P0LIST);
5215 } else if (car(sc->args) == sc->QQUOTE && ok_abbrev(cdr(sc->args))) {
5217 sc->args = cadr(sc->args);
5218 s_thread_to(sc,OP_P0LIST);
5219 } else if (car(sc->args) == sc->UNQUOTE && ok_abbrev(cdr(sc->args))) {
5221 sc->args = cadr(sc->args);
5222 s_thread_to(sc,OP_P0LIST);
5223 } else if (car(sc->args) == sc->UNQUOTESP && ok_abbrev(cdr(sc->args))) {
5225 sc->args = cadr(sc->args);
5226 s_thread_to(sc,OP_P0LIST);
5229 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
5230 sc->args = car(sc->args);
5231 s_thread_to(sc,OP_P0LIST);
5235 if (is_pair(sc->args)) {
5236 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
5238 sc->args = car(sc->args);
5239 s_thread_to(sc,OP_P0LIST);
5240 } else if(is_vector(sc->args)) {
5241 s_save(sc,OP_P1LIST,sc->NIL,sc->NIL);
5243 s_thread_to(sc,OP_P0LIST);
5245 if (sc->args != sc->NIL) {
5247 printatom(sc, sc->args, sc->print_flag);
5252 CASE(OP_PVECFROM): {
5253 int i=ivalue_unchecked(cdr(sc->args));
5254 pointer vec=car(sc->args);
5255 int len = vector_length(vec);
5260 pointer elem=vector_elem(vec,i);
5261 cdr(sc->args) = mk_integer(sc, i + 1);
5262 s_save(sc,OP_PVECFROM, sc->args, sc->NIL);
5266 s_thread_to(sc,OP_P0LIST);
5270 CASE(OP_LIST_LENGTH): { /* length */ /* a.k */
5271 long l = list_length(sc, car(sc->args));
5273 Error_1(sc, "length: not a list", car(sc->args));
5276 s_return_enable_gc(sc, mk_integer(sc, l));
5278 CASE(OP_ASSQ): /* assq */ /* a.k */
5280 for (y = cadr(sc->args); is_pair(y); y = cdr(y)) {
5281 if (!is_pair(car(y))) {
5282 Error_0(sc,"unable to handle non pair element");
5288 s_return(sc,car(y));
5294 CASE(OP_GET_CLOSURE): /* get-closure-code */ /* a.k */
5295 sc->args = car(sc->args);
5296 if (sc->args == sc->NIL) {
5298 } else if (is_closure(sc->args)) {
5300 s_return_enable_gc(sc, cons(sc, sc->LAMBDA,
5301 closure_code(sc->value)));
5302 } else if (is_macro(sc->args)) {
5304 s_return_enable_gc(sc, cons(sc, sc->LAMBDA,
5305 closure_code(sc->value)));
5309 CASE(OP_CLOSUREP): /* closure? */
5311 * Note, macro object is also a closure.
5312 * Therefore, (closure? <#MACRO>) ==> #t
5314 s_retbool(is_closure(car(sc->args)));
5315 CASE(OP_MACROP): /* macro? */
5316 s_retbool(is_macro(car(sc->args)));
5317 CASE(OP_VM_HISTORY): /* *vm-history* */
5318 s_return(sc, history_flatten(sc));
5320 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", op);
5321 Error_0(sc,sc->strbuff);
5326 typedef int (*test_predicate)(pointer);
5328 static int is_any(pointer p) {
5333 static int is_nonneg(pointer p) {
5334 return ivalue(p)>=0 && is_integer(p);
5337 /* Correspond carefully with following defines! */
5338 static const struct {
5344 {is_string, "string"},
5345 {is_symbol, "symbol"},
5347 {is_inport,"input port"},
5348 {is_outport,"output port"},
5349 {is_environment, "environment"},
5352 {is_character, "character"},
5353 {is_vector, "vector"},
5354 {is_number, "number"},
5355 {is_integer, "integer"},
5356 {is_nonneg, "non-negative integer"}
5360 #define TST_ANY "\001"
5361 #define TST_STRING "\002"
5362 #define TST_SYMBOL "\003"
5363 #define TST_PORT "\004"
5364 #define TST_INPORT "\005"
5365 #define TST_OUTPORT "\006"
5366 #define TST_ENVIRONMENT "\007"
5367 #define TST_PAIR "\010"
5368 #define TST_LIST "\011"
5369 #define TST_CHAR "\012"
5370 #define TST_VECTOR "\013"
5371 #define TST_NUMBER "\014"
5372 #define TST_INTEGER "\015"
5373 #define TST_NATURAL "\016"
5375 #define INF_ARG 0xff
5377 static const struct op_code_info dispatch_table[]= {
5378 #define _OP_DEF(A,B,C,D,OP) {{A},B,C,{D}},
5379 #include "opdefines.h"
5384 static const char *procname(pointer x) {
5386 const char *name=dispatch_table[n].name;
5394 check_arguments (scheme *sc, const struct op_code_info *pcd, char *msg, size_t msg_size)
5397 int n = list_length(sc, sc->args);
5399 /* Check number of arguments */
5400 if (n < pcd->min_arity) {
5402 snprintf(msg, msg_size, "%s: needs%s %d argument(s)",
5404 pcd->min_arity == pcd->max_arity ? "" : " at least",
5407 if (ok && n>pcd->max_arity) {
5409 snprintf(msg, msg_size, "%s: needs%s %d argument(s)",
5411 pcd->min_arity == pcd->max_arity ? "" : " at most",
5415 if (pcd->arg_tests_encoding[0] != 0) {
5418 const char *t = pcd->arg_tests_encoding;
5419 pointer arglist = sc->args;
5422 pointer arg = car(arglist);
5424 if (j == TST_LIST[0]) {
5425 if (arg != sc->NIL && !is_pair(arg)) break;
5427 if (!tests[j].fct(arg)) break;
5430 if (t[1] != 0 && i < sizeof pcd->arg_tests_encoding) {
5431 /* last test is replicated as necessary */
5434 arglist = cdr(arglist);
5440 snprintf(msg, msg_size, "%s: argument %d must be: %s, got: %s",
5444 type_to_string(type(car(arglist))));
5452 /* ========== Initialization of internal keywords ========== */
5454 /* Symbols representing syntax are tagged with (OP . '()). */
5455 static void assign_syntax(scheme *sc, enum scheme_opcodes op, char *name) {
5459 x = oblist_find_by_name(sc, name, &slot);
5460 assert (x == sc->NIL);
5462 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
5463 typeflag(x) = T_SYMBOL | T_SYNTAX;
5464 setimmutable(car(x));
5465 y = mk_tagged_value(sc, x, mk_integer(sc, op), sc->NIL);
5467 setimmutable(get_tag(sc, y));
5468 *slot = immutable_cons(sc, y, *slot);
5471 /* Returns the opcode for the syntax represented by P. */
5472 static int syntaxnum(scheme *sc, pointer p) {
5473 int op = ivalue_unchecked(car(get_tag(sc, p)));
5474 assert (op < OP_MAXDEFINED);
5478 static void assign_proc(scheme *sc, enum scheme_opcodes op, const char *name) {
5481 x = mk_symbol(sc, name);
5483 new_slot_in_env(sc, x, y);
5486 static pointer mk_proc(scheme *sc, enum scheme_opcodes op) {
5489 y = get_cell(sc, sc->NIL, sc->NIL);
5490 typeflag(y) = (T_PROC | T_ATOM);
5491 ivalue_unchecked(y) = (long) op;
5496 /* initialization of TinyScheme */
5498 INTERFACE static pointer s_cons(scheme *sc, pointer a, pointer b) {
5499 return cons(sc,a,b);
5501 INTERFACE static pointer s_immutable_cons(scheme *sc, pointer a, pointer b) {
5502 return immutable_cons(sc,a,b);
5505 static const struct scheme_interface vtbl = {
5520 get_foreign_object_vtable,
5521 get_foreign_object_data,
5573 scheme *scheme_init_new() {
5574 scheme *sc=(scheme*)malloc(sizeof(scheme));
5575 if(!scheme_init(sc)) {
5583 scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free) {
5584 scheme *sc=(scheme*)malloc(sizeof(scheme));
5585 if(!scheme_init_custom_alloc(sc,malloc,free)) {
5594 int scheme_init(scheme *sc) {
5595 return scheme_init_custom_alloc(sc,malloc,free);
5598 int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
5599 int i, n=sizeof(dispatch_table)/sizeof(dispatch_table[0]);
5608 sc->sink = &sc->_sink;
5609 sc->NIL = &sc->_NIL;
5610 sc->T = &sc->_HASHT;
5611 sc->F = &sc->_HASHF;
5612 sc->EOF_OBJ=&sc->_EOF_OBJ;
5614 sc->free_cell = &sc->_NIL;
5616 sc->inhibit_gc = GC_ENABLED;
5617 sc->reserved_cells = 0;
5618 sc->reserved_lineno = 0;
5621 sc->outport=sc->NIL;
5622 sc->save_inport=sc->NIL;
5623 sc->loadport=sc->NIL;
5625 memset (sc->nesting_stack, 0, sizeof sc->nesting_stack);
5626 sc->interactive_repl=0;
5627 sc->strbuff = sc->malloc(STRBUFFSIZE);
5628 if (sc->strbuff == 0) {
5632 sc->strbuff_size = STRBUFFSIZE;
5634 sc->cell_segments = NULL;
5635 if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
5640 dump_stack_initialize(sc);
5646 typeflag(sc->NIL) = (T_NIL | T_ATOM | MARK);
5647 car(sc->NIL) = cdr(sc->NIL) = sc->NIL;
5649 typeflag(sc->T) = (T_BOOLEAN | T_ATOM | MARK);
5650 car(sc->T) = cdr(sc->T) = sc->T;
5652 typeflag(sc->F) = (T_BOOLEAN | T_ATOM | MARK);
5653 car(sc->F) = cdr(sc->F) = sc->F;
5655 typeflag(sc->EOF_OBJ) = (T_EOF_OBJ | T_ATOM | MARK);
5656 car(sc->EOF_OBJ) = cdr(sc->EOF_OBJ) = sc->EOF_OBJ;
5658 typeflag(sc->sink) = (T_SINK | T_PAIR | MARK);
5659 car(sc->sink) = cdr(sc->sink) = sc->NIL;
5661 sc->c_nest = sc->NIL;
5663 sc->oblist = oblist_initial_value(sc);
5664 /* init global_env */
5665 new_frame_in_env(sc, sc->NIL);
5666 sc->global_env = sc->envir;
5668 x = mk_symbol(sc,"else");
5669 new_slot_in_env(sc, x, sc->T);
5671 assign_syntax(sc, OP_LAMBDA, "lambda");
5672 assign_syntax(sc, OP_QUOTE, "quote");
5673 assign_syntax(sc, OP_DEF0, "define");
5674 assign_syntax(sc, OP_IF0, "if");
5675 assign_syntax(sc, OP_BEGIN, "begin");
5676 assign_syntax(sc, OP_SET0, "set!");
5677 assign_syntax(sc, OP_LET0, "let");
5678 assign_syntax(sc, OP_LET0AST, "let*");
5679 assign_syntax(sc, OP_LET0REC, "letrec");
5680 assign_syntax(sc, OP_COND0, "cond");
5681 assign_syntax(sc, OP_DELAY, "delay");
5682 assign_syntax(sc, OP_AND0, "and");
5683 assign_syntax(sc, OP_OR0, "or");
5684 assign_syntax(sc, OP_C0STREAM, "cons-stream");
5685 assign_syntax(sc, OP_MACRO0, "macro");
5686 assign_syntax(sc, OP_CASE0, "case");
5688 for(i=0; i<n; i++) {
5689 if (dispatch_table[i].name[0] != 0) {
5690 assign_proc(sc, (enum scheme_opcodes)i, dispatch_table[i].name);
5694 history_init(sc, 8, 8);
5696 /* initialization of global pointers to special symbols */
5697 sc->LAMBDA = mk_symbol(sc, "lambda");
5698 sc->QUOTE = mk_symbol(sc, "quote");
5699 sc->QQUOTE = mk_symbol(sc, "quasiquote");
5700 sc->UNQUOTE = mk_symbol(sc, "unquote");
5701 sc->UNQUOTESP = mk_symbol(sc, "unquote-splicing");
5702 sc->FEED_TO = mk_symbol(sc, "=>");
5703 sc->COLON_HOOK = mk_symbol(sc,"*colon-hook*");
5704 sc->ERROR_HOOK = mk_symbol(sc, "*error-hook*");
5705 sc->SHARP_HOOK = mk_symbol(sc, "*sharp-hook*");
5706 #if USE_COMPILE_HOOK
5707 sc->COMPILE_HOOK = mk_symbol(sc, "*compile-hook*");
5710 return !sc->no_memory;
5713 void scheme_set_input_port_file(scheme *sc, FILE *fin) {
5714 sc->inport=port_from_file(sc,fin,port_input);
5717 void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end) {
5718 sc->inport=port_from_string(sc,start,past_the_end,port_input);
5721 void scheme_set_output_port_file(scheme *sc, FILE *fout) {
5722 sc->outport=port_from_file(sc,fout,port_output);
5725 void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end) {
5726 sc->outport=port_from_string(sc,start,past_the_end,port_output);
5729 void scheme_set_external_data(scheme *sc, void *p) {
5733 void scheme_deinit(scheme *sc) {
5734 struct cell_segment *s;
5738 sc->global_env=sc->NIL;
5739 dump_stack_free(sc);
5745 if(is_port(sc->inport)) {
5746 typeflag(sc->inport) = T_ATOM;
5749 sc->outport=sc->NIL;
5750 if(is_port(sc->save_inport)) {
5751 typeflag(sc->save_inport) = T_ATOM;
5753 sc->save_inport=sc->NIL;
5754 if(is_port(sc->loadport)) {
5755 typeflag(sc->loadport) = T_ATOM;
5757 sc->loadport=sc->NIL;
5759 for(i=0; i<=sc->file_i; i++) {
5760 port_clear_location(sc, &sc->load_stack[i]);
5764 gc(sc,sc->NIL,sc->NIL);
5766 for (s = sc->cell_segments; s; s = _dealloc_cellseg(sc, s)) {
5769 sc->free(sc->strbuff);
5772 void scheme_load_file(scheme *sc, FILE *fin)
5773 { scheme_load_named_file(sc,fin,0); }
5775 void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename) {
5776 dump_stack_reset(sc);
5777 sc->envir = sc->global_env;
5779 sc->load_stack[0].kind=port_input|port_file;
5780 sc->load_stack[0].rep.stdio.file=fin;
5781 sc->loadport=mk_port(sc,sc->load_stack);
5784 sc->interactive_repl=1;
5787 port_init_location(sc, &sc->load_stack[0],
5788 (fin != stdin && filename)
5789 ? mk_string(sc, filename)
5792 sc->inport=sc->loadport;
5793 sc->args = mk_integer(sc,sc->file_i);
5794 Eval_Cycle(sc, OP_T0LVL);
5795 typeflag(sc->loadport)=T_ATOM;
5796 if(sc->retcode==0) {
5797 sc->retcode=sc->nesting!=0;
5800 port_clear_location(sc, &sc->load_stack[0]);
5803 void scheme_load_string(scheme *sc, const char *cmd) {
5804 scheme_load_memory(sc, cmd, strlen(cmd), NULL);
5807 void scheme_load_memory(scheme *sc, const char *buf, size_t len, const char *filename) {
5808 dump_stack_reset(sc);
5809 sc->envir = sc->global_env;
5811 sc->load_stack[0].kind=port_input|port_string;
5812 sc->load_stack[0].rep.string.start = (char *) buf; /* This func respects const */
5813 sc->load_stack[0].rep.string.past_the_end = (char *) buf + len;
5814 sc->load_stack[0].rep.string.curr = (char *) buf;
5815 port_init_location(sc, &sc->load_stack[0], filename ? mk_string(sc, filename) : NULL);
5816 sc->loadport=mk_port(sc,sc->load_stack);
5818 sc->interactive_repl=0;
5819 sc->inport=sc->loadport;
5820 sc->args = mk_integer(sc,sc->file_i);
5821 Eval_Cycle(sc, OP_T0LVL);
5822 typeflag(sc->loadport)=T_ATOM;
5823 if(sc->retcode==0) {
5824 sc->retcode=sc->nesting!=0;
5827 port_clear_location(sc, &sc->load_stack[0]);
5830 void scheme_define(scheme *sc, pointer envir, pointer symbol, pointer value) {
5833 x = find_slot_spec_in_env(sc, envir, symbol, 0, &sslot);
5835 set_slot_in_env(sc, x, value);
5837 new_slot_spec_in_env(sc, symbol, value, sslot);
5842 void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr)
5846 mk_symbol(sc,sr->name),
5847 mk_foreign_func(sc, sr->f));
5850 void scheme_register_foreign_func_list(scheme * sc,
5851 scheme_registerable * list,
5855 for(i = 0; i < count; i++)
5857 scheme_register_foreign_func(sc, list + i);
5861 pointer scheme_apply0(scheme *sc, const char *procname)
5862 { return scheme_eval(sc, cons(sc,mk_symbol(sc,procname),sc->NIL)); }
5864 void save_from_C_call(scheme *sc)
5866 pointer saved_data =
5873 sc->c_nest = cons(sc, saved_data, sc->c_nest);
5874 /* Truncate the dump stack so TS will return here when done, not
5875 directly resume pre-C-call operations. */
5876 dump_stack_reset(sc);
5878 void restore_from_C_call(scheme *sc)
5880 car(sc->sink) = caar(sc->c_nest);
5881 sc->envir = cadar(sc->c_nest);
5882 sc->dump = cdr(cdar(sc->c_nest));
5884 sc->c_nest = cdr(sc->c_nest);
5887 /* "func" and "args" are assumed to be already eval'ed. */
5888 pointer scheme_call(scheme *sc, pointer func, pointer args)
5890 int old_repl = sc->interactive_repl;
5891 sc->interactive_repl = 0;
5892 save_from_C_call(sc);
5893 sc->envir = sc->global_env;
5897 Eval_Cycle(sc, OP_APPLY);
5898 sc->interactive_repl = old_repl;
5899 restore_from_C_call(sc);
5903 pointer scheme_eval(scheme *sc, pointer obj)
5905 int old_repl = sc->interactive_repl;
5906 sc->interactive_repl = 0;
5907 save_from_C_call(sc);
5911 Eval_Cycle(sc, OP_EVAL);
5912 sc->interactive_repl = old_repl;
5913 restore_from_C_call(sc);
5920 /* ========== Main ========== */
5924 #if defined(__APPLE__) && !defined (OSX)
5927 extern MacTS_main(int argc, char **argv);
5929 int argc = ccommand(&argv);
5930 MacTS_main(argc,argv);
5933 int MacTS_main(int argc, char **argv) {
5935 int main(int argc, char **argv) {
5939 char *file_name=InitFile;
5946 if(argc==2 && strcmp(argv[1],"-?")==0) {
5947 printf("Usage: tinyscheme -?\n");
5948 printf("or: tinyscheme [<file1> <file2> ...]\n");
5949 printf("followed by\n");
5950 printf(" -1 <file> [<arg1> <arg2> ...]\n");
5951 printf(" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5952 printf("assuming that the executable is named tinyscheme.\n");
5953 printf("Use - as filename for stdin.\n");
5956 if(!scheme_init(&sc)) {
5957 fprintf(stderr,"Could not initialize!\n");
5960 scheme_set_input_port_file(&sc, stdin);
5961 scheme_set_output_port_file(&sc, stdout);
5963 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"load-extension"),mk_foreign_func(&sc, scm_load_ext));
5966 if(access(file_name,0)!=0) {
5967 char *p=getenv("TINYSCHEMEINIT");
5973 if(strcmp(file_name,"-")==0) {
5975 } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0) {
5976 pointer args=sc.NIL;
5977 isfile=file_name[1]=='1';
5979 if(strcmp(file_name,"-")==0) {
5982 fin=fopen(file_name,"r");
5984 for(;*argv;argv++) {
5985 pointer value=mk_string(&sc,*argv);
5986 args=cons(&sc,value,args);
5988 args=reverse_in_place(&sc,sc.NIL,args);
5989 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args);
5992 fin=fopen(file_name,"r");
5994 if(isfile && fin==0) {
5995 fprintf(stderr,"Could not open file %s\n",file_name);
5998 scheme_load_named_file(&sc,fin,file_name);
6000 scheme_load_string(&sc,file_name);
6002 if(!isfile || fin!=stdin) {
6004 fprintf(stderr,"Errors encountered reading %s\n",file_name);
6012 } while(file_name!=0);
6014 scheme_load_named_file(&sc,stdin,0);