1 /* T I N Y S C H E M E 1 . 4 1
2 * Dimitrios Souflis (dsouflis@acm.org)
3 * Based on MiniScheme (original credits follow)
4 * (MINISCM) coded by Atsushi Moriwaki (11/5/1989)
5 * (MINISCM) E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp
6 * (MINISCM) This version has been modified by R.C. Secrist.
8 * (MINISCM) Mini-Scheme is now maintained by Akira KIDA.
10 * (MINISCM) This is a revised and modified version by Akira KIDA.
11 * (MINISCM) current version is 0.85k4 (15 May 1994)
15 #define _SCHEME_SOURCE
16 #include "scheme-private.h"
21 #define snprintf _snprintf
39 # define stricmp strcasecmp
43 /* Used for documentation purposes, to signal functions in 'interface' */
58 #define TOK_SHARP_CONST 11
62 #define DELIMITERS "()\";\f\t\v\n\r "
65 * Basic memory allocation units
68 #define banner "TinyScheme 1.41"
75 static int stricmp(const char *s1, const char *s2)
89 #endif /* __APPLE__ */
92 static const char *strlwr(char *s) {
103 # define prompt "ts> "
107 # define InitFile "init.scm"
110 #ifndef FIRST_CELLSEGS
111 # define FIRST_CELLSEGS 3
134 T_LAST_SYSTEM_TYPE=19
138 type_to_string (enum scheme_types typ)
142 case T_STRING: return "string";
143 case T_NUMBER: return "number";
144 case T_SYMBOL: return "symbol";
145 case T_PROC: return "proc";
146 case T_PAIR: return "pair";
147 case T_CLOSURE: return "closure";
148 case T_CONTINUATION: return "continuation";
149 case T_FOREIGN: return "foreign";
150 case T_CHARACTER: return "character";
151 case T_PORT: return "port";
152 case T_VECTOR: return "vector";
153 case T_MACRO: return "macro";
154 case T_PROMISE: return "promise";
155 case T_ENVIRONMENT: return "environment";
156 case T_FOREIGN_OBJECT: return "foreign object";
157 case T_BOOLEAN: return "boolean";
158 case T_NIL: return "nil";
159 case T_EOF_OBJ: return "eof object";
160 case T_SINK: return "sink";
162 assert (! "not reached");
165 /* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */
168 #define T_MASKTYPE 31 /* 0000000000011111 */
169 #define T_TAGGED 1024 /* 0000010000000000 */
170 #define T_FINALIZE 2048 /* 0000100000000000 */
171 #define T_SYNTAX 4096 /* 0001000000000000 */
172 #define T_IMMUTABLE 8192 /* 0010000000000000 */
173 #define T_ATOM 16384 /* 0100000000000000 */ /* only for gc */
174 #define CLRATOM 49151 /* 1011111111111111 */ /* only for gc */
175 #define MARK 32768 /* 1000000000000000 */
176 #define UNMARK 32767 /* 0111111111111111 */
179 static num num_add(num a, num b);
180 static num num_mul(num a, num b);
181 static num num_div(num a, num b);
182 static num num_intdiv(num a, num b);
183 static num num_sub(num a, num b);
184 static num num_rem(num a, num b);
185 static num num_mod(num a, num b);
186 static int num_eq(num a, num b);
187 static int num_gt(num a, num b);
188 static int num_ge(num a, num b);
189 static int num_lt(num a, num b);
190 static int num_le(num a, num b);
193 static double round_per_R5RS(double x);
195 static int is_zero_double(double x);
196 static INLINE int num_is_integer(pointer p) {
197 return ((p)->_object._number.is_fixnum);
203 /* macros for cell operations */
204 #define typeflag(p) ((p)->_flag)
205 #define type(p) (typeflag(p)&T_MASKTYPE)
207 INTERFACE INLINE int is_string(pointer p) { return (type(p)==T_STRING); }
208 #define strvalue(p) ((p)->_object._string._svalue)
209 #define strlength(p) ((p)->_object._string._length)
211 INTERFACE static int is_list(scheme *sc, pointer p);
212 INTERFACE INLINE int is_vector(pointer p) { return (type(p)==T_VECTOR); }
213 INTERFACE static void fill_vector(pointer vec, pointer obj);
214 INTERFACE static pointer vector_elem(pointer vec, int ielem);
215 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a);
216 INTERFACE INLINE int is_number(pointer p) { return (type(p)==T_NUMBER); }
217 INTERFACE INLINE int is_integer(pointer p) {
220 if (num_is_integer(p) || (double)ivalue(p) == rvalue(p))
225 INTERFACE INLINE int is_real(pointer p) {
226 return is_number(p) && (!(p)->_object._number.is_fixnum);
229 INTERFACE INLINE int is_character(pointer p) { return (type(p)==T_CHARACTER); }
230 INTERFACE INLINE char *string_value(pointer p) { return strvalue(p); }
231 INLINE num nvalue(pointer p) { return ((p)->_object._number); }
232 INTERFACE long ivalue(pointer p) { return (num_is_integer(p)?(p)->_object._number.value.ivalue:(long)(p)->_object._number.value.rvalue); }
233 INTERFACE double rvalue(pointer p) { return (!num_is_integer(p)?(p)->_object._number.value.rvalue:(double)(p)->_object._number.value.ivalue); }
234 #define ivalue_unchecked(p) ((p)->_object._number.value.ivalue)
235 #define rvalue_unchecked(p) ((p)->_object._number.value.rvalue)
236 #define set_num_integer(p) (p)->_object._number.is_fixnum=1;
237 #define set_num_real(p) (p)->_object._number.is_fixnum=0;
238 INTERFACE long charvalue(pointer p) { return ivalue_unchecked(p); }
240 INTERFACE INLINE int is_port(pointer p) { return (type(p)==T_PORT); }
241 INTERFACE INLINE int is_inport(pointer p) { return is_port(p) && p->_object._port->kind & port_input; }
242 INTERFACE INLINE int is_outport(pointer p) { return is_port(p) && p->_object._port->kind & port_output; }
244 INTERFACE INLINE int is_pair(pointer p) { return (type(p)==T_PAIR); }
245 #define car(p) ((p)->_object._cons._car)
246 #define cdr(p) ((p)->_object._cons._cdr)
247 INTERFACE pointer pair_car(pointer p) { return car(p); }
248 INTERFACE pointer pair_cdr(pointer p) { return cdr(p); }
249 INTERFACE pointer set_car(pointer p, pointer q) { return car(p)=q; }
250 INTERFACE pointer set_cdr(pointer p, pointer q) { return cdr(p)=q; }
252 INTERFACE INLINE int is_symbol(pointer p) { return (type(p)==T_SYMBOL); }
253 INTERFACE INLINE char *symname(pointer p) { return strvalue(car(p)); }
255 SCHEME_EXPORT INLINE int hasprop(pointer p) { return (is_symbol(p)); }
256 #define symprop(p) cdr(p)
259 INTERFACE INLINE int is_syntax(pointer p) { return (typeflag(p)&T_SYNTAX); }
260 INTERFACE INLINE int is_proc(pointer p) { return (type(p)==T_PROC); }
261 INTERFACE INLINE int is_foreign(pointer p) { return (type(p)==T_FOREIGN); }
262 INTERFACE INLINE char *syntaxname(pointer p) { return strvalue(car(p)); }
263 #define procnum(p) ivalue(p)
264 static const char *procname(pointer x);
266 INTERFACE INLINE int is_closure(pointer p) { return (type(p)==T_CLOSURE); }
267 INTERFACE INLINE int is_macro(pointer p) { return (type(p)==T_MACRO); }
268 INTERFACE INLINE pointer closure_code(pointer p) { return car(p); }
269 INTERFACE INLINE pointer closure_env(pointer p) { return cdr(p); }
271 INTERFACE INLINE int is_continuation(pointer p) { return (type(p)==T_CONTINUATION); }
272 #define cont_dump(p) cdr(p)
274 INTERFACE INLINE int is_foreign_object(pointer p) { return (type(p)==T_FOREIGN_OBJECT); }
275 INTERFACE const foreign_object_vtable *get_foreign_object_vtable(pointer p) {
276 return p->_object._foreign_object._vtable;
278 INTERFACE void *get_foreign_object_data(pointer p) {
279 return p->_object._foreign_object._data;
282 /* To do: promise should be forced ONCE only */
283 INTERFACE INLINE int is_promise(pointer p) { return (type(p)==T_PROMISE); }
285 INTERFACE INLINE int is_environment(pointer p) { return (type(p)==T_ENVIRONMENT); }
286 #define setenvironment(p) typeflag(p) = T_ENVIRONMENT
288 #define is_atom(p) (typeflag(p)&T_ATOM)
289 #define setatom(p) typeflag(p) |= T_ATOM
290 #define clratom(p) typeflag(p) &= CLRATOM
292 #define is_mark(p) (typeflag(p)&MARK)
293 #define setmark(p) typeflag(p) |= MARK
294 #define clrmark(p) typeflag(p) &= UNMARK
296 INTERFACE INLINE int is_immutable(pointer p) { return (typeflag(p)&T_IMMUTABLE); }
297 /*#define setimmutable(p) typeflag(p) |= T_IMMUTABLE*/
298 INTERFACE INLINE void setimmutable(pointer p) { typeflag(p) |= T_IMMUTABLE; }
300 #define caar(p) car(car(p))
301 #define cadr(p) car(cdr(p))
302 #define cdar(p) cdr(car(p))
303 #define cddr(p) cdr(cdr(p))
304 #define cadar(p) car(cdr(car(p)))
305 #define caddr(p) car(cdr(cdr(p)))
306 #define cdaar(p) cdr(car(car(p)))
307 #define cadaar(p) car(cdr(car(car(p))))
308 #define cadddr(p) car(cdr(cdr(cdr(p))))
309 #define cddddr(p) cdr(cdr(cdr(cdr(p))))
312 static pointer history_flatten(scheme *sc);
313 static void history_mark(scheme *sc);
315 # define history_mark(SC) (void) 0
316 # define history_flatten(SC) (SC)->NIL
319 #if USE_CHAR_CLASSIFIERS
320 static INLINE int Cisalpha(int c) { return isascii(c) && isalpha(c); }
321 static INLINE int Cisdigit(int c) { return isascii(c) && isdigit(c); }
322 static INLINE int Cisspace(int c) { return isascii(c) && isspace(c); }
323 static INLINE int Cisupper(int c) { return isascii(c) && isupper(c); }
324 static INLINE int Cislower(int c) { return isascii(c) && islower(c); }
328 static const char *charnames[32]={
363 static int is_ascii_name(const char *name, int *pc) {
365 for(i=0; i<32; i++) {
366 if(stricmp(name,charnames[i])==0) {
371 if(stricmp(name,"del")==0) {
380 static int file_push(scheme *sc, pointer fname);
381 static void file_pop(scheme *sc);
382 static int file_interactive(scheme *sc);
383 static INLINE int is_one_of(char *s, int c);
384 static int alloc_cellseg(scheme *sc, int n);
385 static long binary_decode(const char *s);
386 static INLINE pointer get_cell(scheme *sc, pointer a, pointer b);
387 static pointer _get_cell(scheme *sc, pointer a, pointer b);
388 static pointer reserve_cells(scheme *sc, int n);
389 static pointer get_consecutive_cells(scheme *sc, int n);
390 static pointer find_consecutive_cells(scheme *sc, int n);
391 static void finalize_cell(scheme *sc, pointer a);
392 static int count_consecutive_cells(pointer x, int needed);
393 static pointer find_slot_in_env(scheme *sc, pointer env, pointer sym, int all);
394 static pointer mk_number(scheme *sc, num n);
395 static char *store_string(scheme *sc, int len, const char *str, char fill);
396 static pointer mk_vector(scheme *sc, int len);
397 static pointer mk_atom(scheme *sc, char *q);
398 static pointer mk_sharp_const(scheme *sc, char *name);
399 static pointer mk_port(scheme *sc, port *p);
400 static pointer port_from_filename(scheme *sc, const char *fn, int prop);
401 static pointer port_from_file(scheme *sc, FILE *, int prop);
402 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop);
403 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop);
404 static port *port_rep_from_file(scheme *sc, FILE *, int prop);
405 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop);
406 static void port_close(scheme *sc, pointer p, int flag);
407 static void mark(pointer a);
408 static void gc(scheme *sc, pointer a, pointer b);
409 static int basic_inchar(port *pt);
410 static int inchar(scheme *sc);
411 static void backchar(scheme *sc, int c);
412 static char *readstr_upto(scheme *sc, char *delim);
413 static pointer readstrexp(scheme *sc);
414 static INLINE int skipspace(scheme *sc);
415 static int token(scheme *sc);
416 static void printslashstring(scheme *sc, char *s, int len);
417 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen);
418 static void printatom(scheme *sc, pointer l, int f);
419 static pointer mk_proc(scheme *sc, enum scheme_opcodes op);
420 static pointer mk_closure(scheme *sc, pointer c, pointer e);
421 static pointer mk_continuation(scheme *sc, pointer d);
422 static pointer reverse(scheme *sc, pointer term, pointer list);
423 static pointer reverse_in_place(scheme *sc, pointer term, pointer list);
424 static pointer revappend(scheme *sc, pointer a, pointer b);
425 static void dump_stack_mark(scheme *);
426 static pointer opexe_0(scheme *sc, enum scheme_opcodes op);
427 static pointer opexe_1(scheme *sc, enum scheme_opcodes op);
428 static pointer opexe_2(scheme *sc, enum scheme_opcodes op);
429 static pointer opexe_3(scheme *sc, enum scheme_opcodes op);
430 static pointer opexe_4(scheme *sc, enum scheme_opcodes op);
431 static pointer opexe_5(scheme *sc, enum scheme_opcodes op);
432 static pointer opexe_6(scheme *sc, enum scheme_opcodes op);
433 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op);
434 static void assign_syntax(scheme *sc, char *name);
435 static int syntaxnum(pointer p);
436 static void assign_proc(scheme *sc, enum scheme_opcodes, char *name);
438 #define num_ivalue(n) (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue)
439 #define num_rvalue(n) (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue)
441 static num num_add(num a, num b) {
443 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
445 ret.value.ivalue= a.value.ivalue+b.value.ivalue;
447 ret.value.rvalue=num_rvalue(a)+num_rvalue(b);
452 static num num_mul(num a, num b) {
454 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
456 ret.value.ivalue= a.value.ivalue*b.value.ivalue;
458 ret.value.rvalue=num_rvalue(a)*num_rvalue(b);
463 static num num_div(num a, num b) {
465 ret.is_fixnum=a.is_fixnum && b.is_fixnum && a.value.ivalue%b.value.ivalue==0;
467 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
469 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
474 static num num_intdiv(num a, num b) {
476 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
478 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
480 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
485 static num num_sub(num a, num b) {
487 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
489 ret.value.ivalue= a.value.ivalue-b.value.ivalue;
491 ret.value.rvalue=num_rvalue(a)-num_rvalue(b);
496 static num num_rem(num a, num b) {
499 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
503 /* remainder should have same sign as second operand */
508 } else if (res < 0) {
513 ret.value.ivalue=res;
517 static num num_mod(num a, num b) {
520 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
524 /* modulo should have same sign as second operand */
528 ret.value.ivalue=res;
532 static int num_eq(num a, num b) {
534 int is_fixnum=a.is_fixnum && b.is_fixnum;
536 ret= a.value.ivalue==b.value.ivalue;
538 ret=num_rvalue(a)==num_rvalue(b);
544 static int num_gt(num a, num b) {
546 int is_fixnum=a.is_fixnum && b.is_fixnum;
548 ret= a.value.ivalue>b.value.ivalue;
550 ret=num_rvalue(a)>num_rvalue(b);
555 static int num_ge(num a, num b) {
559 static int num_lt(num a, num b) {
561 int is_fixnum=a.is_fixnum && b.is_fixnum;
563 ret= a.value.ivalue<b.value.ivalue;
565 ret=num_rvalue(a)<num_rvalue(b);
570 static int num_le(num a, num b) {
575 /* Round to nearest. Round to even if midway */
576 static double round_per_R5RS(double x) {
586 if(fmod(fl,2.0)==0.0) { /* I imagine this holds */
595 static int is_zero_double(double x) {
596 return x<DBL_MIN && x>-DBL_MIN;
599 static long binary_decode(const char *s) {
602 while(*s!=0 && (*s=='1' || *s=='0')) {
613 /* Tags are like property lists, but can be attached to arbitrary
619 mk_tagged_value(scheme *sc, pointer v, pointer tag_car, pointer tag_cdr)
623 assert(! is_vector(v));
625 r = get_consecutive_cells(sc, 2);
629 memcpy(r, v, sizeof *v);
630 typeflag(r) |= T_TAGGED;
633 typeflag(t) = T_PAIR;
643 return !! (typeflag(v) & T_TAGGED);
646 static INLINE pointer
647 get_tag(scheme *sc, pointer v)
656 #define mk_tagged_value(SC, X, A, B) (X)
658 #define get_tag(SC, V) (SC)->NIL
664 /* Allocate a new cell segment but do not make it available yet. */
666 _alloc_cellseg(scheme *sc, size_t len, void **alloc, pointer *cells)
671 if (adj < sizeof(struct cell))
672 adj = sizeof(struct cell);
674 cp = sc->malloc(len * sizeof(struct cell) + adj);
680 /* adjust in TYPE_BITS-bit boundary */
681 if (((uintptr_t) cp) % adj != 0)
682 cp = (void *) (adj * ((uintptr_t) cp / adj + 1));
688 /* allocate new cell segment */
689 static int alloc_cellseg(scheme *sc, int n) {
696 for (k = 0; k < n; k++) {
697 if (sc->last_cell_seg >= CELL_NSEGMENT - 1)
699 i = ++sc->last_cell_seg;
700 if (_alloc_cellseg(sc, CELL_SEGSIZE, &sc->alloc_seg[i], &newp)) {
704 /* insert new segment in address order */
705 sc->cell_seg[i] = newp;
706 while (i > 0 && sc->cell_seg[i - 1] > sc->cell_seg[i]) {
708 sc->cell_seg[i] = sc->cell_seg[i - 1];
709 sc->cell_seg[--i] = p;
711 sc->fcells += CELL_SEGSIZE;
712 last = newp + CELL_SEGSIZE - 1;
713 for (p = newp; p <= last; p++) {
718 /* insert new cells in address order on free list */
719 if (sc->free_cell == sc->NIL || p < sc->free_cell) {
720 cdr(last) = sc->free_cell;
721 sc->free_cell = newp;
724 while (cdr(p) != sc->NIL && newp > cdr(p))
735 /* Controlling the garbage collector.
737 * Every time a cell is allocated, the interpreter may run out of free
738 * cells and do a garbage collection. This is problematic because it
739 * might garbage collect objects that have been allocated, but are not
740 * yet made available to the interpreter.
742 * Previously, we would plug such newly allocated cells into the list
743 * of newly allocated objects rooted at car(sc->sink), but that
744 * requires allocating yet another cell increasing pressure on the
745 * memory management system.
747 * A faster alternative is to preallocate the cells needed for an
748 * operation and make sure the garbage collection is not run until all
749 * allocated objects are plugged in. This can be done with gc_disable
753 /* The garbage collector is enabled if the inhibit counter is
757 /* For now we provide a way to disable this optimization for
758 * benchmarking and because it produces slightly smaller code. */
759 #ifndef USE_GC_LOCKING
760 # define USE_GC_LOCKING 1
763 /* To facilitate nested calls to gc_disable, functions that allocate
764 * more than one cell may define a macro, e.g. foo_allocates. This
765 * macro can be used to compute the amount of preallocation at the
766 * call site with the help of this macro. */
767 #define gc_reservations(fn) fn ## _allocates
771 /* Report a shortage in reserved cells, and terminate the program. */
773 gc_reservation_failure(struct scheme *sc)
777 "insufficient reservation\n")
780 "insufficient reservation in line %d\n",
781 sc->reserved_lineno);
786 /* Disable the garbage collection and reserve the given number of
787 * cells. gc_disable may be nested, but the enclosing reservation
788 * must include the reservations of all nested calls. Note: You must
789 * re-enable the gc before calling Error_X. */
791 _gc_disable(struct scheme *sc, size_t reserve, int lineno)
793 if (sc->inhibit_gc == 0) {
794 reserve_cells(sc, (reserve));
795 sc->reserved_cells = (reserve);
799 sc->reserved_lineno = lineno;
801 } else if (sc->reserved_cells < (reserve))
802 gc_reservation_failure (sc);
805 #define gc_disable(sc, reserve) \
806 _gc_disable (sc, reserve, __LINE__)
808 /* Enable the garbage collector. */
809 #define gc_enable(sc) \
811 assert(sc->inhibit_gc); \
812 sc->inhibit_gc -= 1; \
815 /* Test whether the garbage collector is enabled. */
816 #define gc_enabled(sc) \
817 (sc->inhibit_gc == GC_ENABLED)
819 /* Consume a reserved cell. */
820 #define gc_consume(sc) \
822 assert(! gc_enabled (sc)); \
823 if (sc->reserved_cells == 0) \
824 gc_reservation_failure (sc); \
825 sc->reserved_cells -= 1; \
828 #else /* USE_GC_LOCKING */
830 #define gc_disable(sc, reserve) (void) 0
831 #define gc_enable(sc) (void) 0
832 #define gc_enabled(sc) 1
833 #define gc_consume(sc) (void) 0
835 #endif /* USE_GC_LOCKING */
837 static INLINE pointer get_cell_x(scheme *sc, pointer a, pointer b) {
838 if (! gc_enabled (sc) || sc->free_cell != sc->NIL) {
839 pointer x = sc->free_cell;
840 if (! gc_enabled (sc))
842 sc->free_cell = cdr(x);
846 assert (gc_enabled (sc));
847 return _get_cell (sc, a, b);
851 /* get new cell. parameter a, b is marked by gc. */
852 static pointer _get_cell(scheme *sc, pointer a, pointer b) {
859 assert (gc_enabled (sc));
860 if (sc->free_cell == sc->NIL) {
861 const int min_to_be_recovered = sc->last_cell_seg*8;
863 if (sc->fcells < min_to_be_recovered
864 || sc->free_cell == sc->NIL) {
865 /* if only a few recovered, get more to avoid fruitless gc's */
866 if (!alloc_cellseg(sc,1) && sc->free_cell == sc->NIL) {
873 sc->free_cell = cdr(x);
878 /* make sure that there is a given number of cells free */
879 static pointer reserve_cells(scheme *sc, int n) {
884 /* Are there enough cells available? */
885 if (sc->fcells < n) {
886 /* If not, try gc'ing some */
887 gc(sc, sc->NIL, sc->NIL);
888 if (sc->fcells < n) {
889 /* If there still aren't, try getting more heap */
890 if (!alloc_cellseg(sc,1)) {
895 if (sc->fcells < n) {
896 /* If all fail, report failure */
904 static pointer get_consecutive_cells(scheme *sc, int n) {
907 if(sc->no_memory) { return sc->sink; }
909 /* Are there any cells available? */
910 x=find_consecutive_cells(sc,n);
911 if (x != sc->NIL) { return x; }
913 /* If not, try gc'ing some */
914 gc(sc, sc->NIL, sc->NIL);
915 x=find_consecutive_cells(sc,n);
916 if (x != sc->NIL) { return x; }
918 /* If there still aren't, try getting more heap */
919 if (!alloc_cellseg(sc,1))
925 x=find_consecutive_cells(sc,n);
926 if (x != sc->NIL) { return x; }
928 /* If all fail, report failure */
933 static int count_consecutive_cells(pointer x, int needed) {
938 if(n>needed) return n;
943 static pointer find_consecutive_cells(scheme *sc, int n) {
948 while(*pp!=sc->NIL) {
949 cnt=count_consecutive_cells(*pp,n);
961 /* Free a cell. This is dangerous. Only free cells that are not
964 free_cell(scheme *sc, pointer a)
966 cdr(a) = sc->free_cell;
971 /* Free a cell and retrieve its content. This is dangerous. Only
972 * free cells that are not referenced. */
974 free_cons(scheme *sc, pointer a, pointer *r_car, pointer *r_cdr)
981 /* To retain recent allocs before interpreter knows about them -
984 static void push_recent_alloc(scheme *sc, pointer recent, pointer extra)
986 pointer holder = get_cell_x(sc, recent, extra);
987 typeflag(holder) = T_PAIR | T_IMMUTABLE;
988 car(holder) = recent;
989 cdr(holder) = car(sc->sink);
990 car(sc->sink) = holder;
993 static INLINE void ok_to_freely_gc(scheme *sc)
995 pointer a = car(sc->sink), next;
996 car(sc->sink) = sc->NIL;
1005 static pointer get_cell(scheme *sc, pointer a, pointer b)
1007 pointer cell = get_cell_x(sc, a, b);
1008 /* For right now, include "a" and "b" in "cell" so that gc doesn't
1009 think they are garbage. */
1010 /* Tentatively record it as a pair so gc understands it. */
1011 typeflag(cell) = T_PAIR;
1014 if (gc_enabled (sc))
1015 push_recent_alloc(sc, cell, sc->NIL);
1019 static pointer get_vector_object(scheme *sc, int len, pointer init)
1021 pointer cells = get_consecutive_cells(sc,len/2+len%2+1);
1022 if(sc->no_memory) { return sc->sink; }
1023 /* Record it as a vector so that gc understands it. */
1024 typeflag(cells) = (T_VECTOR | T_ATOM);
1025 ivalue_unchecked(cells)=len;
1026 set_num_integer(cells);
1027 fill_vector(cells,init);
1028 if (gc_enabled (sc))
1029 push_recent_alloc(sc, cells, sc->NIL);
1034 static void check_cell_alloced(pointer p, int expect_alloced)
1036 /* Can't use putstr(sc,str) because callers have no access to
1038 if(typeflag(p) & !expect_alloced)
1040 fprintf(stderr,"Cell is already allocated!\n");
1042 if(!(typeflag(p)) & expect_alloced)
1044 fprintf(stderr,"Cell is not allocated!\n");
1048 static void check_range_alloced(pointer p, int n, int expect_alloced)
1052 { (void)check_cell_alloced(p+i,expect_alloced); }
1057 /* Medium level cell allocation */
1059 /* get new cons cell */
1060 pointer _cons(scheme *sc, pointer a, pointer b, int immutable) {
1061 pointer x = get_cell(sc,a, b);
1063 typeflag(x) = T_PAIR;
1072 /* ========== oblist implementation ========== */
1074 #ifndef USE_OBJECT_LIST
1076 static int hash_fn(const char *key, int table_size);
1078 static pointer oblist_initial_value(scheme *sc)
1080 return mk_vector(sc, 461); /* probably should be bigger */
1083 /* returns the new symbol */
1084 static pointer oblist_add_by_name(scheme *sc, const char *name)
1086 #define oblist_add_by_name_allocates 3
1090 gc_disable(sc, gc_reservations (oblist_add_by_name));
1091 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
1092 typeflag(x) = T_SYMBOL;
1093 setimmutable(car(x));
1095 location = hash_fn(name, ivalue_unchecked(sc->oblist));
1096 set_vector_elem(sc->oblist, location,
1097 immutable_cons(sc, x, vector_elem(sc->oblist, location)));
1102 static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
1108 location = hash_fn(name, ivalue_unchecked(sc->oblist));
1109 for (x = vector_elem(sc->oblist, location); x != sc->NIL; x = cdr(x)) {
1110 s = symname(car(x));
1111 /* case-insensitive, per R5RS section 2. */
1112 if(stricmp(name, s) == 0) {
1119 static pointer oblist_all_symbols(scheme *sc)
1123 pointer ob_list = sc->NIL;
1125 for (i = 0; i < ivalue_unchecked(sc->oblist); i++) {
1126 for (x = vector_elem(sc->oblist, i); x != sc->NIL; x = cdr(x)) {
1127 ob_list = cons(sc, x, ob_list);
1135 static pointer oblist_initial_value(scheme *sc)
1140 static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
1145 for (x = sc->oblist; x != sc->NIL; x = cdr(x)) {
1146 s = symname(car(x));
1147 /* case-insensitive, per R5RS section 2. */
1148 if(stricmp(name, s) == 0) {
1155 /* returns the new symbol */
1156 static pointer oblist_add_by_name(scheme *sc, const char *name)
1160 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
1161 typeflag(x) = T_SYMBOL;
1162 setimmutable(car(x));
1163 sc->oblist = immutable_cons(sc, x, sc->oblist);
1166 static pointer oblist_all_symbols(scheme *sc)
1173 static pointer mk_port(scheme *sc, port *p) {
1174 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1176 typeflag(x) = T_PORT|T_ATOM|T_FINALIZE;
1181 pointer mk_foreign_func(scheme *sc, foreign_func f) {
1182 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1184 typeflag(x) = (T_FOREIGN | T_ATOM);
1189 pointer mk_foreign_object(scheme *sc, const foreign_object_vtable *vtable, void *data) {
1190 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1192 typeflag(x) = (T_FOREIGN_OBJECT | T_ATOM | T_FINALIZE);
1193 x->_object._foreign_object._vtable=vtable;
1194 x->_object._foreign_object._data = data;
1198 INTERFACE pointer mk_character(scheme *sc, int c) {
1199 pointer x = get_cell(sc,sc->NIL, sc->NIL);
1201 typeflag(x) = (T_CHARACTER | T_ATOM);
1202 ivalue_unchecked(x)= c;
1209 #if USE_SMALL_INTEGERS
1211 /* s_save assumes that all opcodes can be expressed as a small
1213 #define MAX_SMALL_INTEGER OP_MAXDEFINED
1216 initialize_small_integers(scheme *sc)
1219 if (_alloc_cellseg(sc, MAX_SMALL_INTEGER, &sc->integer_alloc,
1220 &sc->integer_cells))
1223 for (i = 0; i < MAX_SMALL_INTEGER; i++) {
1224 pointer x = &sc->integer_cells[i];
1225 typeflag(x) = T_NUMBER | T_ATOM | MARK;
1226 ivalue_unchecked(x) = i;
1233 static INLINE pointer
1234 mk_small_integer(scheme *sc, long n)
1236 #define mk_small_integer_allocates 0
1237 assert(0 <= n && n < MAX_SMALL_INTEGER);
1238 return &sc->integer_cells[n];
1242 #define mk_small_integer_allocates 1
1243 #define mk_small_integer mk_integer
1247 /* get number atom (integer) */
1248 INTERFACE pointer mk_integer(scheme *sc, long n) {
1251 #if USE_SMALL_INTEGERS
1252 if (0 <= n && n < MAX_SMALL_INTEGER)
1253 return mk_small_integer(sc, n);
1256 x = get_cell(sc,sc->NIL, sc->NIL);
1257 typeflag(x) = (T_NUMBER | T_ATOM);
1258 ivalue_unchecked(x)= n;
1265 INTERFACE pointer mk_real(scheme *sc, double n) {
1266 pointer x = get_cell(sc,sc->NIL, sc->NIL);
1268 typeflag(x) = (T_NUMBER | T_ATOM);
1269 rvalue_unchecked(x)= n;
1274 static pointer mk_number(scheme *sc, num n) {
1276 return mk_integer(sc,n.value.ivalue);
1278 return mk_real(sc,n.value.rvalue);
1282 /* allocate name to string area */
1283 static char *store_string(scheme *sc, int len_str, const char *str, char fill) {
1286 q=(char*)sc->malloc(len_str+1);
1292 memcpy (q, str, len_str);
1295 memset(q, fill, len_str);
1301 /* get new string */
1302 INTERFACE pointer mk_string(scheme *sc, const char *str) {
1303 return mk_counted_string(sc,str,strlen(str));
1306 INTERFACE pointer mk_counted_string(scheme *sc, const char *str, int len) {
1307 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1308 typeflag(x) = (T_STRING | T_ATOM | T_FINALIZE);
1309 strvalue(x) = store_string(sc,len,str,0);
1314 INTERFACE pointer mk_empty_string(scheme *sc, int len, char fill) {
1315 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1316 typeflag(x) = (T_STRING | T_ATOM | T_FINALIZE);
1317 strvalue(x) = store_string(sc,len,0,fill);
1322 INTERFACE static pointer mk_vector(scheme *sc, int len)
1323 { return get_vector_object(sc,len,sc->NIL); }
1325 INTERFACE static void fill_vector(pointer vec, pointer obj) {
1327 int n = ivalue(vec)/2+ivalue(vec)%2;
1328 for(i=0; i < n; i++) {
1329 typeflag(vec+1+i) = T_PAIR;
1330 setimmutable(vec+1+i);
1336 INTERFACE static pointer vector_elem(pointer vec, int ielem) {
1339 return car(vec+1+n);
1341 return cdr(vec+1+n);
1345 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a) {
1348 return car(vec+1+n)=a;
1350 return cdr(vec+1+n)=a;
1354 /* get new symbol */
1355 INTERFACE pointer mk_symbol(scheme *sc, const char *name) {
1356 #define mk_symbol_allocates oblist_add_by_name_allocates
1359 /* first check oblist */
1360 x = oblist_find_by_name(sc, name);
1364 x = oblist_add_by_name(sc, name);
1369 INTERFACE pointer gensym(scheme *sc) {
1373 for(; sc->gensym_cnt<LONG_MAX; sc->gensym_cnt++) {
1374 snprintf(name,40,"gensym-%ld",sc->gensym_cnt);
1376 /* first check oblist */
1377 x = oblist_find_by_name(sc, name);
1382 x = oblist_add_by_name(sc, name);
1390 /* double the size of the string buffer */
1391 static int expand_strbuff(scheme *sc) {
1392 size_t new_size = sc->strbuff_size * 2;
1393 char *new_buffer = sc->malloc(new_size);
1394 if (new_buffer == 0) {
1398 memcpy(new_buffer, sc->strbuff, sc->strbuff_size);
1399 sc->free(sc->strbuff);
1400 sc->strbuff = new_buffer;
1401 sc->strbuff_size = new_size;
1405 /* make symbol or number atom from string */
1406 static pointer mk_atom(scheme *sc, char *q) {
1408 int has_dec_point=0;
1414 while ((next = strstr(next, "::")) != 0) {
1415 /* Keep looking for the last occurrence. */
1422 return cons(sc, sc->COLON_HOOK,
1426 cons(sc, mk_symbol(sc, strlwr(p + 2)),
1428 cons(sc, mk_atom(sc, q), sc->NIL)));
1434 if ((c == '+') || (c == '-')) {
1441 return (mk_symbol(sc, strlwr(q)));
1443 } else if (c == '.') {
1447 return (mk_symbol(sc, strlwr(q)));
1449 } else if (!isdigit(c)) {
1450 return (mk_symbol(sc, strlwr(q)));
1453 for ( ; (c = *p) != 0; ++p) {
1456 if(!has_dec_point) {
1461 else if ((c == 'e') || (c == 'E')) {
1463 has_dec_point = 1; /* decimal point illegal
1466 if ((*p == '-') || (*p == '+') || isdigit(*p)) {
1471 return (mk_symbol(sc, strlwr(q)));
1475 return mk_real(sc,atof(q));
1477 return (mk_integer(sc, atol(q)));
1481 static pointer mk_sharp_const(scheme *sc, char *name) {
1483 char tmp[STRBUFFSIZE];
1485 if (!strcmp(name, "t"))
1487 else if (!strcmp(name, "f"))
1489 else if (*name == 'o') {/* #o (octal) */
1490 snprintf(tmp, STRBUFFSIZE, "0%s", name+1);
1491 sscanf(tmp, "%lo", (long unsigned *)&x);
1492 return (mk_integer(sc, x));
1493 } else if (*name == 'd') { /* #d (decimal) */
1494 sscanf(name+1, "%ld", (long int *)&x);
1495 return (mk_integer(sc, x));
1496 } else if (*name == 'x') { /* #x (hex) */
1497 snprintf(tmp, STRBUFFSIZE, "0x%s", name+1);
1498 sscanf(tmp, "%lx", (long unsigned *)&x);
1499 return (mk_integer(sc, x));
1500 } else if (*name == 'b') { /* #b (binary) */
1501 x = binary_decode(name+1);
1502 return (mk_integer(sc, x));
1503 } else if (*name == '\\') { /* #\w (character) */
1505 if(stricmp(name+1,"space")==0) {
1507 } else if(stricmp(name+1,"newline")==0) {
1509 } else if(stricmp(name+1,"return")==0) {
1511 } else if(stricmp(name+1,"tab")==0) {
1513 } else if(name[1]=='x' && name[2]!=0) {
1515 if(sscanf(name+2,"%x",(unsigned int *)&c1)==1 && c1 < UCHAR_MAX) {
1521 } else if(is_ascii_name(name+1,&c)) {
1524 } else if(name[2]==0) {
1529 return mk_character(sc,c);
1534 /* ========== garbage collector ========== */
1537 * We use algorithm E (Knuth, The Art of Computer Programming Vol.1,
1538 * sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm,
1541 static void mark(pointer a) {
1549 int n = ivalue_unchecked(p)/2+ivalue_unchecked(p)%2;
1550 for(i=0; i < n; i++) {
1551 /* Vector cells will be treated like ordinary cells */
1556 else if (is_port(p)) {
1557 port *pt = p->_object._port;
1558 if (pt->kind & port_file) {
1559 mark(pt->rep.stdio.curr_line);
1560 mark(pt->rep.stdio.filename);
1564 /* Mark tag if p has one. */
1571 if (q && !is_mark(q)) {
1572 setatom(p); /* a note that we have moved car */
1578 E5: q = cdr(p); /* down cdr */
1579 if (q && !is_mark(q)) {
1585 E6: /* up. Undo the link switching from steps E4 and E5. */
1603 /* garbage collection. parameter a, b is marked. */
1604 static void gc(scheme *sc, pointer a, pointer b) {
1608 assert (gc_enabled (sc));
1610 if(sc->gc_verbose) {
1611 putstr(sc, "gc...");
1614 /* mark system globals */
1616 mark(sc->global_env);
1618 /* mark current registers */
1623 dump_stack_mark(sc);
1626 mark(sc->save_inport);
1629 for (i = 0; i <= sc->file_i; i++) {
1630 if (! (sc->load_stack[i].kind & port_file))
1633 mark(sc->load_stack[i].rep.stdio.filename);
1634 mark(sc->load_stack[i].rep.stdio.curr_line);
1637 /* Mark recent objects the interpreter doesn't know about yet. */
1638 mark(car(sc->sink));
1639 /* Mark any older stuff above nested C calls */
1642 /* mark variables a, b */
1646 /* garbage collect */
1649 sc->free_cell = sc->NIL;
1650 /* free-list is kept sorted by address so as to maintain consecutive
1651 ranges, if possible, for use with vectors. Here we scan the cells
1652 (which are also kept sorted by address) downwards to build the
1653 free-list in sorted order.
1655 for (i = sc->last_cell_seg; i >= 0; i--) {
1656 p = sc->cell_seg[i] + CELL_SEGSIZE;
1657 while (--p >= sc->cell_seg[i]) {
1662 if (typeflag(p) & T_FINALIZE) {
1663 finalize_cell(sc, p);
1668 cdr(p) = sc->free_cell;
1674 if (sc->gc_verbose) {
1676 snprintf(msg,80,"done: %ld cells were recovered.\n", sc->fcells);
1681 static void finalize_cell(scheme *sc, pointer a) {
1683 sc->free(strvalue(a));
1684 } else if(is_port(a)) {
1685 if(a->_object._port->kind&port_file
1686 && a->_object._port->rep.stdio.closeit) {
1687 port_close(sc,a,port_input|port_output);
1688 } else if (a->_object._port->kind & port_srfi6) {
1689 sc->free(a->_object._port->rep.string.start);
1691 sc->free(a->_object._port);
1692 } else if(is_foreign_object(a)) {
1693 a->_object._foreign_object._vtable->finalize(sc, a->_object._foreign_object._data);
1699 port_clear_location (scheme *sc, port *p)
1701 assert(p->kind & port_file);
1702 p->rep.stdio.curr_line = sc->NIL;
1703 p->rep.stdio.filename = sc->NIL;
1707 port_reset_current_line (scheme *sc, port *p)
1709 assert(p->kind & port_file);
1710 p->rep.stdio.curr_line = mk_integer(sc, 0);
1714 port_increment_current_line (scheme *sc, port *p, long delta)
1716 assert(p->kind & port_file);
1717 p->rep.stdio.curr_line =
1718 mk_integer(sc, ivalue_unchecked(p->rep.stdio.curr_line) + delta);
1722 /* ========== Routines for Reading ========== */
1724 static int file_push(scheme *sc, pointer fname) {
1727 if (sc->file_i == MAXFIL-1)
1729 fin = fopen(string_value(fname), "r");
1732 sc->load_stack[sc->file_i].kind=port_file|port_input;
1733 sc->load_stack[sc->file_i].rep.stdio.file=fin;
1734 sc->load_stack[sc->file_i].rep.stdio.closeit=1;
1735 sc->nesting_stack[sc->file_i]=0;
1736 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1739 port_reset_current_line(sc, &sc->load_stack[sc->file_i]);
1740 sc->load_stack[sc->file_i].rep.stdio.filename = fname;
1746 static void file_pop(scheme *sc) {
1747 if(sc->file_i != 0) {
1748 sc->nesting=sc->nesting_stack[sc->file_i];
1749 port_close(sc,sc->loadport,port_input);
1751 if (sc->load_stack[sc->file_i].kind & port_file)
1752 port_clear_location(sc, &sc->load_stack[sc->file_i]);
1755 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1759 static int file_interactive(scheme *sc) {
1760 return sc->file_i==0 && sc->load_stack[0].rep.stdio.file==stdin
1761 && sc->inport->_object._port->kind&port_file;
1764 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop) {
1768 if(prop==(port_input|port_output)) {
1770 } else if(prop==port_output) {
1779 pt=port_rep_from_file(sc,f,prop);
1780 pt->rep.stdio.closeit=1;
1784 pt->rep.stdio.filename = mk_string(sc, fn);
1786 pt->rep.stdio.filename = mk_string(sc, "<unknown>");
1788 port_reset_current_line(sc, pt);
1793 static pointer port_from_filename(scheme *sc, const char *fn, int prop) {
1795 pt=port_rep_from_filename(sc,fn,prop);
1799 return mk_port(sc,pt);
1802 static port *port_rep_from_file(scheme *sc, FILE *f, int prop)
1806 pt = (port *)sc->malloc(sizeof *pt);
1810 pt->kind = port_file | prop;
1811 pt->rep.stdio.file = f;
1812 pt->rep.stdio.closeit = 0;
1814 pt->rep.stdio.filename = mk_string(sc, "<unknown>");
1815 port_reset_current_line(sc, pt);
1820 static pointer port_from_file(scheme *sc, FILE *f, int prop) {
1822 pt=port_rep_from_file(sc,f,prop);
1826 return mk_port(sc,pt);
1829 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1831 pt=(port*)sc->malloc(sizeof(port));
1835 pt->kind=port_string|prop;
1836 pt->rep.string.start=start;
1837 pt->rep.string.curr=start;
1838 pt->rep.string.past_the_end=past_the_end;
1842 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1844 pt=port_rep_from_string(sc,start,past_the_end,prop);
1848 return mk_port(sc,pt);
1851 #define BLOCK_SIZE 256
1853 static port *port_rep_from_scratch(scheme *sc) {
1856 pt=(port*)sc->malloc(sizeof(port));
1860 start=sc->malloc(BLOCK_SIZE);
1864 memset(start,' ',BLOCK_SIZE-1);
1865 start[BLOCK_SIZE-1]='\0';
1866 pt->kind=port_string|port_output|port_srfi6;
1867 pt->rep.string.start=start;
1868 pt->rep.string.curr=start;
1869 pt->rep.string.past_the_end=start+BLOCK_SIZE-1;
1873 static pointer port_from_scratch(scheme *sc) {
1875 pt=port_rep_from_scratch(sc);
1879 return mk_port(sc,pt);
1882 static void port_close(scheme *sc, pointer p, int flag) {
1883 port *pt=p->_object._port;
1885 if((pt->kind & (port_input|port_output))==0) {
1886 if(pt->kind&port_file) {
1889 /* Cleanup is here so (close-*-port) functions could work too */
1890 port_clear_location(sc, pt);
1893 fclose(pt->rep.stdio.file);
1899 /* get new character from input file */
1900 static int inchar(scheme *sc) {
1904 pt = sc->inport->_object._port;
1905 if(pt->kind & port_saw_EOF)
1907 c = basic_inchar(pt);
1908 if(c == EOF && sc->inport == sc->loadport) {
1909 /* Instead, set port_saw_EOF */
1910 pt->kind |= port_saw_EOF;
1919 static int basic_inchar(port *pt) {
1920 if(pt->kind & port_file) {
1921 return fgetc(pt->rep.stdio.file);
1923 if(*pt->rep.string.curr == 0 ||
1924 pt->rep.string.curr == pt->rep.string.past_the_end) {
1927 return *pt->rep.string.curr++;
1932 /* back character to input buffer */
1933 static void backchar(scheme *sc, int c) {
1936 pt=sc->inport->_object._port;
1937 if(pt->kind&port_file) {
1938 ungetc(c,pt->rep.stdio.file);
1940 if(pt->rep.string.curr!=pt->rep.string.start) {
1941 --pt->rep.string.curr;
1946 static int realloc_port_string(scheme *sc, port *p)
1948 char *start=p->rep.string.start;
1949 size_t old_size = p->rep.string.past_the_end - start;
1950 size_t new_size=p->rep.string.past_the_end-start+1+BLOCK_SIZE;
1951 char *str=sc->malloc(new_size);
1953 memset(str,' ',new_size-1);
1954 str[new_size-1]='\0';
1955 memcpy(str, start, old_size);
1956 p->rep.string.start=str;
1957 p->rep.string.past_the_end=str+new_size-1;
1958 p->rep.string.curr-=start-str;
1966 INTERFACE void putstr(scheme *sc, const char *s) {
1967 port *pt=sc->outport->_object._port;
1968 if(pt->kind&port_file) {
1969 fputs(s,pt->rep.stdio.file);
1972 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
1973 *pt->rep.string.curr++=*s;
1974 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
1975 *pt->rep.string.curr++=*s;
1981 static void putchars(scheme *sc, const char *s, int len) {
1982 port *pt=sc->outport->_object._port;
1983 if(pt->kind&port_file) {
1984 fwrite(s,1,len,pt->rep.stdio.file);
1987 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
1988 *pt->rep.string.curr++=*s++;
1989 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
1990 *pt->rep.string.curr++=*s++;
1996 INTERFACE void putcharacter(scheme *sc, int c) {
1997 port *pt=sc->outport->_object._port;
1998 if(pt->kind&port_file) {
1999 fputc(c,pt->rep.stdio.file);
2001 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
2002 *pt->rep.string.curr++=c;
2003 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
2004 *pt->rep.string.curr++=c;
2009 /* read characters up to delimiter, but cater to character constants */
2010 static char *readstr_upto(scheme *sc, char *delim) {
2011 char *p = sc->strbuff;
2013 while ((p - sc->strbuff < sc->strbuff_size) &&
2014 !is_one_of(delim, (*p++ = inchar(sc))));
2016 if(p == sc->strbuff+2 && p[-2] == '\\') {
2025 /* read string expression "xxx...xxx" */
2026 static pointer readstrexp(scheme *sc) {
2027 char *p = sc->strbuff;
2030 enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state=st_ok;
2037 if(p-sc->strbuff > (sc->strbuff_size)-1) {
2038 ptrdiff_t offset = p - sc->strbuff;
2039 if (expand_strbuff(sc) != 0) {
2042 p = sc->strbuff + offset;
2052 return mk_counted_string(sc,sc->strbuff,p-sc->strbuff);
2101 if(c>='0' && c<='F') {
2105 c1=(c1<<4)+c-'A'+10;
2119 if (c < '0' || c > '7')
2127 if (state==st_oct2 && c1 >= 32)
2132 if (state == st_oct1)
2146 /* check c is in chars */
2147 static INLINE int is_one_of(char *s, int c) {
2148 if(c==EOF) return 1;
2155 /* skip white characters */
2156 static INLINE int skipspace(scheme *sc) {
2157 int c = 0, curr_line = 0;
2165 } while (isspace(c));
2170 port *p = &sc->load_stack[sc->file_i];
2171 if (p->kind & port_file)
2172 port_increment_current_line(sc, p, curr_line);
2185 static int token(scheme *sc) {
2188 if(c == EOF) { return (TOK_EOF); }
2189 switch (c=inchar(sc)) {
2193 return (TOK_LPAREN);
2195 return (TOK_RPAREN);
2198 if(is_one_of(" \n\t",c)) {
2208 while ((c=inchar(sc)) != '\n' && c!=EOF)
2212 if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
2213 port_increment_current_line(sc, &sc->load_stack[sc->file_i], 1);
2217 { return (TOK_EOF); }
2219 { return (token(sc));}
2221 return (TOK_DQUOTE);
2223 return (TOK_BQUOTE);
2225 if ((c=inchar(sc)) == '@') {
2226 return (TOK_ATMARK);
2235 } else if(c == '!') {
2236 while ((c=inchar(sc)) != '\n' && c!=EOF)
2240 if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
2241 port_increment_current_line(sc, &sc->load_stack[sc->file_i], 1);
2245 { return (TOK_EOF); }
2247 { return (token(sc));}
2250 if(is_one_of(" tfodxb\\",c)) {
2251 return TOK_SHARP_CONST;
2262 /* ========== Routines for Printing ========== */
2263 #define ok_abbrev(x) (is_pair(x) && cdr(x) == sc->NIL)
2265 static void printslashstring(scheme *sc, char *p, int len) {
2267 unsigned char *s=(unsigned char*)p;
2268 putcharacter(sc,'"');
2269 for ( i=0; i<len; i++) {
2270 if(*s==0xff || *s=='"' || *s<' ' || *s=='\\') {
2271 putcharacter(sc,'\\');
2274 putcharacter(sc,'"');
2277 putcharacter(sc,'n');
2280 putcharacter(sc,'t');
2283 putcharacter(sc,'r');
2286 putcharacter(sc,'\\');
2290 putcharacter(sc,'x');
2292 putcharacter(sc,d+'0');
2294 putcharacter(sc,d-10+'A');
2298 putcharacter(sc,d+'0');
2300 putcharacter(sc,d-10+'A');
2305 putcharacter(sc,*s);
2309 putcharacter(sc,'"');
2314 static void printatom(scheme *sc, pointer l, int f) {
2317 atom2str(sc,l,f,&p,&len);
2322 /* Uses internal buffer unless string pointer is already available */
2323 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen) {
2328 } else if (l == sc->T) {
2330 } else if (l == sc->F) {
2332 } else if (l == sc->EOF_OBJ) {
2334 } else if (is_port(l)) {
2336 } else if (is_number(l)) {
2338 if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */ {
2339 if(num_is_integer(l)) {
2340 snprintf(p, STRBUFFSIZE, "%ld", ivalue_unchecked(l));
2342 snprintf(p, STRBUFFSIZE, "%.10g", rvalue_unchecked(l));
2343 /* r5rs says there must be a '.' (unless 'e'?) */
2344 f = strcspn(p, ".e");
2346 p[f] = '.'; /* not found, so add '.0' at the end */
2355 snprintf(p, STRBUFFSIZE, "%lx", v);
2357 snprintf(p, STRBUFFSIZE, "-%lx", -v);
2358 } else if (f == 8) {
2360 snprintf(p, STRBUFFSIZE, "%lo", v);
2362 snprintf(p, STRBUFFSIZE, "-%lo", -v);
2363 } else if (f == 2) {
2364 unsigned long b = (v < 0) ? -v : v;
2365 p = &p[STRBUFFSIZE-1];
2367 do { *--p = (b&1) ? '1' : '0'; b >>= 1; } while (b != 0);
2368 if (v < 0) *--p = '-';
2371 } else if (is_string(l)) {
2374 *plen = strlength(l);
2376 } else { /* Hack, uses the fact that printing is needed */
2379 printslashstring(sc, strvalue(l), strlength(l));
2382 } else if (is_character(l)) {
2408 snprintf(p,STRBUFFSIZE, "#\\%s",charnames[c]);
2413 snprintf(p,STRBUFFSIZE,"#\\x%x",c);
2417 snprintf(p,STRBUFFSIZE,"#\\%c",c);
2421 } else if (is_symbol(l)) {
2423 } else if (is_proc(l)) {
2425 snprintf(p,STRBUFFSIZE,"#<%s PROCEDURE %ld>", procname(l),procnum(l));
2426 } else if (is_macro(l)) {
2428 } else if (is_closure(l)) {
2430 } else if (is_promise(l)) {
2432 } else if (is_foreign(l)) {
2434 snprintf(p,STRBUFFSIZE,"#<FOREIGN PROCEDURE %ld>", procnum(l));
2435 } else if (is_continuation(l)) {
2436 p = "#<CONTINUATION>";
2437 } else if (is_foreign_object(l)) {
2439 l->_object._foreign_object._vtable->to_string(sc, p, STRBUFFSIZE, l->_object._foreign_object._data);
2446 /* ========== Routines for Evaluation Cycle ========== */
2448 /* make closure. c is code. e is environment */
2449 static pointer mk_closure(scheme *sc, pointer c, pointer e) {
2450 pointer x = get_cell(sc, c, e);
2452 typeflag(x) = T_CLOSURE;
2458 /* make continuation. */
2459 static pointer mk_continuation(scheme *sc, pointer d) {
2460 pointer x = get_cell(sc, sc->NIL, d);
2462 typeflag(x) = T_CONTINUATION;
2467 static pointer list_star(scheme *sc, pointer d) {
2469 if(cdr(d)==sc->NIL) {
2472 p=cons(sc,car(d),cdr(d));
2474 while(cdr(cdr(p))!=sc->NIL) {
2475 d=cons(sc,car(p),cdr(p));
2476 if(cdr(cdr(p))!=sc->NIL) {
2484 /* reverse list -- produce new list */
2485 static pointer reverse(scheme *sc, pointer term, pointer list) {
2486 /* a must be checked by gc */
2487 pointer a = list, p = term;
2489 for ( ; is_pair(a); a = cdr(a)) {
2490 p = cons(sc, car(a), p);
2495 /* reverse list --- in-place */
2496 static pointer reverse_in_place(scheme *sc, pointer term, pointer list) {
2497 pointer p = list, result = term, q;
2499 while (p != sc->NIL) {
2508 /* append list -- produce new list (in reverse order) */
2509 static pointer revappend(scheme *sc, pointer a, pointer b) {
2513 while (is_pair(p)) {
2514 result = cons(sc, car(p), result);
2522 return sc->F; /* signal an error */
2525 /* equivalence of atoms */
2526 int eqv(pointer a, pointer b) {
2529 return (strvalue(a) == strvalue(b));
2532 } else if (is_number(a)) {
2534 if (num_is_integer(a) == num_is_integer(b))
2535 return num_eq(nvalue(a),nvalue(b));
2538 } else if (is_character(a)) {
2539 if (is_character(b))
2540 return charvalue(a)==charvalue(b);
2543 } else if (is_port(a)) {
2548 } else if (is_proc(a)) {
2550 return procnum(a)==procnum(b);
2558 /* true or false value macro */
2559 /* () is #t in R5RS */
2560 #define is_true(p) ((p) != sc->F)
2561 #define is_false(p) ((p) == sc->F)
2563 /* ========== Environment implementation ========== */
2565 #if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
2567 static int hash_fn(const char *key, int table_size)
2569 unsigned int hashed = 0;
2571 int bits_per_int = sizeof(unsigned int)*8;
2573 for (c = key; *c; c++) {
2574 /* letters have about 5 bits in them */
2575 hashed = (hashed<<5) | (hashed>>(bits_per_int-5));
2578 return hashed % table_size;
2582 #ifndef USE_ALIST_ENV
2585 * In this implementation, each frame of the environment may be
2586 * a hash table: a vector of alists hashed by variable name.
2587 * In practice, we use a vector only for the initial frame;
2588 * subsequent frames are too small and transient for the lookup
2589 * speed to out-weigh the cost of making a new vector.
2592 static void new_frame_in_env(scheme *sc, pointer old_env)
2596 /* The interaction-environment has about 300 variables in it. */
2597 if (old_env == sc->NIL) {
2598 new_frame = mk_vector(sc, 461);
2600 new_frame = sc->NIL;
2604 sc->envir = immutable_cons(sc, new_frame, old_env);
2606 setenvironment(sc->envir);
2609 static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
2610 pointer variable, pointer value)
2612 #define new_slot_spec_in_env_allocates 2
2614 gc_disable(sc, gc_reservations (new_slot_spec_in_env));
2615 slot = immutable_cons(sc, variable, value);
2617 if (is_vector(car(env))) {
2618 int location = hash_fn(symname(variable), ivalue_unchecked(car(env)));
2620 set_vector_elem(car(env), location,
2621 immutable_cons(sc, slot, vector_elem(car(env), location)));
2623 car(env) = immutable_cons(sc, slot, car(env));
2628 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
2633 for (x = env; x != sc->NIL; x = cdr(x)) {
2634 if (is_vector(car(x))) {
2635 location = hash_fn(symname(hdl), ivalue_unchecked(car(x)));
2636 y = vector_elem(car(x), location);
2640 for ( ; y != sc->NIL; y = cdr(y)) {
2641 if (caar(y) == hdl) {
2658 #else /* USE_ALIST_ENV */
2660 static INLINE void new_frame_in_env(scheme *sc, pointer old_env)
2662 sc->envir = immutable_cons(sc, sc->NIL, old_env);
2663 setenvironment(sc->envir);
2666 static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
2667 pointer variable, pointer value)
2669 car(env) = immutable_cons(sc, immutable_cons(sc, variable, value), car(env));
2672 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
2675 for (x = env; x != sc->NIL; x = cdr(x)) {
2676 for (y = car(x); y != sc->NIL; y = cdr(y)) {
2677 if (caar(y) == hdl) {
2694 #endif /* USE_ALIST_ENV else */
2696 static INLINE void new_slot_in_env(scheme *sc, pointer variable, pointer value)
2698 #define new_slot_in_env_allocates new_slot_spec_in_env_allocates
2699 new_slot_spec_in_env(sc, sc->envir, variable, value);
2702 static INLINE void set_slot_in_env(scheme *sc, pointer slot, pointer value)
2708 static INLINE pointer slot_value_in_env(pointer slot)
2713 /* ========== Evaluation Cycle ========== */
2716 static pointer _Error_1(scheme *sc, const char *s, pointer a) {
2717 const char *str = s;
2721 pointer hdl=sc->ERROR_HOOK;
2725 char sbuf[STRBUFFSIZE];
2728 history = history_flatten(sc);
2731 /* make sure error is not in REPL */
2732 if (sc->load_stack[sc->file_i].kind & port_file &&
2733 sc->load_stack[sc->file_i].rep.stdio.file != stdin) {
2738 if (history != sc->NIL && has_tag(car(history))
2739 && (tag = get_tag(sc, car(history)))
2740 && is_string(car(tag)) && is_integer(cdr(tag))) {
2741 fname = string_value(car(tag));
2742 ln = ivalue_unchecked(cdr(tag));
2744 fname = string_value(sc->load_stack[sc->file_i].rep.stdio.filename);
2745 ln = ivalue_unchecked(sc->load_stack[sc->file_i].rep.stdio.curr_line);
2748 /* should never happen */
2749 if(!fname) fname = "<unknown>";
2751 /* we started from 0 */
2753 snprintf(sbuf, STRBUFFSIZE, "%s:%i: %s", fname, ln, s);
2755 str = (const char*)sbuf;
2760 x=find_slot_in_env(sc,sc->envir,hdl,1);
2762 sc->code = cons(sc, cons(sc, sc->QUOTE,
2763 cons(sc, history, sc->NIL)),
2766 sc->code = cons(sc, cons(sc, sc->QUOTE, cons(sc, a, sc->NIL)),
2769 sc->code = cons(sc, sc->F, sc->code);
2771 sc->code = cons(sc, mk_string(sc, str), sc->code);
2772 setimmutable(car(sc->code));
2773 sc->code = cons(sc, slot_value_in_env(x), sc->code);
2774 sc->op = (int)OP_EVAL;
2780 sc->args = cons(sc, (a), sc->NIL);
2784 sc->args = cons(sc, mk_string(sc, str), sc->args);
2785 setimmutable(car(sc->args));
2786 sc->op = (int)OP_ERR0;
2789 #define Error_1(sc,s, a) return _Error_1(sc,s,a)
2790 #define Error_0(sc,s) return _Error_1(sc,s,0)
2792 /* Too small to turn into function */
2794 # define END } while (0)
2798 /* Flags. The interpreter has a flags field. When the interpreter
2799 * pushes a frame to the dump stack, it is encoded with the opcode.
2800 * Therefore, we do not use the least significant byte. */
2802 /* Masks used to encode and decode opcode and flags. */
2803 #define S_OP_MASK 0x000000ff
2804 #define S_FLAG_MASK 0xffffff00
2806 /* Set if the interpreter evaluates an expression in a tail context
2807 * (see R5RS, section 3.5). If a function, procedure, or continuation
2808 * is invoked while this flag is set, the call is recorded as tail
2809 * call in the history buffer. */
2810 #define S_FLAG_TAIL_CONTEXT 0x00000100
2813 #define s_set_flag(sc, f) \
2815 (sc)->flags |= S_FLAG_ ## f; \
2819 #define s_clear_flag(sc, f) \
2821 (sc)->flags &= ~ S_FLAG_ ## f; \
2824 /* Check if flag F is set. */
2825 #define s_get_flag(sc, f) \
2826 !!((sc)->flags & S_FLAG_ ## f)
2830 /* Bounce back to Eval_Cycle and execute A. */
2831 #define s_goto(sc,a) BEGIN \
2832 sc->op = (int)(a); \
2835 #if USE_THREADED_CODE
2837 /* Do not bounce back to Eval_Cycle but execute A by jumping directly
2838 * to it. Only applicable if A is part of the same dispatch
2840 #define s_thread_to(sc, a) \
2846 /* Define a label OP and emit a case statement for OP. For use in the
2847 * dispatch functions. The slightly peculiar goto that is never
2848 * executed avoids warnings about unused labels. */
2849 #define CASE(OP) if (0) goto OP; OP: case OP
2851 #else /* USE_THREADED_CODE */
2852 #define s_thread_to(sc, a) s_goto(sc, a)
2853 #define CASE(OP) case OP
2854 #endif /* USE_THREADED_CODE */
2856 /* Return to the previous frame on the dump stack, setting the current
2858 #define s_return(sc, a) return _s_return(sc, a, 0)
2860 /* Return to the previous frame on the dump stack, setting the current
2861 * value to A, and re-enable the garbage collector. */
2862 #define s_return_enable_gc(sc, a) return _s_return(sc, a, 1)
2864 static INLINE void dump_stack_reset(scheme *sc)
2869 static INLINE void dump_stack_initialize(scheme *sc)
2871 dump_stack_reset(sc);
2874 static void dump_stack_free(scheme *sc)
2879 static pointer _s_return(scheme *sc, pointer a, int enable_gc) {
2880 pointer dump = sc->dump;
2886 if (dump == sc->NIL)
2888 free_cons(sc, dump, &op, &dump);
2889 v = (unsigned long) ivalue_unchecked(op);
2890 sc->op = (int) (v & S_OP_MASK);
2891 sc->flags = v & S_FLAG_MASK;
2892 #ifdef USE_SMALL_INTEGERS
2893 if (v < MAX_SMALL_INTEGER) {
2894 /* This is a small integer, we must not free it. */
2896 /* Normal integer. Recover the cell. */
2899 free_cons(sc, dump, &sc->args, &dump);
2900 free_cons(sc, dump, &sc->envir, &dump);
2901 free_cons(sc, dump, &sc->code, &sc->dump);
2905 static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) {
2906 #define s_save_allocates 5
2908 unsigned long v = sc->flags | ((unsigned long) op);
2909 gc_disable(sc, gc_reservations (s_save));
2910 dump = cons(sc, sc->envir, cons(sc, (code), sc->dump));
2911 dump = cons(sc, (args), dump);
2912 sc->dump = cons(sc, mk_integer(sc, (long) v), dump);
2916 static INLINE void dump_stack_mark(scheme *sc)
2926 history_free(scheme *sc)
2928 sc->free(sc->history.m);
2929 sc->history.tailstacks = sc->NIL;
2930 sc->history.callstack = sc->NIL;
2934 history_init(scheme *sc, size_t N, size_t M)
2937 struct history *h = &sc->history;
2942 assert ((N & h->mask_N) == 0);
2946 assert ((M & h->mask_M) == 0);
2948 h->callstack = mk_vector(sc, N);
2949 if (h->callstack == sc->sink)
2952 h->tailstacks = mk_vector(sc, N);
2953 for (i = 0; i < N; i++) {
2954 pointer tailstack = mk_vector(sc, M);
2955 if (tailstack == sc->sink)
2957 set_vector_elem(h->tailstacks, i, tailstack);
2960 h->m = sc->malloc(N * sizeof *h->m);
2964 for (i = 0; i < N; i++)
2975 history_mark(scheme *sc)
2977 struct history *h = &sc->history;
2979 mark(h->tailstacks);
2982 #define add_mod(a, b, mask) (((a) + (b)) & (mask))
2983 #define sub_mod(a, b, mask) add_mod(a, (mask) + 1 - (b), mask)
2986 tailstack_clear(scheme *sc, pointer v)
2988 assert(is_vector(v));
2990 fill_vector(v, sc->NIL);
2994 callstack_pop(scheme *sc)
2996 struct history *h = &sc->history;
3000 if (h->callstack == sc->NIL)
3003 item = vector_elem(h->callstack, n);
3004 /* Clear our frame so that it can be gc'ed and we don't run into it
3005 * when walking the history. */
3006 set_vector_elem(h->callstack, n, sc->NIL);
3007 tailstack_clear(sc, vector_elem(h->tailstacks, n));
3009 /* Exit from the frame. */
3010 h->n = sub_mod(h->n, 1, h->mask_N);
3016 callstack_push(scheme *sc, pointer item)
3018 struct history *h = &sc->history;
3021 if (h->callstack == sc->NIL)
3024 /* Enter a new frame. */
3025 n = h->n = add_mod(n, 1, h->mask_N);
3027 /* Initialize tail stack. */
3028 tailstack_clear(sc, vector_elem(h->tailstacks, n));
3029 h->m[n] = h->mask_M;
3031 set_vector_elem(h->callstack, n, item);
3035 tailstack_push(scheme *sc, pointer item)
3037 struct history *h = &sc->history;
3041 if (h->callstack == sc->NIL)
3044 /* Enter a new tail frame. */
3045 m = h->m[n] = add_mod(m, 1, h->mask_M);
3046 set_vector_elem(vector_elem(h->tailstacks, n), m, item);
3050 tailstack_flatten(scheme *sc, pointer tailstack, size_t i, size_t n,
3053 struct history *h = &sc->history;
3059 if (acc == sc->sink)
3063 /* We reached the end, but we did not see a unused frame. Signal
3064 this using '... . */
3065 return cons(sc, mk_symbol(sc, "..."), acc);
3068 frame = vector_elem(tailstack, n);
3069 if (frame == sc->NIL) {
3070 /* A unused frame. We reached the end of the history. */
3075 acc = cons(sc, frame, acc);
3077 return tailstack_flatten(sc, tailstack, i - 1, sub_mod(n, 1, h->mask_M),
3082 callstack_flatten(scheme *sc, size_t i, size_t n, pointer acc)
3084 struct history *h = &sc->history;
3090 if (acc == sc->sink)
3094 /* We reached the end, but we did not see a unused frame. Signal
3095 this using '... . */
3096 return cons(sc, mk_symbol(sc, "..."), acc);
3099 frame = vector_elem(h->callstack, n);
3100 if (frame == sc->NIL) {
3101 /* A unused frame. We reached the end of the history. */
3105 /* First, emit the tail calls. */
3106 acc = tailstack_flatten(sc, vector_elem(h->tailstacks, n), h->M, h->m[n],
3110 acc = cons(sc, frame, acc);
3112 return callstack_flatten(sc, i - 1, sub_mod(n, 1, h->mask_N), acc);
3116 history_flatten(scheme *sc)
3118 struct history *h = &sc->history;
3121 if (h->callstack == sc->NIL)
3124 history = callstack_flatten(sc, h->N, h->n, sc->NIL);
3125 if (history == sc->sink)
3128 return reverse_in_place(sc, sc->NIL, history);
3134 #else /* USE_HISTORY */
3136 #define history_init(SC, A, B) (void) 0
3137 #define history_free(SC) (void) 0
3138 #define callstack_pop(SC) (void) 0
3139 #define callstack_push(SC, X) (void) 0
3140 #define tailstack_push(SC, X) (void) 0
3142 #endif /* USE_HISTORY */
3146 #define s_retbool(tf) s_return(sc,(tf) ? sc->T : sc->F)
3148 static pointer opexe_0(scheme *sc, enum scheme_opcodes op) {
3153 CASE(OP_LOAD): /* load */
3154 if(file_interactive(sc)) {
3155 fprintf(sc->outport->_object._port->rep.stdio.file,
3156 "Loading %s\n", strvalue(car(sc->args)));
3158 if (!file_push(sc, car(sc->args))) {
3159 Error_1(sc,"unable to open", car(sc->args));
3163 sc->args = mk_integer(sc,sc->file_i);
3164 s_thread_to(sc,OP_T0LVL);
3167 CASE(OP_T0LVL): /* top level */
3168 /* If we reached the end of file, this loop is done. */
3169 if(sc->loadport->_object._port->kind & port_saw_EOF)
3174 sc->nesting = sc->nesting_stack[0];
3180 s_return(sc,sc->value);
3185 /* If interactive, be nice to user. */
3186 if(file_interactive(sc))
3188 sc->envir = sc->global_env;
3189 dump_stack_reset(sc);
3194 /* Set up another iteration of REPL */
3196 sc->save_inport=sc->inport;
3197 sc->inport = sc->loadport;
3198 s_save(sc,OP_T0LVL, sc->NIL, sc->NIL);
3199 s_save(sc,OP_VALUEPRINT, sc->NIL, sc->NIL);
3200 s_save(sc,OP_T1LVL, sc->NIL, sc->NIL);
3201 s_thread_to(sc,OP_READ_INTERNAL);
3203 CASE(OP_T1LVL): /* top level */
3204 sc->code = sc->value;
3205 sc->inport=sc->save_inport;
3206 s_thread_to(sc,OP_EVAL);
3208 CASE(OP_READ_INTERNAL): /* internal read */
3209 sc->tok = token(sc);
3210 if(sc->tok==TOK_EOF)
3211 { s_return(sc,sc->EOF_OBJ); }
3212 s_goto(sc,OP_RDSEXPR);
3215 s_return(sc, gensym(sc));
3217 CASE(OP_VALUEPRINT): /* print evaluation result */
3218 /* OP_VALUEPRINT is always pushed, because when changing from
3219 non-interactive to interactive mode, it needs to be
3220 already on the stack */
3222 putstr(sc,"\nGives: ");
3224 if(file_interactive(sc)) {
3226 sc->args = sc->value;
3227 s_goto(sc,OP_P0LIST);
3229 s_return(sc,sc->value);
3232 CASE(OP_EVAL): /* main part of evaluation */
3235 /*s_save(sc,OP_VALUEPRINT,sc->NIL,sc->NIL);*/
3236 s_save(sc,OP_REAL_EVAL,sc->args,sc->code);
3238 putstr(sc,"\nEval: ");
3239 s_goto(sc,OP_P0LIST);
3244 if (is_symbol(sc->code)) { /* symbol */
3245 x=find_slot_in_env(sc,sc->envir,sc->code,1);
3247 s_return(sc,slot_value_in_env(x));
3249 Error_1(sc,"eval: unbound variable:", sc->code);
3251 } else if (is_pair(sc->code)) {
3252 if (is_syntax(x = car(sc->code))) { /* SYNTAX */
3253 sc->code = cdr(sc->code);
3254 s_goto(sc,syntaxnum(x));
3255 } else {/* first, eval top element and eval arguments */
3256 s_save(sc,OP_E0ARGS, sc->NIL, sc->code);
3257 /* If no macros => s_save(sc,OP_E1ARGS, sc->NIL, cdr(sc->code));*/
3258 sc->code = car(sc->code);
3259 s_clear_flag(sc, TAIL_CONTEXT);
3260 s_thread_to(sc,OP_EVAL);
3263 s_return(sc,sc->code);
3266 CASE(OP_E0ARGS): /* eval arguments */
3267 if (is_macro(sc->value)) { /* macro expansion */
3268 gc_disable(sc, 1 + gc_reservations (s_save));
3269 s_save(sc,OP_DOMACRO, sc->NIL, sc->NIL);
3270 sc->args = cons(sc,sc->code, sc->NIL);
3272 sc->code = sc->value;
3273 s_clear_flag(sc, TAIL_CONTEXT);
3274 s_thread_to(sc,OP_APPLY);
3277 sc->args = cons(sc, sc->code, sc->NIL);
3279 sc->code = cdr(sc->code);
3280 s_thread_to(sc,OP_E1ARGS);
3283 CASE(OP_E1ARGS): /* eval arguments */
3285 sc->args = cons(sc, sc->value, sc->args);
3287 if (is_pair(sc->code)) { /* continue */
3288 s_save(sc,OP_E1ARGS, sc->args, cdr(sc->code));
3289 sc->code = car(sc->code);
3291 s_clear_flag(sc, TAIL_CONTEXT);
3292 s_thread_to(sc,OP_EVAL);
3294 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3295 s_thread_to(sc,OP_APPLY_CODE);
3301 sc->tracing=ivalue(car(sc->args));
3303 s_return_enable_gc(sc, mk_integer(sc, tr));
3308 CASE(OP_CALLSTACK_POP): /* pop the call stack */
3310 s_return(sc, sc->value);
3313 CASE(OP_APPLY_CODE): /* apply 'cadr(args)' to 'cddr(args)',
3314 * record in the history as invoked from
3316 free_cons(sc, sc->args, &callsite, &sc->args);
3317 sc->code = car(sc->args);
3318 sc->args = cdr(sc->args);
3321 CASE(OP_APPLY): /* apply 'code' to 'args' */
3324 s_save(sc,OP_REAL_APPLY,sc->args,sc->code);
3326 /* sc->args=cons(sc,sc->code,sc->args);*/
3327 putstr(sc,"\nApply to: ");
3328 s_goto(sc,OP_P0LIST);
3331 CASE(OP_REAL_APPLY):
3334 if (op != OP_APPLY_CODE)
3335 callsite = sc->code;
3336 if (s_get_flag(sc, TAIL_CONTEXT)) {
3337 /* We are evaluating a tail call. */
3338 tailstack_push(sc, callsite);
3340 callstack_push(sc, callsite);
3341 s_save(sc, OP_CALLSTACK_POP, sc->NIL, sc->NIL);
3345 if (is_proc(sc->code)) {
3346 s_goto(sc,procnum(sc->code)); /* PROCEDURE */
3347 } else if (is_foreign(sc->code))
3349 /* Keep nested calls from GC'ing the arglist */
3350 push_recent_alloc(sc,sc->args,sc->NIL);
3351 x=sc->code->_object._ff(sc,sc->args);
3353 } else if (is_closure(sc->code) || is_macro(sc->code)
3354 || is_promise(sc->code)) { /* CLOSURE */
3355 /* Should not accept promise */
3356 /* make environment */
3357 new_frame_in_env(sc, closure_env(sc->code));
3358 for (x = car(closure_code(sc->code)), y = sc->args;
3359 is_pair(x); x = cdr(x), y = cdr(y)) {
3361 Error_1(sc, "not enough arguments, missing:", x);
3363 new_slot_in_env(sc, car(x), car(y));
3368 Error_0(sc, "too many arguments");
3370 } else if (is_symbol(x))
3371 new_slot_in_env(sc, x, y);
3373 Error_1(sc,"syntax error in closure: not a symbol:", x);
3375 sc->code = cdr(closure_code(sc->code));
3377 s_set_flag(sc, TAIL_CONTEXT);
3378 s_thread_to(sc,OP_BEGIN);
3379 } else if (is_continuation(sc->code)) { /* CONTINUATION */
3380 sc->dump = cont_dump(sc->code);
3381 s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL);
3383 Error_1(sc,"illegal function",sc->code);
3386 CASE(OP_DOMACRO): /* do macro */
3387 sc->code = sc->value;
3388 s_thread_to(sc,OP_EVAL);
3390 #if USE_COMPILE_HOOK
3391 CASE(OP_LAMBDA): /* lambda */
3392 /* If the hook is defined, apply it to sc->code, otherwise
3393 set sc->value fall through */
3395 pointer f=find_slot_in_env(sc,sc->envir,sc->COMPILE_HOOK,1);
3397 sc->value = sc->code;
3400 gc_disable(sc, 1 + gc_reservations (s_save));
3401 s_save(sc,OP_LAMBDA1,sc->args,sc->code);
3402 sc->args=cons(sc,sc->code,sc->NIL);
3404 sc->code=slot_value_in_env(f);
3405 s_thread_to(sc,OP_APPLY);
3410 CASE(OP_LAMBDA): /* lambda */
3411 sc->value = sc->code;
3417 s_return_enable_gc(sc, mk_closure(sc, sc->value, sc->envir));
3420 CASE(OP_MKCLOSURE): /* make-closure */
3422 if(car(x)==sc->LAMBDA) {
3425 if(cdr(sc->args)==sc->NIL) {
3431 s_return_enable_gc(sc, mk_closure(sc, x, y));
3433 CASE(OP_QUOTE): /* quote */
3434 s_return(sc,car(sc->code));
3436 CASE(OP_DEF0): /* define */
3437 if(is_immutable(car(sc->code)))
3438 Error_1(sc,"define: unable to alter immutable", car(sc->code));
3440 if (is_pair(car(sc->code))) {
3443 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
3447 sc->code = cadr(sc->code);
3449 if (!is_symbol(x)) {
3450 Error_0(sc,"variable is not a symbol");
3452 s_save(sc,OP_DEF1, sc->NIL, x);
3453 s_thread_to(sc,OP_EVAL);
3455 CASE(OP_DEF1): /* define */
3456 x=find_slot_in_env(sc,sc->envir,sc->code,0);
3458 set_slot_in_env(sc, x, sc->value);
3460 new_slot_in_env(sc, sc->code, sc->value);
3462 s_return(sc,sc->code);
3465 CASE(OP_DEFP): /* defined? */
3467 if(cdr(sc->args)!=sc->NIL) {
3470 s_retbool(find_slot_in_env(sc,x,car(sc->args),1)!=sc->NIL);
3472 CASE(OP_SET0): /* set! */
3473 if(is_immutable(car(sc->code)))
3474 Error_1(sc,"set!: unable to alter immutable variable",car(sc->code));
3475 s_save(sc,OP_SET1, sc->NIL, car(sc->code));
3476 sc->code = cadr(sc->code);
3477 s_thread_to(sc,OP_EVAL);
3479 CASE(OP_SET1): /* set! */
3480 y=find_slot_in_env(sc,sc->envir,sc->code,1);
3482 set_slot_in_env(sc, y, sc->value);
3483 s_return(sc,sc->value);
3485 Error_1(sc,"set!: unbound variable:", sc->code);
3489 CASE(OP_BEGIN): /* begin */
3493 if (!is_pair(sc->code)) {
3494 s_return(sc,sc->code);
3497 last = cdr(sc->code) == sc->NIL;
3499 s_save(sc,OP_BEGIN, sc->NIL, cdr(sc->code));
3501 sc->code = car(sc->code);
3503 /* This is not the end of the list. This is not a tail
3505 s_clear_flag(sc, TAIL_CONTEXT);
3506 s_thread_to(sc,OP_EVAL);
3509 CASE(OP_IF0): /* if */
3510 s_save(sc,OP_IF1, sc->NIL, cdr(sc->code));
3511 sc->code = car(sc->code);
3512 s_clear_flag(sc, TAIL_CONTEXT);
3513 s_thread_to(sc,OP_EVAL);
3515 CASE(OP_IF1): /* if */
3516 if (is_true(sc->value))
3517 sc->code = car(sc->code);
3519 sc->code = cadr(sc->code); /* (if #f 1) ==> () because
3520 * car(sc->NIL) = sc->NIL */
3521 s_thread_to(sc,OP_EVAL);
3523 CASE(OP_LET0): /* let */
3525 sc->value = sc->code;
3526 sc->code = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code);
3527 s_thread_to(sc,OP_LET1);
3529 CASE(OP_LET1): /* let (calculate parameters) */
3530 gc_disable(sc, 1 + (is_pair(sc->code) ? gc_reservations (s_save) : 0));
3531 sc->args = cons(sc, sc->value, sc->args);
3532 if (is_pair(sc->code)) { /* continue */
3533 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
3535 Error_1(sc, "Bad syntax of binding spec in let :",
3538 s_save(sc,OP_LET1, sc->args, cdr(sc->code));
3540 sc->code = cadar(sc->code);
3542 s_clear_flag(sc, TAIL_CONTEXT);
3543 s_thread_to(sc,OP_EVAL);
3546 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3547 sc->code = car(sc->args);
3548 sc->args = cdr(sc->args);
3549 s_thread_to(sc,OP_LET2);
3552 CASE(OP_LET2): /* let */
3553 new_frame_in_env(sc, sc->envir);
3554 for (x = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code), y = sc->args;
3555 y != sc->NIL; x = cdr(x), y = cdr(y)) {
3556 new_slot_in_env(sc, caar(x), car(y));
3558 if (is_symbol(car(sc->code))) { /* named let */
3559 for (x = cadr(sc->code), sc->args = sc->NIL; x != sc->NIL; x = cdr(x)) {
3561 Error_1(sc, "Bad syntax of binding in let :", x);
3562 if (!is_list(sc, car(x)))
3563 Error_1(sc, "Bad syntax of binding in let :", car(x));
3565 sc->args = cons(sc, caar(x), sc->args);
3568 gc_disable(sc, 2 + gc_reservations (new_slot_in_env));
3569 x = mk_closure(sc, cons(sc, reverse_in_place(sc, sc->NIL, sc->args), cddr(sc->code)), sc->envir);
3570 new_slot_in_env(sc, car(sc->code), x);
3572 sc->code = cddr(sc->code);
3575 sc->code = cdr(sc->code);
3578 s_thread_to(sc,OP_BEGIN);
3580 CASE(OP_LET0AST): /* let* */
3581 if (car(sc->code) == sc->NIL) {
3582 new_frame_in_env(sc, sc->envir);
3583 sc->code = cdr(sc->code);
3584 s_thread_to(sc,OP_BEGIN);
3586 if(!is_pair(car(sc->code)) || !is_pair(caar(sc->code)) || !is_pair(cdaar(sc->code))) {
3587 Error_1(sc,"Bad syntax of binding spec in let* :",car(sc->code));
3589 s_save(sc,OP_LET1AST, cdr(sc->code), car(sc->code));
3590 sc->code = cadaar(sc->code);
3591 s_clear_flag(sc, TAIL_CONTEXT);
3592 s_thread_to(sc,OP_EVAL);
3594 CASE(OP_LET1AST): /* let* (make new frame) */
3595 new_frame_in_env(sc, sc->envir);
3596 s_thread_to(sc,OP_LET2AST);
3598 CASE(OP_LET2AST): /* let* (calculate parameters) */
3599 new_slot_in_env(sc, caar(sc->code), sc->value);
3600 sc->code = cdr(sc->code);
3601 if (is_pair(sc->code)) { /* continue */
3602 s_save(sc,OP_LET2AST, sc->args, sc->code);
3603 sc->code = cadar(sc->code);
3605 s_clear_flag(sc, TAIL_CONTEXT);
3606 s_thread_to(sc,OP_EVAL);
3608 sc->code = sc->args;
3610 s_thread_to(sc,OP_BEGIN);
3613 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3614 Error_0(sc,sc->strbuff);
3619 static pointer opexe_1(scheme *sc, enum scheme_opcodes op) {
3623 CASE(OP_LET0REC): /* letrec */
3624 new_frame_in_env(sc, sc->envir);
3626 sc->value = sc->code;
3627 sc->code = car(sc->code);
3628 s_thread_to(sc,OP_LET1REC);
3630 CASE(OP_LET1REC): /* letrec (calculate parameters) */
3632 sc->args = cons(sc, sc->value, sc->args);
3634 if (is_pair(sc->code)) { /* continue */
3635 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
3636 Error_1(sc, "Bad syntax of binding spec in letrec :",
3639 s_save(sc,OP_LET1REC, sc->args, cdr(sc->code));
3640 sc->code = cadar(sc->code);
3642 s_clear_flag(sc, TAIL_CONTEXT);
3645 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3646 sc->code = car(sc->args);
3647 sc->args = cdr(sc->args);
3648 s_thread_to(sc,OP_LET2REC);
3651 CASE(OP_LET2REC): /* letrec */
3652 for (x = car(sc->code), y = sc->args; y != sc->NIL; x = cdr(x), y = cdr(y)) {
3653 new_slot_in_env(sc, caar(x), car(y));
3655 sc->code = cdr(sc->code);
3657 s_goto(sc,OP_BEGIN);
3659 CASE(OP_COND0): /* cond */
3660 if (!is_pair(sc->code)) {
3661 Error_0(sc,"syntax error in cond");
3663 s_save(sc,OP_COND1, sc->NIL, sc->code);
3664 sc->code = caar(sc->code);
3665 s_clear_flag(sc, TAIL_CONTEXT);
3668 CASE(OP_COND1): /* cond */
3669 if (is_true(sc->value)) {
3670 if ((sc->code = cdar(sc->code)) == sc->NIL) {
3671 s_return(sc,sc->value);
3673 if(!sc->code || car(sc->code)==sc->FEED_TO) {
3674 if(!is_pair(cdr(sc->code))) {
3675 Error_0(sc,"syntax error in cond");
3678 x=cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL));
3679 sc->code=cons(sc,cadr(sc->code),cons(sc,x,sc->NIL));
3683 s_goto(sc,OP_BEGIN);
3685 if ((sc->code = cdr(sc->code)) == sc->NIL) {
3686 s_return(sc,sc->NIL);
3688 s_save(sc,OP_COND1, sc->NIL, sc->code);
3689 sc->code = caar(sc->code);
3690 s_clear_flag(sc, TAIL_CONTEXT);
3695 CASE(OP_DELAY): /* delay */
3697 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
3698 typeflag(x)=T_PROMISE;
3699 s_return_enable_gc(sc,x);
3701 CASE(OP_AND0): /* and */
3702 if (sc->code == sc->NIL) {
3705 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
3706 if (cdr(sc->code) != sc->NIL)
3707 s_clear_flag(sc, TAIL_CONTEXT);
3708 sc->code = car(sc->code);
3711 CASE(OP_AND1): /* and */
3712 if (is_false(sc->value)) {
3713 s_return(sc,sc->value);
3714 } else if (sc->code == sc->NIL) {
3715 s_return(sc,sc->value);
3717 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
3718 if (cdr(sc->code) != sc->NIL)
3719 s_clear_flag(sc, TAIL_CONTEXT);
3720 sc->code = car(sc->code);
3724 CASE(OP_OR0): /* or */
3725 if (sc->code == sc->NIL) {
3728 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
3729 if (cdr(sc->code) != sc->NIL)
3730 s_clear_flag(sc, TAIL_CONTEXT);
3731 sc->code = car(sc->code);
3734 CASE(OP_OR1): /* or */
3735 if (is_true(sc->value)) {
3736 s_return(sc,sc->value);
3737 } else if (sc->code == sc->NIL) {
3738 s_return(sc,sc->value);
3740 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
3741 if (cdr(sc->code) != sc->NIL)
3742 s_clear_flag(sc, TAIL_CONTEXT);
3743 sc->code = car(sc->code);
3747 CASE(OP_C0STREAM): /* cons-stream */
3748 s_save(sc,OP_C1STREAM, sc->NIL, cdr(sc->code));
3749 sc->code = car(sc->code);
3752 CASE(OP_C1STREAM): /* cons-stream */
3753 sc->args = sc->value; /* save sc->value to register sc->args for gc */
3755 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
3756 typeflag(x)=T_PROMISE;
3757 s_return_enable_gc(sc, cons(sc, sc->args, x));
3759 CASE(OP_MACRO0): /* macro */
3760 if (is_pair(car(sc->code))) {
3763 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
3767 sc->code = cadr(sc->code);
3769 if (!is_symbol(x)) {
3770 Error_0(sc,"variable is not a symbol");
3772 s_save(sc,OP_MACRO1, sc->NIL, x);
3775 CASE(OP_MACRO1): /* macro */
3776 typeflag(sc->value) = T_MACRO;
3777 x = find_slot_in_env(sc, sc->envir, sc->code, 0);
3779 set_slot_in_env(sc, x, sc->value);
3781 new_slot_in_env(sc, sc->code, sc->value);
3783 s_return(sc,sc->code);
3785 CASE(OP_CASE0): /* case */
3786 s_save(sc,OP_CASE1, sc->NIL, cdr(sc->code));
3787 sc->code = car(sc->code);
3788 s_clear_flag(sc, TAIL_CONTEXT);
3791 CASE(OP_CASE1): /* case */
3792 for (x = sc->code; x != sc->NIL; x = cdr(x)) {
3793 if (!is_pair(y = caar(x))) {
3796 for ( ; y != sc->NIL; y = cdr(y)) {
3797 if (eqv(car(y), sc->value)) {
3806 if (is_pair(caar(x))) {
3808 s_goto(sc,OP_BEGIN);
3810 s_save(sc,OP_CASE2, sc->NIL, cdar(x));
3815 s_return(sc,sc->NIL);
3818 CASE(OP_CASE2): /* case */
3819 if (is_true(sc->value)) {
3820 s_goto(sc,OP_BEGIN);
3822 s_return(sc,sc->NIL);
3825 CASE(OP_PAPPLY): /* apply */
3826 sc->code = car(sc->args);
3827 sc->args = list_star(sc,cdr(sc->args));
3828 /*sc->args = cadr(sc->args);*/
3829 s_goto(sc,OP_APPLY);
3831 CASE(OP_PEVAL): /* eval */
3832 if(cdr(sc->args)!=sc->NIL) {
3833 sc->envir=cadr(sc->args);
3835 sc->code = car(sc->args);
3838 CASE(OP_CONTINUATION): /* call-with-current-continuation */
3839 sc->code = car(sc->args);
3841 sc->args = cons(sc, mk_continuation(sc, sc->dump), sc->NIL);
3843 s_goto(sc,OP_APPLY);
3846 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3847 Error_0(sc,sc->strbuff);
3854 get_property(scheme *sc, pointer obj, pointer key)
3858 assert (is_symbol(obj));
3859 assert (is_symbol(key));
3861 for (x = symprop(obj); x != sc->NIL; x = cdr(x)) {
3873 set_property(scheme *sc, pointer obj, pointer key, pointer value)
3875 #define set_property_allocates 2
3878 assert (is_symbol(obj));
3879 assert (is_symbol(key));
3881 for (x = symprop(obj); x != sc->NIL; x = cdr(x)) {
3889 gc_disable(sc, gc_reservations(set_property));
3890 symprop(obj) = cons(sc, cons(sc, key, value), symprop(obj));
3898 static pointer opexe_2(scheme *sc, enum scheme_opcodes op) {
3907 CASE(OP_INEX2EX): /* inexact->exact */
3909 if(num_is_integer(x)) {
3911 } else if(modf(rvalue_unchecked(x),&dd)==0.0) {
3912 s_return(sc,mk_integer(sc,ivalue(x)));
3914 Error_1(sc,"inexact->exact: not integral:",x);
3919 s_return(sc, mk_real(sc, exp(rvalue(x))));
3923 s_return(sc, mk_real(sc, log(rvalue(x))));
3927 s_return(sc, mk_real(sc, sin(rvalue(x))));
3931 s_return(sc, mk_real(sc, cos(rvalue(x))));
3935 s_return(sc, mk_real(sc, tan(rvalue(x))));
3939 s_return(sc, mk_real(sc, asin(rvalue(x))));
3943 s_return(sc, mk_real(sc, acos(rvalue(x))));
3947 if(cdr(sc->args)==sc->NIL) {
3948 s_return(sc, mk_real(sc, atan(rvalue(x))));
3950 pointer y=cadr(sc->args);
3951 s_return(sc, mk_real(sc, atan2(rvalue(x),rvalue(y))));
3956 s_return(sc, mk_real(sc, sqrt(rvalue(x))));
3961 pointer y=cadr(sc->args);
3963 if (num_is_integer(x) && num_is_integer(y))
3965 /* This 'if' is an R5RS compatibility fix. */
3966 /* NOTE: Remove this 'if' fix for R6RS. */
3967 if (rvalue(x) == 0 && rvalue(y) < 0) {
3970 result = pow(rvalue(x),rvalue(y));
3972 /* Before returning integer result make sure we can. */
3973 /* If the test fails, result is too big for integer. */
3976 long result_as_long = (long)result;
3977 if (result != (double)result_as_long)
3981 s_return(sc, mk_real(sc, result));
3983 s_return(sc, mk_integer(sc, result));
3989 s_return(sc, mk_real(sc, floor(rvalue(x))));
3993 s_return(sc, mk_real(sc, ceil(rvalue(x))));
3995 CASE(OP_TRUNCATE ): {
3996 double rvalue_of_x ;
3998 rvalue_of_x = rvalue(x) ;
3999 if (rvalue_of_x > 0) {
4000 s_return(sc, mk_real(sc, floor(rvalue_of_x)));
4002 s_return(sc, mk_real(sc, ceil(rvalue_of_x)));
4008 if (num_is_integer(x))
4010 s_return(sc, mk_real(sc, round_per_R5RS(rvalue(x))));
4013 CASE(OP_ADD): /* + */
4015 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4016 v=num_add(v,nvalue(car(x)));
4019 s_return_enable_gc(sc, mk_number(sc, v));
4021 CASE(OP_MUL): /* * */
4023 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4024 v=num_mul(v,nvalue(car(x)));
4027 s_return_enable_gc(sc, mk_number(sc, v));
4029 CASE(OP_SUB): /* - */
4030 if(cdr(sc->args)==sc->NIL) {
4035 v = nvalue(car(sc->args));
4037 for (; x != sc->NIL; x = cdr(x)) {
4038 v=num_sub(v,nvalue(car(x)));
4041 s_return_enable_gc(sc, mk_number(sc, v));
4043 CASE(OP_DIV): /* / */
4044 if(cdr(sc->args)==sc->NIL) {
4049 v = nvalue(car(sc->args));
4051 for (; x != sc->NIL; x = cdr(x)) {
4052 if (!is_zero_double(rvalue(car(x))))
4053 v=num_div(v,nvalue(car(x)));
4055 Error_0(sc,"/: division by zero");
4059 s_return_enable_gc(sc, mk_number(sc, v));
4061 CASE(OP_INTDIV): /* quotient */
4062 if(cdr(sc->args)==sc->NIL) {
4067 v = nvalue(car(sc->args));
4069 for (; x != sc->NIL; x = cdr(x)) {
4070 if (ivalue(car(x)) != 0)
4071 v=num_intdiv(v,nvalue(car(x)));
4073 Error_0(sc,"quotient: division by zero");
4077 s_return_enable_gc(sc, mk_number(sc, v));
4079 CASE(OP_REM): /* remainder */
4080 v = nvalue(car(sc->args));
4081 if (ivalue(cadr(sc->args)) != 0)
4082 v=num_rem(v,nvalue(cadr(sc->args)));
4084 Error_0(sc,"remainder: division by zero");
4087 s_return_enable_gc(sc, mk_number(sc, v));
4089 CASE(OP_MOD): /* modulo */
4090 v = nvalue(car(sc->args));
4091 if (ivalue(cadr(sc->args)) != 0)
4092 v=num_mod(v,nvalue(cadr(sc->args)));
4094 Error_0(sc,"modulo: division by zero");
4097 s_return_enable_gc(sc, mk_number(sc, v));
4099 CASE(OP_CAR): /* car */
4100 s_return(sc,caar(sc->args));
4102 CASE(OP_CDR): /* cdr */
4103 s_return(sc,cdar(sc->args));
4105 CASE(OP_CONS): /* cons */
4106 cdr(sc->args) = cadr(sc->args);
4107 s_return(sc,sc->args);
4109 CASE(OP_SETCAR): /* set-car! */
4110 if(!is_immutable(car(sc->args))) {
4111 caar(sc->args) = cadr(sc->args);
4112 s_return(sc,car(sc->args));
4114 Error_0(sc,"set-car!: unable to alter immutable pair");
4117 CASE(OP_SETCDR): /* set-cdr! */
4118 if(!is_immutable(car(sc->args))) {
4119 cdar(sc->args) = cadr(sc->args);
4120 s_return(sc,car(sc->args));
4122 Error_0(sc,"set-cdr!: unable to alter immutable pair");
4125 CASE(OP_CHAR2INT): { /* char->integer */
4127 c=(char)ivalue(car(sc->args));
4129 s_return_enable_gc(sc, mk_integer(sc, (unsigned char) c));
4132 CASE(OP_INT2CHAR): { /* integer->char */
4134 c=(unsigned char)ivalue(car(sc->args));
4136 s_return_enable_gc(sc, mk_character(sc, (char) c));
4139 CASE(OP_CHARUPCASE): {
4141 c=(unsigned char)ivalue(car(sc->args));
4144 s_return_enable_gc(sc, mk_character(sc, (char) c));
4147 CASE(OP_CHARDNCASE): {
4149 c=(unsigned char)ivalue(car(sc->args));
4152 s_return_enable_gc(sc, mk_character(sc, (char) c));
4155 CASE(OP_STR2SYM): /* string->symbol */
4156 gc_disable(sc, gc_reservations (mk_symbol));
4157 s_return_enable_gc(sc, mk_symbol(sc, strvalue(car(sc->args))));
4159 CASE(OP_STR2ATOM): /* string->atom */ {
4160 char *s=strvalue(car(sc->args));
4162 if(cdr(sc->args)!=sc->NIL) {
4163 /* we know cadr(sc->args) is a natural number */
4164 /* see if it is 2, 8, 10, or 16, or error */
4165 pf = ivalue_unchecked(cadr(sc->args));
4166 if(pf == 16 || pf == 10 || pf == 8 || pf == 2) {
4174 Error_1(sc, "string->atom: bad base:", cadr(sc->args));
4175 } else if(*s=='#') /* no use of base! */ {
4176 s_return(sc, mk_sharp_const(sc, s+1));
4178 if (pf == 0 || pf == 10) {
4179 s_return(sc, mk_atom(sc, s));
4183 long iv = strtol(s,&ep,(int )pf);
4185 s_return(sc, mk_integer(sc, iv));
4188 s_return(sc, sc->F);
4194 CASE(OP_SYM2STR): /* symbol->string */
4196 x=mk_string(sc,symname(car(sc->args)));
4198 s_return_enable_gc(sc, x);
4200 CASE(OP_ATOM2STR): /* atom->string */ {
4203 if(cdr(sc->args)!=sc->NIL) {
4204 /* we know cadr(sc->args) is a natural number */
4205 /* see if it is 2, 8, 10, or 16, or error */
4206 pf = ivalue_unchecked(cadr(sc->args));
4207 if(is_number(x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2)) {
4215 Error_1(sc, "atom->string: bad base:", cadr(sc->args));
4216 } else if(is_number(x) || is_character(x) || is_string(x) || is_symbol(x)) {
4219 atom2str(sc,x,(int )pf,&p,&len);
4221 s_return_enable_gc(sc, mk_counted_string(sc, p, len));
4223 Error_1(sc, "atom->string: not an atom:", x);
4227 CASE(OP_MKSTRING): { /* make-string */
4231 len=ivalue(car(sc->args));
4233 if(cdr(sc->args)!=sc->NIL) {
4234 fill=charvalue(cadr(sc->args));
4237 s_return_enable_gc(sc, mk_empty_string(sc, len, (char) fill));
4240 CASE(OP_STRLEN): /* string-length */
4242 s_return_enable_gc(sc, mk_integer(sc, strlength(car(sc->args))));
4244 CASE(OP_STRREF): { /* string-ref */
4248 str=strvalue(car(sc->args));
4250 index=ivalue(cadr(sc->args));
4252 if(index>=strlength(car(sc->args))) {
4253 Error_1(sc,"string-ref: out of bounds:",cadr(sc->args));
4257 s_return_enable_gc(sc,
4258 mk_character(sc, ((unsigned char*) str)[index]));
4261 CASE(OP_STRSET): { /* string-set! */
4266 if(is_immutable(car(sc->args))) {
4267 Error_1(sc,"string-set!: unable to alter immutable string:",car(sc->args));
4269 str=strvalue(car(sc->args));
4271 index=ivalue(cadr(sc->args));
4272 if(index>=strlength(car(sc->args))) {
4273 Error_1(sc,"string-set!: out of bounds:",cadr(sc->args));
4276 c=charvalue(caddr(sc->args));
4279 s_return(sc,car(sc->args));
4282 CASE(OP_STRAPPEND): { /* string-append */
4283 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4288 /* compute needed length for new string */
4289 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4290 len += strlength(car(x));
4293 newstr = mk_empty_string(sc, len, ' ');
4294 /* store the contents of the argument strings into the new string */
4295 for (pos = strvalue(newstr), x = sc->args; x != sc->NIL;
4296 pos += strlength(car(x)), x = cdr(x)) {
4297 memcpy(pos, strvalue(car(x)), strlength(car(x)));
4299 s_return_enable_gc(sc, newstr);
4302 CASE(OP_SUBSTR): { /* substring */
4308 str=strvalue(car(sc->args));
4310 index0=ivalue(cadr(sc->args));
4312 if(index0>strlength(car(sc->args))) {
4313 Error_1(sc,"substring: start out of bounds:",cadr(sc->args));
4316 if(cddr(sc->args)!=sc->NIL) {
4317 index1=ivalue(caddr(sc->args));
4318 if(index1>strlength(car(sc->args)) || index1<index0) {
4319 Error_1(sc,"substring: end out of bounds:",caddr(sc->args));
4322 index1=strlength(car(sc->args));
4327 x=mk_empty_string(sc,len,' ');
4328 memcpy(strvalue(x),str+index0,len);
4331 s_return_enable_gc(sc, x);
4334 CASE(OP_VECTOR): { /* vector */
4337 int len=list_length(sc,sc->args);
4339 Error_1(sc,"vector: not a proper list:",sc->args);
4341 vec=mk_vector(sc,len);
4342 if(sc->no_memory) { s_return(sc, sc->sink); }
4343 for (x = sc->args, i = 0; is_pair(x); x = cdr(x), i++) {
4344 set_vector_elem(vec,i,car(x));
4349 CASE(OP_MKVECTOR): { /* make-vector */
4350 pointer fill=sc->NIL;
4354 len=ivalue(car(sc->args));
4356 if(cdr(sc->args)!=sc->NIL) {
4357 fill=cadr(sc->args);
4359 vec=mk_vector(sc,len);
4360 if(sc->no_memory) { s_return(sc, sc->sink); }
4362 fill_vector(vec,fill);
4367 CASE(OP_VECLEN): /* vector-length */
4369 s_return_enable_gc(sc, mk_integer(sc, ivalue(car(sc->args))));
4371 CASE(OP_VECREF): { /* vector-ref */
4374 index=ivalue(cadr(sc->args));
4376 if(index>=ivalue(car(sc->args))) {
4377 Error_1(sc,"vector-ref: out of bounds:",cadr(sc->args));
4380 s_return(sc,vector_elem(car(sc->args),index));
4383 CASE(OP_VECSET): { /* vector-set! */
4386 if(is_immutable(car(sc->args))) {
4387 Error_1(sc,"vector-set!: unable to alter immutable vector:",car(sc->args));
4390 index=ivalue(cadr(sc->args));
4391 if(index>=ivalue(car(sc->args))) {
4392 Error_1(sc,"vector-set!: out of bounds:",cadr(sc->args));
4395 set_vector_elem(car(sc->args),index,caddr(sc->args));
4396 s_return(sc,car(sc->args));
4400 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
4401 Error_0(sc,sc->strbuff);
4406 static int is_list(scheme *sc, pointer a)
4407 { return list_length(sc,a) >= 0; }
4413 dotted list: -2 minus length before dot
4415 int list_length(scheme *sc, pointer a) {
4422 if (fast == sc->NIL)
4428 if (fast == sc->NIL)
4435 /* Safe because we would have already returned if `fast'
4436 encountered a non-pair. */
4440 /* the fast pointer has looped back around and caught up
4441 with the slow pointer, hence the structure is circular,
4442 not of finite length, and therefore not a list */
4448 static pointer opexe_3(scheme *sc, enum scheme_opcodes op) {
4451 int (*comp_func)(num,num)=0;
4454 CASE(OP_NOT): /* not */
4455 s_retbool(is_false(car(sc->args)));
4456 CASE(OP_BOOLP): /* boolean? */
4457 s_retbool(car(sc->args) == sc->F || car(sc->args) == sc->T);
4458 CASE(OP_EOFOBJP): /* boolean? */
4459 s_retbool(car(sc->args) == sc->EOF_OBJ);
4460 CASE(OP_NULLP): /* null? */
4461 s_retbool(car(sc->args) == sc->NIL);
4462 CASE(OP_NUMEQ): /* = */
4463 CASE(OP_LESS): /* < */
4464 CASE(OP_GRE): /* > */
4465 CASE(OP_LEQ): /* <= */
4466 CASE(OP_GEQ): /* >= */
4468 case OP_NUMEQ: comp_func=num_eq; break;
4469 case OP_LESS: comp_func=num_lt; break;
4470 case OP_GRE: comp_func=num_gt; break;
4471 case OP_LEQ: comp_func=num_le; break;
4472 case OP_GEQ: comp_func=num_ge; break;
4473 default: assert (! "reached");
4479 for (; x != sc->NIL; x = cdr(x)) {
4480 if(!comp_func(v,nvalue(car(x)))) {
4486 CASE(OP_SYMBOLP): /* symbol? */
4487 s_retbool(is_symbol(car(sc->args)));
4488 CASE(OP_NUMBERP): /* number? */
4489 s_retbool(is_number(car(sc->args)));
4490 CASE(OP_STRINGP): /* string? */
4491 s_retbool(is_string(car(sc->args)));
4492 CASE(OP_INTEGERP): /* integer? */
4493 s_retbool(is_integer(car(sc->args)));
4494 CASE(OP_REALP): /* real? */
4495 s_retbool(is_number(car(sc->args))); /* All numbers are real */
4496 CASE(OP_CHARP): /* char? */
4497 s_retbool(is_character(car(sc->args)));
4498 #if USE_CHAR_CLASSIFIERS
4499 CASE(OP_CHARAP): /* char-alphabetic? */
4500 s_retbool(Cisalpha(ivalue(car(sc->args))));
4501 CASE(OP_CHARNP): /* char-numeric? */
4502 s_retbool(Cisdigit(ivalue(car(sc->args))));
4503 CASE(OP_CHARWP): /* char-whitespace? */
4504 s_retbool(Cisspace(ivalue(car(sc->args))));
4505 CASE(OP_CHARUP): /* char-upper-case? */
4506 s_retbool(Cisupper(ivalue(car(sc->args))));
4507 CASE(OP_CHARLP): /* char-lower-case? */
4508 s_retbool(Cislower(ivalue(car(sc->args))));
4510 CASE(OP_PORTP): /* port? */
4511 s_retbool(is_port(car(sc->args)));
4512 CASE(OP_INPORTP): /* input-port? */
4513 s_retbool(is_inport(car(sc->args)));
4514 CASE(OP_OUTPORTP): /* output-port? */
4515 s_retbool(is_outport(car(sc->args)));
4516 CASE(OP_PROCP): /* procedure? */
4518 * continuation should be procedure by the example
4519 * (call-with-current-continuation procedure?) ==> #t
4520 * in R^3 report sec. 6.9
4522 s_retbool(is_proc(car(sc->args)) || is_closure(car(sc->args))
4523 || is_continuation(car(sc->args)) || is_foreign(car(sc->args)));
4524 CASE(OP_PAIRP): /* pair? */
4525 s_retbool(is_pair(car(sc->args)));
4526 CASE(OP_LISTP): /* list? */
4527 s_retbool(list_length(sc,car(sc->args)) >= 0);
4529 CASE(OP_ENVP): /* environment? */
4530 s_retbool(is_environment(car(sc->args)));
4531 CASE(OP_VECTORP): /* vector? */
4532 s_retbool(is_vector(car(sc->args)));
4533 CASE(OP_EQ): /* eq? */
4534 s_retbool(car(sc->args) == cadr(sc->args));
4535 CASE(OP_EQV): /* eqv? */
4536 s_retbool(eqv(car(sc->args), cadr(sc->args)));
4538 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
4539 Error_0(sc,sc->strbuff);
4544 static pointer opexe_4(scheme *sc, enum scheme_opcodes op) {
4548 CASE(OP_FORCE): /* force */
4549 sc->code = car(sc->args);
4550 if (is_promise(sc->code)) {
4551 /* Should change type to closure here */
4552 s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code);
4554 s_goto(sc,OP_APPLY);
4556 s_return(sc,sc->code);
4559 CASE(OP_SAVE_FORCED): /* Save forced value replacing promise */
4560 memcpy(sc->code,sc->value,sizeof(struct cell));
4561 s_return(sc,sc->value);
4563 CASE(OP_WRITE): /* write */
4564 CASE(OP_DISPLAY): /* display */
4565 CASE(OP_WRITE_CHAR): /* write-char */
4566 if(is_pair(cdr(sc->args))) {
4567 if(cadr(sc->args)!=sc->outport) {
4568 x=cons(sc,sc->outport,sc->NIL);
4569 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
4570 sc->outport=cadr(sc->args);
4573 sc->args = car(sc->args);
4579 s_goto(sc,OP_P0LIST);
4581 CASE(OP_NEWLINE): /* newline */
4582 if(is_pair(sc->args)) {
4583 if(car(sc->args)!=sc->outport) {
4584 x=cons(sc,sc->outport,sc->NIL);
4585 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
4586 sc->outport=car(sc->args);
4592 CASE(OP_ERR0): /* error */
4594 if (!is_string(car(sc->args))) {
4595 sc->args=cons(sc,mk_string(sc," -- "),sc->args);
4596 setimmutable(car(sc->args));
4598 putstr(sc, "Error: ");
4599 putstr(sc, strvalue(car(sc->args)));
4600 sc->args = cdr(sc->args);
4601 s_thread_to(sc,OP_ERR1);
4603 CASE(OP_ERR1): /* error */
4605 if (sc->args != sc->NIL) {
4606 s_save(sc,OP_ERR1, cdr(sc->args), sc->NIL);
4607 sc->args = car(sc->args);
4609 s_goto(sc,OP_P0LIST);
4612 if(sc->interactive_repl) {
4613 s_goto(sc,OP_T0LVL);
4619 CASE(OP_REVERSE): /* reverse */
4620 s_return(sc,reverse(sc, sc->NIL, car(sc->args)));
4622 CASE(OP_LIST_STAR): /* list* */
4623 s_return(sc,list_star(sc,sc->args));
4625 CASE(OP_APPEND): /* append */
4632 /* cdr() in the while condition is not a typo. If car() */
4633 /* is used (append '() 'a) will return the wrong result.*/
4634 while (cdr(y) != sc->NIL) {
4635 x = revappend(sc, x, car(y));
4638 Error_0(sc, "non-list argument to append");
4642 s_return(sc, reverse_in_place(sc, car(y), x));
4645 CASE(OP_SET_SYMBOL_PROPERTY): /* set-symbol-property! */
4646 gc_disable(sc, gc_reservations(set_property));
4647 s_return_enable_gc(sc,
4648 set_property(sc, car(sc->args),
4649 cadr(sc->args), caddr(sc->args)));
4651 CASE(OP_SYMBOL_PROPERTY): /* symbol-property */
4652 s_return(sc, get_property(sc, car(sc->args), cadr(sc->args)));
4653 #endif /* USE_PLIST */
4656 CASE(OP_TAG_VALUE): { /* not exposed */
4657 /* This tags sc->value with car(sc->args). Useful to tag
4658 * results of opcode evaluations. */
4660 free_cons(sc, sc->args, &a, &b);
4661 free_cons(sc, b, &b, &c);
4662 assert(c == sc->NIL);
4663 s_return(sc, mk_tagged_value(sc, sc->value, a, b));
4666 CASE(OP_MK_TAGGED): /* make-tagged-value */
4667 if (is_vector(car(sc->args)))
4668 Error_0(sc, "cannot tag vector");
4669 s_return(sc, mk_tagged_value(sc, car(sc->args),
4670 car(cadr(sc->args)),
4671 cdr(cadr(sc->args))));
4673 CASE(OP_GET_TAG): /* get-tag */
4674 s_return(sc, get_tag(sc, car(sc->args)));
4675 #endif /* USE_TAGS */
4677 CASE(OP_QUIT): /* quit */
4678 if(is_pair(sc->args)) {
4679 sc->retcode=ivalue(car(sc->args));
4683 CASE(OP_GC): /* gc */
4684 gc(sc, sc->NIL, sc->NIL);
4687 CASE(OP_GCVERB): /* gc-verbose */
4688 { int was = sc->gc_verbose;
4690 sc->gc_verbose = (car(sc->args) != sc->F);
4694 CASE(OP_NEWSEGMENT): /* new-segment */
4695 if (!is_pair(sc->args) || !is_number(car(sc->args))) {
4696 Error_0(sc,"new-segment: argument must be a number");
4698 alloc_cellseg(sc, (int) ivalue(car(sc->args)));
4701 CASE(OP_OBLIST): /* oblist */
4702 s_return(sc, oblist_all_symbols(sc));
4704 CASE(OP_CURR_INPORT): /* current-input-port */
4705 s_return(sc,sc->inport);
4707 CASE(OP_CURR_OUTPORT): /* current-output-port */
4708 s_return(sc,sc->outport);
4710 CASE(OP_OPEN_INFILE): /* open-input-file */
4711 CASE(OP_OPEN_OUTFILE): /* open-output-file */
4712 CASE(OP_OPEN_INOUTFILE): /* open-input-output-file */ {
4716 case OP_OPEN_INFILE: prop=port_input; break;
4717 case OP_OPEN_OUTFILE: prop=port_output; break;
4718 case OP_OPEN_INOUTFILE: prop=port_input|port_output; break;
4719 default: assert (! "reached");
4721 p=port_from_filename(sc,strvalue(car(sc->args)),prop);
4727 default: assert (! "reached");
4730 #if USE_STRING_PORTS
4731 CASE(OP_OPEN_INSTRING): /* open-input-string */
4732 CASE(OP_OPEN_INOUTSTRING): /* open-input-output-string */ {
4736 case OP_OPEN_INSTRING: prop=port_input; break;
4737 case OP_OPEN_INOUTSTRING: prop=port_input|port_output; break;
4738 default: assert (! "reached");
4740 p=port_from_string(sc, strvalue(car(sc->args)),
4741 strvalue(car(sc->args))+strlength(car(sc->args)), prop);
4747 CASE(OP_OPEN_OUTSTRING): /* open-output-string */ {
4749 if(car(sc->args)==sc->NIL) {
4750 p=port_from_scratch(sc);
4755 p=port_from_string(sc, strvalue(car(sc->args)),
4756 strvalue(car(sc->args))+strlength(car(sc->args)),
4764 CASE(OP_GET_OUTSTRING): /* get-output-string */ {
4767 if ((p=car(sc->args)->_object._port)->kind&port_string) {
4771 size=p->rep.string.curr-p->rep.string.start+1;
4772 str=sc->malloc(size);
4776 memcpy(str,p->rep.string.start,size-1);
4778 s=mk_string(sc,str);
4787 CASE(OP_CLOSE_INPORT): /* close-input-port */
4788 port_close(sc,car(sc->args),port_input);
4791 CASE(OP_CLOSE_OUTPORT): /* close-output-port */
4792 port_close(sc,car(sc->args),port_output);
4795 CASE(OP_INT_ENV): /* interaction-environment */
4796 s_return(sc,sc->global_env);
4798 CASE(OP_CURR_ENV): /* current-environment */
4799 s_return(sc,sc->envir);
4805 static pointer opexe_5(scheme *sc, enum scheme_opcodes op) {
4808 if(sc->nesting!=0) {
4812 Error_1(sc,"unmatched parentheses:",mk_integer(sc,n));
4816 /* ========== reading part ========== */
4818 if(!is_pair(sc->args)) {
4819 s_goto(sc,OP_READ_INTERNAL);
4821 if(!is_inport(car(sc->args))) {
4822 Error_1(sc,"read: not an input port:",car(sc->args));
4824 if(car(sc->args)==sc->inport) {
4825 s_goto(sc,OP_READ_INTERNAL);
4828 sc->inport=car(sc->args);
4829 x=cons(sc,x,sc->NIL);
4830 s_save(sc,OP_SET_INPORT, x, sc->NIL);
4831 s_goto(sc,OP_READ_INTERNAL);
4833 CASE(OP_READ_CHAR): /* read-char */
4834 CASE(OP_PEEK_CHAR): /* peek-char */ {
4836 if(is_pair(sc->args)) {
4837 if(car(sc->args)!=sc->inport) {
4839 x=cons(sc,x,sc->NIL);
4840 s_save(sc,OP_SET_INPORT, x, sc->NIL);
4841 sc->inport=car(sc->args);
4846 s_return(sc,sc->EOF_OBJ);
4848 if(sc->op==OP_PEEK_CHAR) {
4851 s_return(sc,mk_character(sc,c));
4854 CASE(OP_CHAR_READY): /* char-ready? */ {
4855 pointer p=sc->inport;
4857 if(is_pair(sc->args)) {
4860 res=p->_object._port->kind&port_string;
4864 CASE(OP_SET_INPORT): /* set-input-port */
4865 sc->inport=car(sc->args);
4866 s_return(sc,sc->value);
4868 CASE(OP_SET_OUTPORT): /* set-output-port */
4869 sc->outport=car(sc->args);
4870 s_return(sc,sc->value);
4875 s_return(sc,sc->EOF_OBJ);
4878 s_save(sc,OP_RDVEC,sc->NIL,sc->NIL);
4881 sc->tok = token(sc);
4882 if (sc->tok == TOK_RPAREN) {
4883 s_return(sc,sc->NIL);
4884 } else if (sc->tok == TOK_DOT) {
4885 Error_0(sc,"syntax error: illegal dot expression");
4887 sc->nesting_stack[sc->file_i]++;
4888 #if USE_TAGS && SHOW_ERROR_LINE
4889 if (sc->load_stack[sc->file_i].kind & port_file) {
4891 sc->load_stack[sc->file_i].rep.stdio.filename;
4893 sc->load_stack[sc->file_i].rep.stdio.curr_line;
4895 s_save(sc, OP_TAG_VALUE,
4896 cons(sc, filename, cons(sc, lineno, sc->NIL)),
4900 s_save(sc,OP_RDLIST, sc->NIL, sc->NIL);
4901 s_thread_to(sc,OP_RDSEXPR);
4904 s_save(sc,OP_RDQUOTE, sc->NIL, sc->NIL);
4905 sc->tok = token(sc);
4906 s_thread_to(sc,OP_RDSEXPR);
4908 sc->tok = token(sc);
4909 if(sc->tok==TOK_VEC) {
4910 s_save(sc,OP_RDQQUOTEVEC, sc->NIL, sc->NIL);
4912 s_thread_to(sc,OP_RDSEXPR);
4914 s_save(sc,OP_RDQQUOTE, sc->NIL, sc->NIL);
4916 s_thread_to(sc,OP_RDSEXPR);
4918 s_save(sc,OP_RDUNQUOTE, sc->NIL, sc->NIL);
4919 sc->tok = token(sc);
4920 s_thread_to(sc,OP_RDSEXPR);
4922 s_save(sc,OP_RDUQTSP, sc->NIL, sc->NIL);
4923 sc->tok = token(sc);
4924 s_thread_to(sc,OP_RDSEXPR);
4926 s_return(sc,mk_atom(sc, readstr_upto(sc, DELIMITERS)));
4930 Error_0(sc,"Error reading string");
4935 pointer f=find_slot_in_env(sc,sc->envir,sc->SHARP_HOOK,1);
4937 Error_0(sc,"undefined sharp expression");
4939 sc->code=cons(sc,slot_value_in_env(f),sc->NIL);
4943 case TOK_SHARP_CONST:
4944 if ((x = mk_sharp_const(sc, readstr_upto(sc, DELIMITERS))) == sc->NIL) {
4945 Error_0(sc,"undefined sharp expression");
4950 Error_0(sc,"syntax error: illegal token");
4956 sc->args = cons(sc, sc->value, sc->args);
4958 sc->tok = token(sc);
4959 if (sc->tok == TOK_EOF)
4960 { s_return(sc,sc->EOF_OBJ); }
4961 else if (sc->tok == TOK_RPAREN) {
4966 else if (sc->load_stack[sc->file_i].kind & port_file)
4967 port_increment_current_line(sc,
4968 &sc->load_stack[sc->file_i], 1);
4970 sc->nesting_stack[sc->file_i]--;
4971 s_return(sc,reverse_in_place(sc, sc->NIL, sc->args));
4972 } else if (sc->tok == TOK_DOT) {
4973 s_save(sc,OP_RDDOT, sc->args, sc->NIL);
4974 sc->tok = token(sc);
4975 s_thread_to(sc,OP_RDSEXPR);
4977 s_save(sc,OP_RDLIST, sc->args, sc->NIL);;
4978 s_thread_to(sc,OP_RDSEXPR);
4983 if (token(sc) != TOK_RPAREN) {
4984 Error_0(sc,"syntax error: illegal dot expression");
4986 sc->nesting_stack[sc->file_i]--;
4987 s_return(sc,reverse_in_place(sc, sc->value, sc->args));
4992 s_return_enable_gc(sc, cons(sc, sc->QUOTE,
4993 cons(sc, sc->value, sc->NIL)));
4997 s_return_enable_gc(sc, cons(sc, sc->QQUOTE,
4998 cons(sc, sc->value, sc->NIL)));
5000 CASE(OP_RDQQUOTEVEC):
5001 gc_disable(sc, 5 + 2 * gc_reservations (mk_symbol));
5002 s_return_enable_gc(sc,cons(sc, mk_symbol(sc,"apply"),
5003 cons(sc, mk_symbol(sc,"vector"),
5004 cons(sc,cons(sc, sc->QQUOTE,
5005 cons(sc,sc->value,sc->NIL)),
5010 s_return_enable_gc(sc, cons(sc, sc->UNQUOTE,
5011 cons(sc, sc->value, sc->NIL)));
5015 s_return_enable_gc(sc, cons(sc, sc->UNQUOTESP,
5016 cons(sc, sc->value, sc->NIL)));
5019 /*sc->code=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
5020 s_goto(sc,OP_EVAL); Cannot be quoted*/
5021 /*x=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
5022 s_return(sc,x); Cannot be part of pairs*/
5023 /*sc->code=mk_proc(sc,OP_VECTOR);
5025 s_goto(sc,OP_APPLY);*/
5027 s_goto(sc,OP_VECTOR);
5029 /* ========== printing part ========== */
5031 if(is_vector(sc->args)) {
5033 sc->args=cons(sc,sc->args,mk_integer(sc,0));
5034 s_thread_to(sc,OP_PVECFROM);
5035 } else if(is_environment(sc->args)) {
5036 putstr(sc,"#<ENVIRONMENT>");
5038 } else if (!is_pair(sc->args)) {
5039 printatom(sc, sc->args, sc->print_flag);
5041 } else if (car(sc->args) == sc->QUOTE && ok_abbrev(cdr(sc->args))) {
5043 sc->args = cadr(sc->args);
5044 s_thread_to(sc,OP_P0LIST);
5045 } else if (car(sc->args) == sc->QQUOTE && ok_abbrev(cdr(sc->args))) {
5047 sc->args = cadr(sc->args);
5048 s_thread_to(sc,OP_P0LIST);
5049 } else if (car(sc->args) == sc->UNQUOTE && ok_abbrev(cdr(sc->args))) {
5051 sc->args = cadr(sc->args);
5052 s_thread_to(sc,OP_P0LIST);
5053 } else if (car(sc->args) == sc->UNQUOTESP && ok_abbrev(cdr(sc->args))) {
5055 sc->args = cadr(sc->args);
5056 s_thread_to(sc,OP_P0LIST);
5059 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
5060 sc->args = car(sc->args);
5061 s_thread_to(sc,OP_P0LIST);
5065 if (is_pair(sc->args)) {
5066 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
5068 sc->args = car(sc->args);
5069 s_thread_to(sc,OP_P0LIST);
5070 } else if(is_vector(sc->args)) {
5071 s_save(sc,OP_P1LIST,sc->NIL,sc->NIL);
5073 s_thread_to(sc,OP_P0LIST);
5075 if (sc->args != sc->NIL) {
5077 printatom(sc, sc->args, sc->print_flag);
5082 CASE(OP_PVECFROM): {
5083 int i=ivalue_unchecked(cdr(sc->args));
5084 pointer vec=car(sc->args);
5085 int len=ivalue_unchecked(vec);
5090 pointer elem=vector_elem(vec,i);
5091 ivalue_unchecked(cdr(sc->args))=i+1;
5092 s_save(sc,OP_PVECFROM, sc->args, sc->NIL);
5096 s_thread_to(sc,OP_P0LIST);
5101 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
5102 Error_0(sc,sc->strbuff);
5108 static pointer opexe_6(scheme *sc, enum scheme_opcodes op) {
5113 CASE(OP_LIST_LENGTH): /* length */ /* a.k */
5114 v=list_length(sc,car(sc->args));
5116 Error_1(sc,"length: not a list:",car(sc->args));
5119 s_return_enable_gc(sc, mk_integer(sc, v));
5121 CASE(OP_ASSQ): /* assq */ /* a.k */
5123 for (y = cadr(sc->args); is_pair(y); y = cdr(y)) {
5124 if (!is_pair(car(y))) {
5125 Error_0(sc,"unable to handle non pair element");
5131 s_return(sc,car(y));
5137 CASE(OP_GET_CLOSURE): /* get-closure-code */ /* a.k */
5138 sc->args = car(sc->args);
5139 if (sc->args == sc->NIL) {
5141 } else if (is_closure(sc->args)) {
5143 s_return_enable_gc(sc, cons(sc, sc->LAMBDA,
5144 closure_code(sc->value)));
5145 } else if (is_macro(sc->args)) {
5147 s_return_enable_gc(sc, cons(sc, sc->LAMBDA,
5148 closure_code(sc->value)));
5152 CASE(OP_CLOSUREP): /* closure? */
5154 * Note, macro object is also a closure.
5155 * Therefore, (closure? <#MACRO>) ==> #t
5157 s_retbool(is_closure(car(sc->args)));
5158 CASE(OP_MACROP): /* macro? */
5159 s_retbool(is_macro(car(sc->args)));
5160 CASE(OP_VM_HISTORY): /* *vm-history* */
5161 s_return(sc, history_flatten(sc));
5163 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
5164 Error_0(sc,sc->strbuff);
5166 return sc->T; /* NOTREACHED */
5169 typedef pointer (*dispatch_func)(scheme *, enum scheme_opcodes);
5171 typedef int (*test_predicate)(pointer);
5173 static int is_any(pointer p) {
5178 static int is_nonneg(pointer p) {
5179 return ivalue(p)>=0 && is_integer(p);
5182 /* Correspond carefully with following defines! */
5189 {is_string, "string"},
5190 {is_symbol, "symbol"},
5192 {is_inport,"input port"},
5193 {is_outport,"output port"},
5194 {is_environment, "environment"},
5197 {is_character, "character"},
5198 {is_vector, "vector"},
5199 {is_number, "number"},
5200 {is_integer, "integer"},
5201 {is_nonneg, "non-negative integer"}
5205 #define TST_ANY "\001"
5206 #define TST_STRING "\002"
5207 #define TST_SYMBOL "\003"
5208 #define TST_PORT "\004"
5209 #define TST_INPORT "\005"
5210 #define TST_OUTPORT "\006"
5211 #define TST_ENVIRONMENT "\007"
5212 #define TST_PAIR "\010"
5213 #define TST_LIST "\011"
5214 #define TST_CHAR "\012"
5215 #define TST_VECTOR "\013"
5216 #define TST_NUMBER "\014"
5217 #define TST_INTEGER "\015"
5218 #define TST_NATURAL "\016"
5225 char *arg_tests_encoding;
5228 #define INF_ARG 0xffff
5230 static op_code_info dispatch_table[]= {
5231 #define _OP_DEF(A,B,C,D,E,OP) {A,B,C,D,E},
5232 #include "opdefines.h"
5236 static const char *procname(pointer x) {
5238 const char *name=dispatch_table[n].name;
5245 /* kernel of this interpreter */
5246 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op) {
5249 op_code_info *pcd=dispatch_table+sc->op;
5250 if (pcd->name!=0) { /* if built-in function, check arguments */
5251 char msg[STRBUFFSIZE];
5253 int n=list_length(sc,sc->args);
5255 /* Check number of arguments */
5256 if(n<pcd->min_arity) {
5258 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5260 pcd->min_arity==pcd->max_arity?"":" at least",
5263 if(ok && n>pcd->max_arity) {
5265 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5267 pcd->min_arity==pcd->max_arity?"":" at most",
5271 if(pcd->arg_tests_encoding!=0) {
5274 const char *t=pcd->arg_tests_encoding;
5275 pointer arglist=sc->args;
5277 pointer arg=car(arglist);
5279 if(j==TST_LIST[0]) {
5280 if(arg!=sc->NIL && !is_pair(arg)) break;
5282 if(!tests[j].fct(arg)) break;
5285 if(t[1]!=0) {/* last test is replicated as necessary */
5288 arglist=cdr(arglist);
5293 snprintf(msg, STRBUFFSIZE, "%s: argument %d must be: %s, got: %s",
5297 type_to_string(type(car(arglist))));
5302 if(_Error_1(sc,msg,0)==sc->NIL) {
5305 pcd=dispatch_table+sc->op;
5308 ok_to_freely_gc(sc);
5309 if (pcd->func(sc, (enum scheme_opcodes)sc->op) == sc->NIL) {
5313 fprintf(stderr,"No memory!\n");
5319 /* ========== Initialization of internal keywords ========== */
5321 static void assign_syntax(scheme *sc, char *name) {
5324 x = oblist_add_by_name(sc, name);
5325 typeflag(x) |= T_SYNTAX;
5328 static void assign_proc(scheme *sc, enum scheme_opcodes op, char *name) {
5331 x = mk_symbol(sc, name);
5333 new_slot_in_env(sc, x, y);
5336 static pointer mk_proc(scheme *sc, enum scheme_opcodes op) {
5339 y = get_cell(sc, sc->NIL, sc->NIL);
5340 typeflag(y) = (T_PROC | T_ATOM);
5341 ivalue_unchecked(y) = (long) op;
5346 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5347 static int syntaxnum(pointer p) {
5348 const char *s=strvalue(car(p));
5349 switch(strlength(car(p))) {
5351 if(s[0]=='i') return OP_IF0; /* if */
5352 else return OP_OR0; /* or */
5354 if(s[0]=='a') return OP_AND0; /* and */
5355 else return OP_LET0; /* let */
5358 case 'e': return OP_CASE0; /* case */
5359 case 'd': return OP_COND0; /* cond */
5360 case '*': return OP_LET0AST; /* let* */
5361 default: return OP_SET0; /* set! */
5365 case 'g': return OP_BEGIN; /* begin */
5366 case 'l': return OP_DELAY; /* delay */
5367 case 'c': return OP_MACRO0; /* macro */
5368 default: return OP_QUOTE; /* quote */
5372 case 'm': return OP_LAMBDA; /* lambda */
5373 case 'f': return OP_DEF0; /* define */
5374 default: return OP_LET0REC; /* letrec */
5377 return OP_C0STREAM; /* cons-stream */
5381 /* initialization of TinyScheme */
5383 INTERFACE static pointer s_cons(scheme *sc, pointer a, pointer b) {
5384 return cons(sc,a,b);
5386 INTERFACE static pointer s_immutable_cons(scheme *sc, pointer a, pointer b) {
5387 return immutable_cons(sc,a,b);
5390 static struct scheme_interface vtbl ={
5405 get_foreign_object_vtable,
5406 get_foreign_object_data,
5458 scheme *scheme_init_new() {
5459 scheme *sc=(scheme*)malloc(sizeof(scheme));
5460 if(!scheme_init(sc)) {
5468 scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free) {
5469 scheme *sc=(scheme*)malloc(sizeof(scheme));
5470 if(!scheme_init_custom_alloc(sc,malloc,free)) {
5479 int scheme_init(scheme *sc) {
5480 return scheme_init_custom_alloc(sc,malloc,free);
5483 int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
5484 int i, n=sizeof(dispatch_table)/sizeof(dispatch_table[0]);
5487 num_zero.is_fixnum=1;
5488 num_zero.value.ivalue=0;
5489 num_one.is_fixnum=1;
5490 num_one.value.ivalue=1;
5498 sc->last_cell_seg = -1;
5499 sc->sink = &sc->_sink;
5500 sc->NIL = &sc->_NIL;
5501 sc->T = &sc->_HASHT;
5502 sc->F = &sc->_HASHF;
5503 sc->EOF_OBJ=&sc->_EOF_OBJ;
5505 #if USE_SMALL_INTEGERS
5506 if (initialize_small_integers(sc)) {
5512 sc->free_cell = &sc->_NIL;
5514 sc->inhibit_gc = GC_ENABLED;
5515 sc->reserved_cells = 0;
5516 sc->reserved_lineno = 0;
5519 sc->outport=sc->NIL;
5520 sc->save_inport=sc->NIL;
5521 sc->loadport=sc->NIL;
5523 memset (sc->nesting_stack, 0, sizeof sc->nesting_stack);
5524 sc->interactive_repl=0;
5525 sc->strbuff = sc->malloc(STRBUFFSIZE);
5526 if (sc->strbuff == 0) {
5530 sc->strbuff_size = STRBUFFSIZE;
5532 if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
5537 dump_stack_initialize(sc);
5544 typeflag(sc->NIL) = (T_NIL | T_ATOM | MARK);
5545 car(sc->NIL) = cdr(sc->NIL) = sc->NIL;
5547 typeflag(sc->T) = (T_BOOLEAN | T_ATOM | MARK);
5548 car(sc->T) = cdr(sc->T) = sc->T;
5550 typeflag(sc->F) = (T_BOOLEAN | T_ATOM | MARK);
5551 car(sc->F) = cdr(sc->F) = sc->F;
5553 typeflag(sc->EOF_OBJ) = (T_EOF_OBJ | T_ATOM | MARK);
5554 car(sc->EOF_OBJ) = cdr(sc->EOF_OBJ) = sc->EOF_OBJ;
5556 typeflag(sc->sink) = (T_SINK | T_PAIR | MARK);
5557 car(sc->sink) = cdr(sc->sink) = sc->NIL;
5559 sc->c_nest = sc->NIL;
5561 sc->oblist = oblist_initial_value(sc);
5562 /* init global_env */
5563 new_frame_in_env(sc, sc->NIL);
5564 sc->global_env = sc->envir;
5566 x = mk_symbol(sc,"else");
5567 new_slot_in_env(sc, x, sc->T);
5569 assign_syntax(sc, "lambda");
5570 assign_syntax(sc, "quote");
5571 assign_syntax(sc, "define");
5572 assign_syntax(sc, "if");
5573 assign_syntax(sc, "begin");
5574 assign_syntax(sc, "set!");
5575 assign_syntax(sc, "let");
5576 assign_syntax(sc, "let*");
5577 assign_syntax(sc, "letrec");
5578 assign_syntax(sc, "cond");
5579 assign_syntax(sc, "delay");
5580 assign_syntax(sc, "and");
5581 assign_syntax(sc, "or");
5582 assign_syntax(sc, "cons-stream");
5583 assign_syntax(sc, "macro");
5584 assign_syntax(sc, "case");
5586 for(i=0; i<n; i++) {
5587 if(dispatch_table[i].name!=0) {
5588 assign_proc(sc, (enum scheme_opcodes)i, dispatch_table[i].name);
5592 history_init(sc, 8, 8);
5594 /* initialization of global pointers to special symbols */
5595 sc->LAMBDA = mk_symbol(sc, "lambda");
5596 sc->QUOTE = mk_symbol(sc, "quote");
5597 sc->QQUOTE = mk_symbol(sc, "quasiquote");
5598 sc->UNQUOTE = mk_symbol(sc, "unquote");
5599 sc->UNQUOTESP = mk_symbol(sc, "unquote-splicing");
5600 sc->FEED_TO = mk_symbol(sc, "=>");
5601 sc->COLON_HOOK = mk_symbol(sc,"*colon-hook*");
5602 sc->ERROR_HOOK = mk_symbol(sc, "*error-hook*");
5603 sc->SHARP_HOOK = mk_symbol(sc, "*sharp-hook*");
5604 #if USE_COMPILE_HOOK
5605 sc->COMPILE_HOOK = mk_symbol(sc, "*compile-hook*");
5608 return !sc->no_memory;
5611 void scheme_set_input_port_file(scheme *sc, FILE *fin) {
5612 sc->inport=port_from_file(sc,fin,port_input);
5615 void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end) {
5616 sc->inport=port_from_string(sc,start,past_the_end,port_input);
5619 void scheme_set_output_port_file(scheme *sc, FILE *fout) {
5620 sc->outport=port_from_file(sc,fout,port_output);
5623 void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end) {
5624 sc->outport=port_from_string(sc,start,past_the_end,port_output);
5627 void scheme_set_external_data(scheme *sc, void *p) {
5631 void scheme_deinit(scheme *sc) {
5635 sc->global_env=sc->NIL;
5636 dump_stack_free(sc);
5642 if(is_port(sc->inport)) {
5643 typeflag(sc->inport) = T_ATOM;
5646 sc->outport=sc->NIL;
5647 if(is_port(sc->save_inport)) {
5648 typeflag(sc->save_inport) = T_ATOM;
5650 sc->save_inport=sc->NIL;
5651 if(is_port(sc->loadport)) {
5652 typeflag(sc->loadport) = T_ATOM;
5654 sc->loadport=sc->NIL;
5657 for(i=0; i<=sc->file_i; i++) {
5658 if (sc->load_stack[i].kind & port_file)
5659 port_clear_location(sc, &sc->load_stack[i]);
5664 gc(sc,sc->NIL,sc->NIL);
5666 #if USE_SMALL_INTEGERS
5667 sc->free(sc->integer_alloc);
5670 for(i=0; i<=sc->last_cell_seg; i++) {
5671 sc->free(sc->alloc_seg[i]);
5673 sc->free(sc->strbuff);
5676 void scheme_load_file(scheme *sc, FILE *fin)
5677 { scheme_load_named_file(sc,fin,0); }
5679 void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename) {
5680 dump_stack_reset(sc);
5681 sc->envir = sc->global_env;
5683 sc->load_stack[0].kind=port_input|port_file;
5684 sc->load_stack[0].rep.stdio.file=fin;
5685 sc->loadport=mk_port(sc,sc->load_stack);
5688 sc->interactive_repl=1;
5692 port_reset_current_line(sc, &sc->load_stack[0]);
5693 if(fin!=stdin && filename)
5694 sc->load_stack[0].rep.stdio.filename = mk_string(sc, filename);
5696 sc->load_stack[0].rep.stdio.filename = mk_string(sc, "<unknown>");
5699 sc->inport=sc->loadport;
5700 sc->args = mk_integer(sc,sc->file_i);
5701 Eval_Cycle(sc, OP_T0LVL);
5702 typeflag(sc->loadport)=T_ATOM;
5703 if(sc->retcode==0) {
5704 sc->retcode=sc->nesting!=0;
5708 port_clear_location(sc, &sc->load_stack[0]);
5712 void scheme_load_string(scheme *sc, const char *cmd) {
5713 dump_stack_reset(sc);
5714 sc->envir = sc->global_env;
5716 sc->load_stack[0].kind=port_input|port_string;
5717 sc->load_stack[0].rep.string.start=(char*)cmd; /* This func respects const */
5718 sc->load_stack[0].rep.string.past_the_end=(char*)cmd+strlen(cmd);
5719 sc->load_stack[0].rep.string.curr=(char*)cmd;
5720 sc->loadport=mk_port(sc,sc->load_stack);
5722 sc->interactive_repl=0;
5723 sc->inport=sc->loadport;
5724 sc->args = mk_integer(sc,sc->file_i);
5725 Eval_Cycle(sc, OP_T0LVL);
5726 typeflag(sc->loadport)=T_ATOM;
5727 if(sc->retcode==0) {
5728 sc->retcode=sc->nesting!=0;
5732 void scheme_define(scheme *sc, pointer envir, pointer symbol, pointer value) {
5735 x=find_slot_in_env(sc,envir,symbol,0);
5737 set_slot_in_env(sc, x, value);
5739 new_slot_spec_in_env(sc, envir, symbol, value);
5744 void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr)
5748 mk_symbol(sc,sr->name),
5749 mk_foreign_func(sc, sr->f));
5752 void scheme_register_foreign_func_list(scheme * sc,
5753 scheme_registerable * list,
5757 for(i = 0; i < count; i++)
5759 scheme_register_foreign_func(sc, list + i);
5763 pointer scheme_apply0(scheme *sc, const char *procname)
5764 { return scheme_eval(sc, cons(sc,mk_symbol(sc,procname),sc->NIL)); }
5766 void save_from_C_call(scheme *sc)
5768 pointer saved_data =
5775 sc->c_nest = cons(sc, saved_data, sc->c_nest);
5776 /* Truncate the dump stack so TS will return here when done, not
5777 directly resume pre-C-call operations. */
5778 dump_stack_reset(sc);
5780 void restore_from_C_call(scheme *sc)
5782 car(sc->sink) = caar(sc->c_nest);
5783 sc->envir = cadar(sc->c_nest);
5784 sc->dump = cdr(cdar(sc->c_nest));
5786 sc->c_nest = cdr(sc->c_nest);
5789 /* "func" and "args" are assumed to be already eval'ed. */
5790 pointer scheme_call(scheme *sc, pointer func, pointer args)
5792 int old_repl = sc->interactive_repl;
5793 sc->interactive_repl = 0;
5794 save_from_C_call(sc);
5795 sc->envir = sc->global_env;
5799 Eval_Cycle(sc, OP_APPLY);
5800 sc->interactive_repl = old_repl;
5801 restore_from_C_call(sc);
5805 pointer scheme_eval(scheme *sc, pointer obj)
5807 int old_repl = sc->interactive_repl;
5808 sc->interactive_repl = 0;
5809 save_from_C_call(sc);
5813 Eval_Cycle(sc, OP_EVAL);
5814 sc->interactive_repl = old_repl;
5815 restore_from_C_call(sc);
5822 /* ========== Main ========== */
5826 #if defined(__APPLE__) && !defined (OSX)
5829 extern MacTS_main(int argc, char **argv);
5831 int argc = ccommand(&argv);
5832 MacTS_main(argc,argv);
5835 int MacTS_main(int argc, char **argv) {
5837 int main(int argc, char **argv) {
5841 char *file_name=InitFile;
5848 if(argc==2 && strcmp(argv[1],"-?")==0) {
5849 printf("Usage: tinyscheme -?\n");
5850 printf("or: tinyscheme [<file1> <file2> ...]\n");
5851 printf("followed by\n");
5852 printf(" -1 <file> [<arg1> <arg2> ...]\n");
5853 printf(" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5854 printf("assuming that the executable is named tinyscheme.\n");
5855 printf("Use - as filename for stdin.\n");
5858 if(!scheme_init(&sc)) {
5859 fprintf(stderr,"Could not initialize!\n");
5862 scheme_set_input_port_file(&sc, stdin);
5863 scheme_set_output_port_file(&sc, stdout);
5865 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"load-extension"),mk_foreign_func(&sc, scm_load_ext));
5868 if(access(file_name,0)!=0) {
5869 char *p=getenv("TINYSCHEMEINIT");
5875 if(strcmp(file_name,"-")==0) {
5877 } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0) {
5878 pointer args=sc.NIL;
5879 isfile=file_name[1]=='1';
5881 if(strcmp(file_name,"-")==0) {
5884 fin=fopen(file_name,"r");
5886 for(;*argv;argv++) {
5887 pointer value=mk_string(&sc,*argv);
5888 args=cons(&sc,value,args);
5890 args=reverse_in_place(&sc,sc.NIL,args);
5891 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args);
5894 fin=fopen(file_name,"r");
5896 if(isfile && fin==0) {
5897 fprintf(stderr,"Could not open file %s\n",file_name);
5900 scheme_load_named_file(&sc,fin,file_name);
5902 scheme_load_string(&sc,file_name);
5904 if(!isfile || fin!=stdin) {
5906 fprintf(stderr,"Errors encountered reading %s\n",file_name);
5914 } while(file_name!=0);
5916 scheme_load_named_file(&sc,stdin,0);