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, const char *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 */
1555 /* Mark tag if p has one. */
1562 if (q && !is_mark(q)) {
1563 setatom(p); /* a note that we have moved car */
1569 E5: q = cdr(p); /* down cdr */
1570 if (q && !is_mark(q)) {
1576 E6: /* up. Undo the link switching from steps E4 and E5. */
1594 /* garbage collection. parameter a, b is marked. */
1595 static void gc(scheme *sc, pointer a, pointer b) {
1599 assert (gc_enabled (sc));
1601 if(sc->gc_verbose) {
1602 putstr(sc, "gc...");
1605 /* mark system globals */
1607 mark(sc->global_env);
1609 /* mark current registers */
1614 dump_stack_mark(sc);
1617 mark(sc->save_inport);
1621 /* Mark recent objects the interpreter doesn't know about yet. */
1622 mark(car(sc->sink));
1623 /* Mark any older stuff above nested C calls */
1626 /* mark variables a, b */
1630 /* garbage collect */
1633 sc->free_cell = sc->NIL;
1634 /* free-list is kept sorted by address so as to maintain consecutive
1635 ranges, if possible, for use with vectors. Here we scan the cells
1636 (which are also kept sorted by address) downwards to build the
1637 free-list in sorted order.
1639 for (i = sc->last_cell_seg; i >= 0; i--) {
1640 p = sc->cell_seg[i] + CELL_SEGSIZE;
1641 while (--p >= sc->cell_seg[i]) {
1646 if (typeflag(p) & T_FINALIZE) {
1647 finalize_cell(sc, p);
1652 cdr(p) = sc->free_cell;
1658 if (sc->gc_verbose) {
1660 snprintf(msg,80,"done: %ld cells were recovered.\n", sc->fcells);
1665 static void finalize_cell(scheme *sc, pointer a) {
1667 sc->free(strvalue(a));
1668 } else if(is_port(a)) {
1669 if(a->_object._port->kind&port_file
1670 && a->_object._port->rep.stdio.closeit) {
1671 port_close(sc,a,port_input|port_output);
1672 } else if (a->_object._port->kind & port_srfi6) {
1673 sc->free(a->_object._port->rep.string.start);
1675 sc->free(a->_object._port);
1676 } else if(is_foreign_object(a)) {
1677 a->_object._foreign_object._vtable->finalize(sc, a->_object._foreign_object._data);
1681 /* ========== Routines for Reading ========== */
1683 static int file_push(scheme *sc, const char *fname) {
1686 if (sc->file_i == MAXFIL-1)
1688 fin=fopen(fname,"r");
1691 sc->load_stack[sc->file_i].kind=port_file|port_input;
1692 sc->load_stack[sc->file_i].rep.stdio.file=fin;
1693 sc->load_stack[sc->file_i].rep.stdio.closeit=1;
1694 sc->nesting_stack[sc->file_i]=0;
1695 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1698 sc->load_stack[sc->file_i].rep.stdio.curr_line = 0;
1700 sc->load_stack[sc->file_i].rep.stdio.filename = store_string(sc, strlen(fname), fname, 0);
1706 static void file_pop(scheme *sc) {
1707 if(sc->file_i != 0) {
1708 sc->nesting=sc->nesting_stack[sc->file_i];
1709 port_close(sc,sc->loadport,port_input);
1711 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1715 static int file_interactive(scheme *sc) {
1716 return sc->file_i==0 && sc->load_stack[0].rep.stdio.file==stdin
1717 && sc->inport->_object._port->kind&port_file;
1720 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop) {
1724 if(prop==(port_input|port_output)) {
1726 } else if(prop==port_output) {
1735 pt=port_rep_from_file(sc,f,prop);
1736 pt->rep.stdio.closeit=1;
1740 pt->rep.stdio.filename = store_string(sc, strlen(fn), fn, 0);
1742 pt->rep.stdio.curr_line = 0;
1747 static pointer port_from_filename(scheme *sc, const char *fn, int prop) {
1749 pt=port_rep_from_filename(sc,fn,prop);
1753 return mk_port(sc,pt);
1756 static port *port_rep_from_file(scheme *sc, FILE *f, int prop)
1760 pt = (port *)sc->malloc(sizeof *pt);
1764 pt->kind = port_file | prop;
1765 pt->rep.stdio.file = f;
1766 pt->rep.stdio.closeit = 0;
1770 static pointer port_from_file(scheme *sc, FILE *f, int prop) {
1772 pt=port_rep_from_file(sc,f,prop);
1776 return mk_port(sc,pt);
1779 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1781 pt=(port*)sc->malloc(sizeof(port));
1785 pt->kind=port_string|prop;
1786 pt->rep.string.start=start;
1787 pt->rep.string.curr=start;
1788 pt->rep.string.past_the_end=past_the_end;
1792 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1794 pt=port_rep_from_string(sc,start,past_the_end,prop);
1798 return mk_port(sc,pt);
1801 #define BLOCK_SIZE 256
1803 static port *port_rep_from_scratch(scheme *sc) {
1806 pt=(port*)sc->malloc(sizeof(port));
1810 start=sc->malloc(BLOCK_SIZE);
1814 memset(start,' ',BLOCK_SIZE-1);
1815 start[BLOCK_SIZE-1]='\0';
1816 pt->kind=port_string|port_output|port_srfi6;
1817 pt->rep.string.start=start;
1818 pt->rep.string.curr=start;
1819 pt->rep.string.past_the_end=start+BLOCK_SIZE-1;
1823 static pointer port_from_scratch(scheme *sc) {
1825 pt=port_rep_from_scratch(sc);
1829 return mk_port(sc,pt);
1832 static void port_close(scheme *sc, pointer p, int flag) {
1833 port *pt=p->_object._port;
1835 if((pt->kind & (port_input|port_output))==0) {
1836 if(pt->kind&port_file) {
1839 /* Cleanup is here so (close-*-port) functions could work too */
1840 pt->rep.stdio.curr_line = 0;
1842 if(pt->rep.stdio.filename)
1843 sc->free(pt->rep.stdio.filename);
1846 fclose(pt->rep.stdio.file);
1852 /* get new character from input file */
1853 static int inchar(scheme *sc) {
1857 pt = sc->inport->_object._port;
1858 if(pt->kind & port_saw_EOF)
1860 c = basic_inchar(pt);
1861 if(c == EOF && sc->inport == sc->loadport) {
1862 /* Instead, set port_saw_EOF */
1863 pt->kind |= port_saw_EOF;
1872 static int basic_inchar(port *pt) {
1873 if(pt->kind & port_file) {
1874 return fgetc(pt->rep.stdio.file);
1876 if(*pt->rep.string.curr == 0 ||
1877 pt->rep.string.curr == pt->rep.string.past_the_end) {
1880 return *pt->rep.string.curr++;
1885 /* back character to input buffer */
1886 static void backchar(scheme *sc, int c) {
1889 pt=sc->inport->_object._port;
1890 if(pt->kind&port_file) {
1891 ungetc(c,pt->rep.stdio.file);
1893 if(pt->rep.string.curr!=pt->rep.string.start) {
1894 --pt->rep.string.curr;
1899 static int realloc_port_string(scheme *sc, port *p)
1901 char *start=p->rep.string.start;
1902 size_t old_size = p->rep.string.past_the_end - start;
1903 size_t new_size=p->rep.string.past_the_end-start+1+BLOCK_SIZE;
1904 char *str=sc->malloc(new_size);
1906 memset(str,' ',new_size-1);
1907 str[new_size-1]='\0';
1908 memcpy(str, start, old_size);
1909 p->rep.string.start=str;
1910 p->rep.string.past_the_end=str+new_size-1;
1911 p->rep.string.curr-=start-str;
1919 INTERFACE void putstr(scheme *sc, const char *s) {
1920 port *pt=sc->outport->_object._port;
1921 if(pt->kind&port_file) {
1922 fputs(s,pt->rep.stdio.file);
1925 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
1926 *pt->rep.string.curr++=*s;
1927 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
1928 *pt->rep.string.curr++=*s;
1934 static void putchars(scheme *sc, const char *s, int len) {
1935 port *pt=sc->outport->_object._port;
1936 if(pt->kind&port_file) {
1937 fwrite(s,1,len,pt->rep.stdio.file);
1940 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
1941 *pt->rep.string.curr++=*s++;
1942 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
1943 *pt->rep.string.curr++=*s++;
1949 INTERFACE void putcharacter(scheme *sc, int c) {
1950 port *pt=sc->outport->_object._port;
1951 if(pt->kind&port_file) {
1952 fputc(c,pt->rep.stdio.file);
1954 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
1955 *pt->rep.string.curr++=c;
1956 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
1957 *pt->rep.string.curr++=c;
1962 /* read characters up to delimiter, but cater to character constants */
1963 static char *readstr_upto(scheme *sc, char *delim) {
1964 char *p = sc->strbuff;
1966 while ((p - sc->strbuff < sc->strbuff_size) &&
1967 !is_one_of(delim, (*p++ = inchar(sc))));
1969 if(p == sc->strbuff+2 && p[-2] == '\\') {
1978 /* read string expression "xxx...xxx" */
1979 static pointer readstrexp(scheme *sc) {
1980 char *p = sc->strbuff;
1983 enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state=st_ok;
1990 if(p-sc->strbuff > (sc->strbuff_size)-1) {
1991 ptrdiff_t offset = p - sc->strbuff;
1992 if (expand_strbuff(sc) != 0) {
1995 p = sc->strbuff + offset;
2005 return mk_counted_string(sc,sc->strbuff,p-sc->strbuff);
2054 if(c>='0' && c<='F') {
2058 c1=(c1<<4)+c-'A'+10;
2072 if (c < '0' || c > '7')
2080 if (state==st_oct2 && c1 >= 32)
2085 if (state == st_oct1)
2099 /* check c is in chars */
2100 static INLINE int is_one_of(char *s, int c) {
2101 if(c==EOF) return 1;
2108 /* skip white characters */
2109 static INLINE int skipspace(scheme *sc) {
2110 int c = 0, curr_line = 0;
2118 } while (isspace(c));
2122 if (sc->load_stack[sc->file_i].kind & port_file)
2123 sc->load_stack[sc->file_i].rep.stdio.curr_line += curr_line;
2135 static int token(scheme *sc) {
2138 if(c == EOF) { return (TOK_EOF); }
2139 switch (c=inchar(sc)) {
2143 return (TOK_LPAREN);
2145 return (TOK_RPAREN);
2148 if(is_one_of(" \n\t",c)) {
2158 while ((c=inchar(sc)) != '\n' && c!=EOF)
2162 if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
2163 sc->load_stack[sc->file_i].rep.stdio.curr_line++;
2167 { return (TOK_EOF); }
2169 { return (token(sc));}
2171 return (TOK_DQUOTE);
2173 return (TOK_BQUOTE);
2175 if ((c=inchar(sc)) == '@') {
2176 return (TOK_ATMARK);
2185 } else if(c == '!') {
2186 while ((c=inchar(sc)) != '\n' && c!=EOF)
2190 if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
2191 sc->load_stack[sc->file_i].rep.stdio.curr_line++;
2195 { return (TOK_EOF); }
2197 { return (token(sc));}
2200 if(is_one_of(" tfodxb\\",c)) {
2201 return TOK_SHARP_CONST;
2212 /* ========== Routines for Printing ========== */
2213 #define ok_abbrev(x) (is_pair(x) && cdr(x) == sc->NIL)
2215 static void printslashstring(scheme *sc, char *p, int len) {
2217 unsigned char *s=(unsigned char*)p;
2218 putcharacter(sc,'"');
2219 for ( i=0; i<len; i++) {
2220 if(*s==0xff || *s=='"' || *s<' ' || *s=='\\') {
2221 putcharacter(sc,'\\');
2224 putcharacter(sc,'"');
2227 putcharacter(sc,'n');
2230 putcharacter(sc,'t');
2233 putcharacter(sc,'r');
2236 putcharacter(sc,'\\');
2240 putcharacter(sc,'x');
2242 putcharacter(sc,d+'0');
2244 putcharacter(sc,d-10+'A');
2248 putcharacter(sc,d+'0');
2250 putcharacter(sc,d-10+'A');
2255 putcharacter(sc,*s);
2259 putcharacter(sc,'"');
2264 static void printatom(scheme *sc, pointer l, int f) {
2267 atom2str(sc,l,f,&p,&len);
2272 /* Uses internal buffer unless string pointer is already available */
2273 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen) {
2278 } else if (l == sc->T) {
2280 } else if (l == sc->F) {
2282 } else if (l == sc->EOF_OBJ) {
2284 } else if (is_port(l)) {
2286 } else if (is_number(l)) {
2288 if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */ {
2289 if(num_is_integer(l)) {
2290 snprintf(p, STRBUFFSIZE, "%ld", ivalue_unchecked(l));
2292 snprintf(p, STRBUFFSIZE, "%.10g", rvalue_unchecked(l));
2293 /* r5rs says there must be a '.' (unless 'e'?) */
2294 f = strcspn(p, ".e");
2296 p[f] = '.'; /* not found, so add '.0' at the end */
2305 snprintf(p, STRBUFFSIZE, "%lx", v);
2307 snprintf(p, STRBUFFSIZE, "-%lx", -v);
2308 } else if (f == 8) {
2310 snprintf(p, STRBUFFSIZE, "%lo", v);
2312 snprintf(p, STRBUFFSIZE, "-%lo", -v);
2313 } else if (f == 2) {
2314 unsigned long b = (v < 0) ? -v : v;
2315 p = &p[STRBUFFSIZE-1];
2317 do { *--p = (b&1) ? '1' : '0'; b >>= 1; } while (b != 0);
2318 if (v < 0) *--p = '-';
2321 } else if (is_string(l)) {
2324 *plen = strlength(l);
2326 } else { /* Hack, uses the fact that printing is needed */
2329 printslashstring(sc, strvalue(l), strlength(l));
2332 } else if (is_character(l)) {
2358 snprintf(p,STRBUFFSIZE, "#\\%s",charnames[c]);
2363 snprintf(p,STRBUFFSIZE,"#\\x%x",c);
2367 snprintf(p,STRBUFFSIZE,"#\\%c",c);
2371 } else if (is_symbol(l)) {
2373 } else if (is_proc(l)) {
2375 snprintf(p,STRBUFFSIZE,"#<%s PROCEDURE %ld>", procname(l),procnum(l));
2376 } else if (is_macro(l)) {
2378 } else if (is_closure(l)) {
2380 } else if (is_promise(l)) {
2382 } else if (is_foreign(l)) {
2384 snprintf(p,STRBUFFSIZE,"#<FOREIGN PROCEDURE %ld>", procnum(l));
2385 } else if (is_continuation(l)) {
2386 p = "#<CONTINUATION>";
2387 } else if (is_foreign_object(l)) {
2389 l->_object._foreign_object._vtable->to_string(sc, p, STRBUFFSIZE, l->_object._foreign_object._data);
2396 /* ========== Routines for Evaluation Cycle ========== */
2398 /* make closure. c is code. e is environment */
2399 static pointer mk_closure(scheme *sc, pointer c, pointer e) {
2400 pointer x = get_cell(sc, c, e);
2402 typeflag(x) = T_CLOSURE;
2408 /* make continuation. */
2409 static pointer mk_continuation(scheme *sc, pointer d) {
2410 pointer x = get_cell(sc, sc->NIL, d);
2412 typeflag(x) = T_CONTINUATION;
2417 static pointer list_star(scheme *sc, pointer d) {
2419 if(cdr(d)==sc->NIL) {
2422 p=cons(sc,car(d),cdr(d));
2424 while(cdr(cdr(p))!=sc->NIL) {
2425 d=cons(sc,car(p),cdr(p));
2426 if(cdr(cdr(p))!=sc->NIL) {
2434 /* reverse list -- produce new list */
2435 static pointer reverse(scheme *sc, pointer term, pointer list) {
2436 /* a must be checked by gc */
2437 pointer a = list, p = term;
2439 for ( ; is_pair(a); a = cdr(a)) {
2440 p = cons(sc, car(a), p);
2445 /* reverse list --- in-place */
2446 static pointer reverse_in_place(scheme *sc, pointer term, pointer list) {
2447 pointer p = list, result = term, q;
2449 while (p != sc->NIL) {
2458 /* append list -- produce new list (in reverse order) */
2459 static pointer revappend(scheme *sc, pointer a, pointer b) {
2463 while (is_pair(p)) {
2464 result = cons(sc, car(p), result);
2472 return sc->F; /* signal an error */
2475 /* equivalence of atoms */
2476 int eqv(pointer a, pointer b) {
2479 return (strvalue(a) == strvalue(b));
2482 } else if (is_number(a)) {
2484 if (num_is_integer(a) == num_is_integer(b))
2485 return num_eq(nvalue(a),nvalue(b));
2488 } else if (is_character(a)) {
2489 if (is_character(b))
2490 return charvalue(a)==charvalue(b);
2493 } else if (is_port(a)) {
2498 } else if (is_proc(a)) {
2500 return procnum(a)==procnum(b);
2508 /* true or false value macro */
2509 /* () is #t in R5RS */
2510 #define is_true(p) ((p) != sc->F)
2511 #define is_false(p) ((p) == sc->F)
2513 /* ========== Environment implementation ========== */
2515 #if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
2517 static int hash_fn(const char *key, int table_size)
2519 unsigned int hashed = 0;
2521 int bits_per_int = sizeof(unsigned int)*8;
2523 for (c = key; *c; c++) {
2524 /* letters have about 5 bits in them */
2525 hashed = (hashed<<5) | (hashed>>(bits_per_int-5));
2528 return hashed % table_size;
2532 #ifndef USE_ALIST_ENV
2535 * In this implementation, each frame of the environment may be
2536 * a hash table: a vector of alists hashed by variable name.
2537 * In practice, we use a vector only for the initial frame;
2538 * subsequent frames are too small and transient for the lookup
2539 * speed to out-weigh the cost of making a new vector.
2542 static void new_frame_in_env(scheme *sc, pointer old_env)
2546 /* The interaction-environment has about 300 variables in it. */
2547 if (old_env == sc->NIL) {
2548 new_frame = mk_vector(sc, 461);
2550 new_frame = sc->NIL;
2554 sc->envir = immutable_cons(sc, new_frame, old_env);
2556 setenvironment(sc->envir);
2559 static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
2560 pointer variable, pointer value)
2562 #define new_slot_spec_in_env_allocates 2
2564 gc_disable(sc, gc_reservations (new_slot_spec_in_env));
2565 slot = immutable_cons(sc, variable, value);
2567 if (is_vector(car(env))) {
2568 int location = hash_fn(symname(variable), ivalue_unchecked(car(env)));
2570 set_vector_elem(car(env), location,
2571 immutable_cons(sc, slot, vector_elem(car(env), location)));
2573 car(env) = immutable_cons(sc, slot, car(env));
2578 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
2583 for (x = env; x != sc->NIL; x = cdr(x)) {
2584 if (is_vector(car(x))) {
2585 location = hash_fn(symname(hdl), ivalue_unchecked(car(x)));
2586 y = vector_elem(car(x), location);
2590 for ( ; y != sc->NIL; y = cdr(y)) {
2591 if (caar(y) == hdl) {
2608 #else /* USE_ALIST_ENV */
2610 static INLINE void new_frame_in_env(scheme *sc, pointer old_env)
2612 sc->envir = immutable_cons(sc, sc->NIL, old_env);
2613 setenvironment(sc->envir);
2616 static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
2617 pointer variable, pointer value)
2619 car(env) = immutable_cons(sc, immutable_cons(sc, variable, value), car(env));
2622 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
2625 for (x = env; x != sc->NIL; x = cdr(x)) {
2626 for (y = car(x); y != sc->NIL; y = cdr(y)) {
2627 if (caar(y) == hdl) {
2644 #endif /* USE_ALIST_ENV else */
2646 static INLINE void new_slot_in_env(scheme *sc, pointer variable, pointer value)
2648 #define new_slot_in_env_allocates new_slot_spec_in_env_allocates
2649 new_slot_spec_in_env(sc, sc->envir, variable, value);
2652 static INLINE void set_slot_in_env(scheme *sc, pointer slot, pointer value)
2658 static INLINE pointer slot_value_in_env(pointer slot)
2663 /* ========== Evaluation Cycle ========== */
2666 static pointer _Error_1(scheme *sc, const char *s, pointer a) {
2667 const char *str = s;
2671 pointer hdl=sc->ERROR_HOOK;
2675 char sbuf[STRBUFFSIZE];
2678 history = history_flatten(sc);
2681 /* make sure error is not in REPL */
2682 if (sc->load_stack[sc->file_i].kind & port_file &&
2683 sc->load_stack[sc->file_i].rep.stdio.file != stdin) {
2688 if (history != sc->NIL && has_tag(car(history))
2689 && (tag = get_tag(sc, car(history)))
2690 && is_string(car(tag)) && is_integer(cdr(tag))) {
2691 fname = string_value(car(tag));
2692 ln = ivalue_unchecked(cdr(tag));
2694 fname = sc->load_stack[sc->file_i].rep.stdio.filename;
2695 ln = sc->load_stack[sc->file_i].rep.stdio.curr_line;
2698 /* should never happen */
2699 if(!fname) fname = "<unknown>";
2701 /* we started from 0 */
2703 snprintf(sbuf, STRBUFFSIZE, "%s:%i: %s", fname, ln, s);
2705 str = (const char*)sbuf;
2710 x=find_slot_in_env(sc,sc->envir,hdl,1);
2712 sc->code = cons(sc, cons(sc, sc->QUOTE,
2713 cons(sc, history, sc->NIL)),
2716 sc->code = cons(sc, cons(sc, sc->QUOTE, cons(sc, a, sc->NIL)),
2719 sc->code = cons(sc, sc->F, sc->code);
2721 sc->code = cons(sc, mk_string(sc, str), sc->code);
2722 setimmutable(car(sc->code));
2723 sc->code = cons(sc, slot_value_in_env(x), sc->code);
2724 sc->op = (int)OP_EVAL;
2730 sc->args = cons(sc, (a), sc->NIL);
2734 sc->args = cons(sc, mk_string(sc, str), sc->args);
2735 setimmutable(car(sc->args));
2736 sc->op = (int)OP_ERR0;
2739 #define Error_1(sc,s, a) return _Error_1(sc,s,a)
2740 #define Error_0(sc,s) return _Error_1(sc,s,0)
2742 /* Too small to turn into function */
2744 # define END } while (0)
2748 /* Flags. The interpreter has a flags field. When the interpreter
2749 * pushes a frame to the dump stack, it is encoded with the opcode.
2750 * Therefore, we do not use the least significant byte. */
2752 /* Masks used to encode and decode opcode and flags. */
2753 #define S_OP_MASK 0x000000ff
2754 #define S_FLAG_MASK 0xffffff00
2756 /* Set if the interpreter evaluates an expression in a tail context
2757 * (see R5RS, section 3.5). If a function, procedure, or continuation
2758 * is invoked while this flag is set, the call is recorded as tail
2759 * call in the history buffer. */
2760 #define S_FLAG_TAIL_CONTEXT 0x00000100
2763 #define s_set_flag(sc, f) \
2765 (sc)->flags |= S_FLAG_ ## f; \
2769 #define s_clear_flag(sc, f) \
2771 (sc)->flags &= ~ S_FLAG_ ## f; \
2774 /* Check if flag F is set. */
2775 #define s_get_flag(sc, f) \
2776 !!((sc)->flags & S_FLAG_ ## f)
2780 /* Bounce back to Eval_Cycle and execute A. */
2781 #define s_goto(sc,a) BEGIN \
2782 sc->op = (int)(a); \
2785 #if USE_THREADED_CODE
2787 /* Do not bounce back to Eval_Cycle but execute A by jumping directly
2788 * to it. Only applicable if A is part of the same dispatch
2790 #define s_thread_to(sc, a) \
2796 /* Define a label OP and emit a case statement for OP. For use in the
2797 * dispatch functions. The slightly peculiar goto that is never
2798 * executed avoids warnings about unused labels. */
2799 #define CASE(OP) if (0) goto OP; OP: case OP
2801 #else /* USE_THREADED_CODE */
2802 #define s_thread_to(sc, a) s_goto(sc, a)
2803 #define CASE(OP) case OP
2804 #endif /* USE_THREADED_CODE */
2806 /* Return to the previous frame on the dump stack, setting the current
2808 #define s_return(sc, a) return _s_return(sc, a, 0)
2810 /* Return to the previous frame on the dump stack, setting the current
2811 * value to A, and re-enable the garbage collector. */
2812 #define s_return_enable_gc(sc, a) return _s_return(sc, a, 1)
2814 static INLINE void dump_stack_reset(scheme *sc)
2819 static INLINE void dump_stack_initialize(scheme *sc)
2821 dump_stack_reset(sc);
2824 static void dump_stack_free(scheme *sc)
2829 static pointer _s_return(scheme *sc, pointer a, int enable_gc) {
2830 pointer dump = sc->dump;
2836 if (dump == sc->NIL)
2838 free_cons(sc, dump, &op, &dump);
2839 v = (unsigned long) ivalue_unchecked(op);
2840 sc->op = (int) (v & S_OP_MASK);
2841 sc->flags = v & S_FLAG_MASK;
2842 #ifdef USE_SMALL_INTEGERS
2843 if (v < MAX_SMALL_INTEGER) {
2844 /* This is a small integer, we must not free it. */
2846 /* Normal integer. Recover the cell. */
2849 free_cons(sc, dump, &sc->args, &dump);
2850 free_cons(sc, dump, &sc->envir, &dump);
2851 free_cons(sc, dump, &sc->code, &sc->dump);
2855 static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) {
2856 #define s_save_allocates 5
2858 unsigned long v = sc->flags | ((unsigned long) op);
2859 gc_disable(sc, gc_reservations (s_save));
2860 dump = cons(sc, sc->envir, cons(sc, (code), sc->dump));
2861 dump = cons(sc, (args), dump);
2862 sc->dump = cons(sc, mk_integer(sc, (long) v), dump);
2866 static INLINE void dump_stack_mark(scheme *sc)
2876 history_free(scheme *sc)
2878 sc->free(sc->history.m);
2879 sc->history.tailstacks = sc->NIL;
2880 sc->history.callstack = sc->NIL;
2884 history_init(scheme *sc, size_t N, size_t M)
2887 struct history *h = &sc->history;
2892 assert ((N & h->mask_N) == 0);
2896 assert ((M & h->mask_M) == 0);
2898 h->callstack = mk_vector(sc, N);
2899 if (h->callstack == sc->sink)
2902 h->tailstacks = mk_vector(sc, N);
2903 for (i = 0; i < N; i++) {
2904 pointer tailstack = mk_vector(sc, M);
2905 if (tailstack == sc->sink)
2907 set_vector_elem(h->tailstacks, i, tailstack);
2910 h->m = sc->malloc(N * sizeof *h->m);
2914 for (i = 0; i < N; i++)
2925 history_mark(scheme *sc)
2927 struct history *h = &sc->history;
2929 mark(h->tailstacks);
2932 #define add_mod(a, b, mask) (((a) + (b)) & (mask))
2933 #define sub_mod(a, b, mask) add_mod(a, (mask) + 1 - (b), mask)
2936 tailstack_clear(scheme *sc, pointer v)
2938 assert(is_vector(v));
2940 fill_vector(v, sc->NIL);
2944 callstack_pop(scheme *sc)
2946 struct history *h = &sc->history;
2950 if (h->callstack == sc->NIL)
2953 item = vector_elem(h->callstack, n);
2954 /* Clear our frame so that it can be gc'ed and we don't run into it
2955 * when walking the history. */
2956 set_vector_elem(h->callstack, n, sc->NIL);
2957 tailstack_clear(sc, vector_elem(h->tailstacks, n));
2959 /* Exit from the frame. */
2960 h->n = sub_mod(h->n, 1, h->mask_N);
2966 callstack_push(scheme *sc, pointer item)
2968 struct history *h = &sc->history;
2971 if (h->callstack == sc->NIL)
2974 /* Enter a new frame. */
2975 n = h->n = add_mod(n, 1, h->mask_N);
2977 /* Initialize tail stack. */
2978 tailstack_clear(sc, vector_elem(h->tailstacks, n));
2979 h->m[n] = h->mask_M;
2981 set_vector_elem(h->callstack, n, item);
2985 tailstack_push(scheme *sc, pointer item)
2987 struct history *h = &sc->history;
2991 if (h->callstack == sc->NIL)
2994 /* Enter a new tail frame. */
2995 m = h->m[n] = add_mod(m, 1, h->mask_M);
2996 set_vector_elem(vector_elem(h->tailstacks, n), m, item);
3000 tailstack_flatten(scheme *sc, pointer tailstack, size_t i, size_t n,
3003 struct history *h = &sc->history;
3009 if (acc == sc->sink)
3013 /* We reached the end, but we did not see a unused frame. Signal
3014 this using '... . */
3015 return cons(sc, mk_symbol(sc, "..."), acc);
3018 frame = vector_elem(tailstack, n);
3019 if (frame == sc->NIL) {
3020 /* A unused frame. We reached the end of the history. */
3025 acc = cons(sc, frame, acc);
3027 return tailstack_flatten(sc, tailstack, i - 1, sub_mod(n, 1, h->mask_M),
3032 callstack_flatten(scheme *sc, size_t i, size_t n, pointer acc)
3034 struct history *h = &sc->history;
3040 if (acc == sc->sink)
3044 /* We reached the end, but we did not see a unused frame. Signal
3045 this using '... . */
3046 return cons(sc, mk_symbol(sc, "..."), acc);
3049 frame = vector_elem(h->callstack, n);
3050 if (frame == sc->NIL) {
3051 /* A unused frame. We reached the end of the history. */
3055 /* First, emit the tail calls. */
3056 acc = tailstack_flatten(sc, vector_elem(h->tailstacks, n), h->M, h->m[n],
3060 acc = cons(sc, frame, acc);
3062 return callstack_flatten(sc, i - 1, sub_mod(n, 1, h->mask_N), acc);
3066 history_flatten(scheme *sc)
3068 struct history *h = &sc->history;
3071 if (h->callstack == sc->NIL)
3074 history = callstack_flatten(sc, h->N, h->n, sc->NIL);
3075 if (history == sc->sink)
3078 return reverse_in_place(sc, sc->NIL, history);
3084 #else /* USE_HISTORY */
3086 #define history_init(SC, A, B) (void) 0
3087 #define history_free(SC) (void) 0
3088 #define callstack_pop(SC) (void) 0
3089 #define callstack_push(SC, X) (void) 0
3090 #define tailstack_push(SC, X) (void) 0
3092 #endif /* USE_HISTORY */
3096 #define s_retbool(tf) s_return(sc,(tf) ? sc->T : sc->F)
3098 static pointer opexe_0(scheme *sc, enum scheme_opcodes op) {
3103 CASE(OP_LOAD): /* load */
3104 if(file_interactive(sc)) {
3105 fprintf(sc->outport->_object._port->rep.stdio.file,
3106 "Loading %s\n", strvalue(car(sc->args)));
3108 if (!file_push(sc,strvalue(car(sc->args)))) {
3109 Error_1(sc,"unable to open", car(sc->args));
3113 sc->args = mk_integer(sc,sc->file_i);
3114 s_thread_to(sc,OP_T0LVL);
3117 CASE(OP_T0LVL): /* top level */
3118 /* If we reached the end of file, this loop is done. */
3119 if(sc->loadport->_object._port->kind & port_saw_EOF)
3124 sc->nesting = sc->nesting_stack[0];
3130 s_return(sc,sc->value);
3135 /* If interactive, be nice to user. */
3136 if(file_interactive(sc))
3138 sc->envir = sc->global_env;
3139 dump_stack_reset(sc);
3144 /* Set up another iteration of REPL */
3146 sc->save_inport=sc->inport;
3147 sc->inport = sc->loadport;
3148 s_save(sc,OP_T0LVL, sc->NIL, sc->NIL);
3149 s_save(sc,OP_VALUEPRINT, sc->NIL, sc->NIL);
3150 s_save(sc,OP_T1LVL, sc->NIL, sc->NIL);
3151 s_thread_to(sc,OP_READ_INTERNAL);
3153 CASE(OP_T1LVL): /* top level */
3154 sc->code = sc->value;
3155 sc->inport=sc->save_inport;
3156 s_thread_to(sc,OP_EVAL);
3158 CASE(OP_READ_INTERNAL): /* internal read */
3159 sc->tok = token(sc);
3160 if(sc->tok==TOK_EOF)
3161 { s_return(sc,sc->EOF_OBJ); }
3162 s_goto(sc,OP_RDSEXPR);
3165 s_return(sc, gensym(sc));
3167 CASE(OP_VALUEPRINT): /* print evaluation result */
3168 /* OP_VALUEPRINT is always pushed, because when changing from
3169 non-interactive to interactive mode, it needs to be
3170 already on the stack */
3172 putstr(sc,"\nGives: ");
3174 if(file_interactive(sc)) {
3176 sc->args = sc->value;
3177 s_goto(sc,OP_P0LIST);
3179 s_return(sc,sc->value);
3182 CASE(OP_EVAL): /* main part of evaluation */
3185 /*s_save(sc,OP_VALUEPRINT,sc->NIL,sc->NIL);*/
3186 s_save(sc,OP_REAL_EVAL,sc->args,sc->code);
3188 putstr(sc,"\nEval: ");
3189 s_goto(sc,OP_P0LIST);
3194 if (is_symbol(sc->code)) { /* symbol */
3195 x=find_slot_in_env(sc,sc->envir,sc->code,1);
3197 s_return(sc,slot_value_in_env(x));
3199 Error_1(sc,"eval: unbound variable:", sc->code);
3201 } else if (is_pair(sc->code)) {
3202 if (is_syntax(x = car(sc->code))) { /* SYNTAX */
3203 sc->code = cdr(sc->code);
3204 s_goto(sc,syntaxnum(x));
3205 } else {/* first, eval top element and eval arguments */
3206 s_save(sc,OP_E0ARGS, sc->NIL, sc->code);
3207 /* If no macros => s_save(sc,OP_E1ARGS, sc->NIL, cdr(sc->code));*/
3208 sc->code = car(sc->code);
3209 s_clear_flag(sc, TAIL_CONTEXT);
3210 s_thread_to(sc,OP_EVAL);
3213 s_return(sc,sc->code);
3216 CASE(OP_E0ARGS): /* eval arguments */
3217 if (is_macro(sc->value)) { /* macro expansion */
3218 gc_disable(sc, 1 + gc_reservations (s_save));
3219 s_save(sc,OP_DOMACRO, sc->NIL, sc->NIL);
3220 sc->args = cons(sc,sc->code, sc->NIL);
3222 sc->code = sc->value;
3223 s_clear_flag(sc, TAIL_CONTEXT);
3224 s_thread_to(sc,OP_APPLY);
3227 sc->args = cons(sc, sc->code, sc->NIL);
3229 sc->code = cdr(sc->code);
3230 s_thread_to(sc,OP_E1ARGS);
3233 CASE(OP_E1ARGS): /* eval arguments */
3235 sc->args = cons(sc, sc->value, sc->args);
3237 if (is_pair(sc->code)) { /* continue */
3238 s_save(sc,OP_E1ARGS, sc->args, cdr(sc->code));
3239 sc->code = car(sc->code);
3241 s_clear_flag(sc, TAIL_CONTEXT);
3242 s_thread_to(sc,OP_EVAL);
3244 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3245 s_thread_to(sc,OP_APPLY_CODE);
3251 sc->tracing=ivalue(car(sc->args));
3253 s_return_enable_gc(sc, mk_integer(sc, tr));
3258 CASE(OP_CALLSTACK_POP): /* pop the call stack */
3260 s_return(sc, sc->value);
3263 CASE(OP_APPLY_CODE): /* apply 'cadr(args)' to 'cddr(args)',
3264 * record in the history as invoked from
3266 free_cons(sc, sc->args, &callsite, &sc->args);
3267 sc->code = car(sc->args);
3268 sc->args = cdr(sc->args);
3271 CASE(OP_APPLY): /* apply 'code' to 'args' */
3274 s_save(sc,OP_REAL_APPLY,sc->args,sc->code);
3276 /* sc->args=cons(sc,sc->code,sc->args);*/
3277 putstr(sc,"\nApply to: ");
3278 s_goto(sc,OP_P0LIST);
3281 CASE(OP_REAL_APPLY):
3284 if (op != OP_APPLY_CODE)
3285 callsite = sc->code;
3286 if (s_get_flag(sc, TAIL_CONTEXT)) {
3287 /* We are evaluating a tail call. */
3288 tailstack_push(sc, callsite);
3290 callstack_push(sc, callsite);
3291 s_save(sc, OP_CALLSTACK_POP, sc->NIL, sc->NIL);
3295 if (is_proc(sc->code)) {
3296 s_goto(sc,procnum(sc->code)); /* PROCEDURE */
3297 } else if (is_foreign(sc->code))
3299 /* Keep nested calls from GC'ing the arglist */
3300 push_recent_alloc(sc,sc->args,sc->NIL);
3301 x=sc->code->_object._ff(sc,sc->args);
3303 } else if (is_closure(sc->code) || is_macro(sc->code)
3304 || is_promise(sc->code)) { /* CLOSURE */
3305 /* Should not accept promise */
3306 /* make environment */
3307 new_frame_in_env(sc, closure_env(sc->code));
3308 for (x = car(closure_code(sc->code)), y = sc->args;
3309 is_pair(x); x = cdr(x), y = cdr(y)) {
3311 Error_1(sc, "not enough arguments, missing:", x);
3313 new_slot_in_env(sc, car(x), car(y));
3318 * if (y != sc->NIL) {
3319 * Error_0(sc,"too many arguments");
3322 } else if (is_symbol(x))
3323 new_slot_in_env(sc, x, y);
3325 Error_1(sc,"syntax error in closure: not a symbol:", x);
3327 sc->code = cdr(closure_code(sc->code));
3329 s_set_flag(sc, TAIL_CONTEXT);
3330 s_thread_to(sc,OP_BEGIN);
3331 } else if (is_continuation(sc->code)) { /* CONTINUATION */
3332 sc->dump = cont_dump(sc->code);
3333 s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL);
3335 Error_1(sc,"illegal function",sc->code);
3338 CASE(OP_DOMACRO): /* do macro */
3339 sc->code = sc->value;
3340 s_thread_to(sc,OP_EVAL);
3342 #if USE_COMPILE_HOOK
3343 CASE(OP_LAMBDA): /* lambda */
3344 /* If the hook is defined, apply it to sc->code, otherwise
3345 set sc->value fall through */
3347 pointer f=find_slot_in_env(sc,sc->envir,sc->COMPILE_HOOK,1);
3349 sc->value = sc->code;
3352 gc_disable(sc, 1 + gc_reservations (s_save));
3353 s_save(sc,OP_LAMBDA1,sc->args,sc->code);
3354 sc->args=cons(sc,sc->code,sc->NIL);
3356 sc->code=slot_value_in_env(f);
3357 s_thread_to(sc,OP_APPLY);
3362 CASE(OP_LAMBDA): /* lambda */
3363 sc->value = sc->code;
3369 s_return_enable_gc(sc, mk_closure(sc, sc->value, sc->envir));
3372 CASE(OP_MKCLOSURE): /* make-closure */
3374 if(car(x)==sc->LAMBDA) {
3377 if(cdr(sc->args)==sc->NIL) {
3383 s_return_enable_gc(sc, mk_closure(sc, x, y));
3385 CASE(OP_QUOTE): /* quote */
3386 s_return(sc,car(sc->code));
3388 CASE(OP_DEF0): /* define */
3389 if(is_immutable(car(sc->code)))
3390 Error_1(sc,"define: unable to alter immutable", car(sc->code));
3392 if (is_pair(car(sc->code))) {
3395 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
3399 sc->code = cadr(sc->code);
3401 if (!is_symbol(x)) {
3402 Error_0(sc,"variable is not a symbol");
3404 s_save(sc,OP_DEF1, sc->NIL, x);
3405 s_thread_to(sc,OP_EVAL);
3407 CASE(OP_DEF1): /* define */
3408 x=find_slot_in_env(sc,sc->envir,sc->code,0);
3410 set_slot_in_env(sc, x, sc->value);
3412 new_slot_in_env(sc, sc->code, sc->value);
3414 s_return(sc,sc->code);
3417 CASE(OP_DEFP): /* defined? */
3419 if(cdr(sc->args)!=sc->NIL) {
3422 s_retbool(find_slot_in_env(sc,x,car(sc->args),1)!=sc->NIL);
3424 CASE(OP_SET0): /* set! */
3425 if(is_immutable(car(sc->code)))
3426 Error_1(sc,"set!: unable to alter immutable variable",car(sc->code));
3427 s_save(sc,OP_SET1, sc->NIL, car(sc->code));
3428 sc->code = cadr(sc->code);
3429 s_thread_to(sc,OP_EVAL);
3431 CASE(OP_SET1): /* set! */
3432 y=find_slot_in_env(sc,sc->envir,sc->code,1);
3434 set_slot_in_env(sc, y, sc->value);
3435 s_return(sc,sc->value);
3437 Error_1(sc,"set!: unbound variable:", sc->code);
3441 CASE(OP_BEGIN): /* begin */
3445 if (!is_pair(sc->code)) {
3446 s_return(sc,sc->code);
3449 last = cdr(sc->code) == sc->NIL;
3451 s_save(sc,OP_BEGIN, sc->NIL, cdr(sc->code));
3453 sc->code = car(sc->code);
3455 /* This is not the end of the list. This is not a tail
3457 s_clear_flag(sc, TAIL_CONTEXT);
3458 s_thread_to(sc,OP_EVAL);
3461 CASE(OP_IF0): /* if */
3462 s_save(sc,OP_IF1, sc->NIL, cdr(sc->code));
3463 sc->code = car(sc->code);
3464 s_clear_flag(sc, TAIL_CONTEXT);
3465 s_thread_to(sc,OP_EVAL);
3467 CASE(OP_IF1): /* if */
3468 if (is_true(sc->value))
3469 sc->code = car(sc->code);
3471 sc->code = cadr(sc->code); /* (if #f 1) ==> () because
3472 * car(sc->NIL) = sc->NIL */
3473 s_thread_to(sc,OP_EVAL);
3475 CASE(OP_LET0): /* let */
3477 sc->value = sc->code;
3478 sc->code = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code);
3479 s_thread_to(sc,OP_LET1);
3481 CASE(OP_LET1): /* let (calculate parameters) */
3482 gc_disable(sc, 1 + (is_pair(sc->code) ? gc_reservations (s_save) : 0));
3483 sc->args = cons(sc, sc->value, sc->args);
3484 if (is_pair(sc->code)) { /* continue */
3485 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
3487 Error_1(sc, "Bad syntax of binding spec in let :",
3490 s_save(sc,OP_LET1, sc->args, cdr(sc->code));
3492 sc->code = cadar(sc->code);
3494 s_clear_flag(sc, TAIL_CONTEXT);
3495 s_thread_to(sc,OP_EVAL);
3498 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3499 sc->code = car(sc->args);
3500 sc->args = cdr(sc->args);
3501 s_thread_to(sc,OP_LET2);
3504 CASE(OP_LET2): /* let */
3505 new_frame_in_env(sc, sc->envir);
3506 for (x = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code), y = sc->args;
3507 y != sc->NIL; x = cdr(x), y = cdr(y)) {
3508 new_slot_in_env(sc, caar(x), car(y));
3510 if (is_symbol(car(sc->code))) { /* named let */
3511 for (x = cadr(sc->code), sc->args = sc->NIL; x != sc->NIL; x = cdr(x)) {
3513 Error_1(sc, "Bad syntax of binding in let :", x);
3514 if (!is_list(sc, car(x)))
3515 Error_1(sc, "Bad syntax of binding in let :", car(x));
3517 sc->args = cons(sc, caar(x), sc->args);
3520 gc_disable(sc, 2 + gc_reservations (new_slot_in_env));
3521 x = mk_closure(sc, cons(sc, reverse_in_place(sc, sc->NIL, sc->args), cddr(sc->code)), sc->envir);
3522 new_slot_in_env(sc, car(sc->code), x);
3524 sc->code = cddr(sc->code);
3527 sc->code = cdr(sc->code);
3530 s_thread_to(sc,OP_BEGIN);
3532 CASE(OP_LET0AST): /* let* */
3533 if (car(sc->code) == sc->NIL) {
3534 new_frame_in_env(sc, sc->envir);
3535 sc->code = cdr(sc->code);
3536 s_thread_to(sc,OP_BEGIN);
3538 if(!is_pair(car(sc->code)) || !is_pair(caar(sc->code)) || !is_pair(cdaar(sc->code))) {
3539 Error_1(sc,"Bad syntax of binding spec in let* :",car(sc->code));
3541 s_save(sc,OP_LET1AST, cdr(sc->code), car(sc->code));
3542 sc->code = cadaar(sc->code);
3543 s_clear_flag(sc, TAIL_CONTEXT);
3544 s_thread_to(sc,OP_EVAL);
3546 CASE(OP_LET1AST): /* let* (make new frame) */
3547 new_frame_in_env(sc, sc->envir);
3548 s_thread_to(sc,OP_LET2AST);
3550 CASE(OP_LET2AST): /* let* (calculate parameters) */
3551 new_slot_in_env(sc, caar(sc->code), sc->value);
3552 sc->code = cdr(sc->code);
3553 if (is_pair(sc->code)) { /* continue */
3554 s_save(sc,OP_LET2AST, sc->args, sc->code);
3555 sc->code = cadar(sc->code);
3557 s_clear_flag(sc, TAIL_CONTEXT);
3558 s_thread_to(sc,OP_EVAL);
3560 sc->code = sc->args;
3562 s_thread_to(sc,OP_BEGIN);
3565 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3566 Error_0(sc,sc->strbuff);
3571 static pointer opexe_1(scheme *sc, enum scheme_opcodes op) {
3575 CASE(OP_LET0REC): /* letrec */
3576 new_frame_in_env(sc, sc->envir);
3578 sc->value = sc->code;
3579 sc->code = car(sc->code);
3580 s_thread_to(sc,OP_LET1REC);
3582 CASE(OP_LET1REC): /* letrec (calculate parameters) */
3584 sc->args = cons(sc, sc->value, sc->args);
3586 if (is_pair(sc->code)) { /* continue */
3587 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
3588 Error_1(sc, "Bad syntax of binding spec in letrec :",
3591 s_save(sc,OP_LET1REC, sc->args, cdr(sc->code));
3592 sc->code = cadar(sc->code);
3594 s_clear_flag(sc, TAIL_CONTEXT);
3597 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
3598 sc->code = car(sc->args);
3599 sc->args = cdr(sc->args);
3600 s_thread_to(sc,OP_LET2REC);
3603 CASE(OP_LET2REC): /* letrec */
3604 for (x = car(sc->code), y = sc->args; y != sc->NIL; x = cdr(x), y = cdr(y)) {
3605 new_slot_in_env(sc, caar(x), car(y));
3607 sc->code = cdr(sc->code);
3609 s_goto(sc,OP_BEGIN);
3611 CASE(OP_COND0): /* cond */
3612 if (!is_pair(sc->code)) {
3613 Error_0(sc,"syntax error in cond");
3615 s_save(sc,OP_COND1, sc->NIL, sc->code);
3616 sc->code = caar(sc->code);
3617 s_clear_flag(sc, TAIL_CONTEXT);
3620 CASE(OP_COND1): /* cond */
3621 if (is_true(sc->value)) {
3622 if ((sc->code = cdar(sc->code)) == sc->NIL) {
3623 s_return(sc,sc->value);
3625 if(!sc->code || car(sc->code)==sc->FEED_TO) {
3626 if(!is_pair(cdr(sc->code))) {
3627 Error_0(sc,"syntax error in cond");
3630 x=cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL));
3631 sc->code=cons(sc,cadr(sc->code),cons(sc,x,sc->NIL));
3635 s_goto(sc,OP_BEGIN);
3637 if ((sc->code = cdr(sc->code)) == sc->NIL) {
3638 s_return(sc,sc->NIL);
3640 s_save(sc,OP_COND1, sc->NIL, sc->code);
3641 sc->code = caar(sc->code);
3642 s_clear_flag(sc, TAIL_CONTEXT);
3647 CASE(OP_DELAY): /* delay */
3649 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
3650 typeflag(x)=T_PROMISE;
3651 s_return_enable_gc(sc,x);
3653 CASE(OP_AND0): /* and */
3654 if (sc->code == sc->NIL) {
3657 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
3658 if (cdr(sc->code) != sc->NIL)
3659 s_clear_flag(sc, TAIL_CONTEXT);
3660 sc->code = car(sc->code);
3663 CASE(OP_AND1): /* and */
3664 if (is_false(sc->value)) {
3665 s_return(sc,sc->value);
3666 } else if (sc->code == sc->NIL) {
3667 s_return(sc,sc->value);
3669 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
3670 if (cdr(sc->code) != sc->NIL)
3671 s_clear_flag(sc, TAIL_CONTEXT);
3672 sc->code = car(sc->code);
3676 CASE(OP_OR0): /* or */
3677 if (sc->code == sc->NIL) {
3680 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
3681 if (cdr(sc->code) != sc->NIL)
3682 s_clear_flag(sc, TAIL_CONTEXT);
3683 sc->code = car(sc->code);
3686 CASE(OP_OR1): /* or */
3687 if (is_true(sc->value)) {
3688 s_return(sc,sc->value);
3689 } else if (sc->code == sc->NIL) {
3690 s_return(sc,sc->value);
3692 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
3693 if (cdr(sc->code) != sc->NIL)
3694 s_clear_flag(sc, TAIL_CONTEXT);
3695 sc->code = car(sc->code);
3699 CASE(OP_C0STREAM): /* cons-stream */
3700 s_save(sc,OP_C1STREAM, sc->NIL, cdr(sc->code));
3701 sc->code = car(sc->code);
3704 CASE(OP_C1STREAM): /* cons-stream */
3705 sc->args = sc->value; /* save sc->value to register sc->args for gc */
3707 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
3708 typeflag(x)=T_PROMISE;
3709 s_return_enable_gc(sc, cons(sc, sc->args, x));
3711 CASE(OP_MACRO0): /* macro */
3712 if (is_pair(car(sc->code))) {
3715 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
3719 sc->code = cadr(sc->code);
3721 if (!is_symbol(x)) {
3722 Error_0(sc,"variable is not a symbol");
3724 s_save(sc,OP_MACRO1, sc->NIL, x);
3727 CASE(OP_MACRO1): /* macro */
3728 typeflag(sc->value) = T_MACRO;
3729 x = find_slot_in_env(sc, sc->envir, sc->code, 0);
3731 set_slot_in_env(sc, x, sc->value);
3733 new_slot_in_env(sc, sc->code, sc->value);
3735 s_return(sc,sc->code);
3737 CASE(OP_CASE0): /* case */
3738 s_save(sc,OP_CASE1, sc->NIL, cdr(sc->code));
3739 sc->code = car(sc->code);
3740 s_clear_flag(sc, TAIL_CONTEXT);
3743 CASE(OP_CASE1): /* case */
3744 for (x = sc->code; x != sc->NIL; x = cdr(x)) {
3745 if (!is_pair(y = caar(x))) {
3748 for ( ; y != sc->NIL; y = cdr(y)) {
3749 if (eqv(car(y), sc->value)) {
3758 if (is_pair(caar(x))) {
3760 s_goto(sc,OP_BEGIN);
3762 s_save(sc,OP_CASE2, sc->NIL, cdar(x));
3767 s_return(sc,sc->NIL);
3770 CASE(OP_CASE2): /* case */
3771 if (is_true(sc->value)) {
3772 s_goto(sc,OP_BEGIN);
3774 s_return(sc,sc->NIL);
3777 CASE(OP_PAPPLY): /* apply */
3778 sc->code = car(sc->args);
3779 sc->args = list_star(sc,cdr(sc->args));
3780 /*sc->args = cadr(sc->args);*/
3781 s_goto(sc,OP_APPLY);
3783 CASE(OP_PEVAL): /* eval */
3784 if(cdr(sc->args)!=sc->NIL) {
3785 sc->envir=cadr(sc->args);
3787 sc->code = car(sc->args);
3790 CASE(OP_CONTINUATION): /* call-with-current-continuation */
3791 sc->code = car(sc->args);
3793 sc->args = cons(sc, mk_continuation(sc, sc->dump), sc->NIL);
3795 s_goto(sc,OP_APPLY);
3798 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3799 Error_0(sc,sc->strbuff);
3806 get_property(scheme *sc, pointer obj, pointer key)
3810 assert (is_symbol(obj));
3811 assert (is_symbol(key));
3813 for (x = symprop(obj); x != sc->NIL; x = cdr(x)) {
3825 set_property(scheme *sc, pointer obj, pointer key, pointer value)
3827 #define set_property_allocates 2
3830 assert (is_symbol(obj));
3831 assert (is_symbol(key));
3833 for (x = symprop(obj); x != sc->NIL; x = cdr(x)) {
3841 gc_disable(sc, gc_reservations(set_property));
3842 symprop(obj) = cons(sc, cons(sc, key, value), symprop(obj));
3850 static pointer opexe_2(scheme *sc, enum scheme_opcodes op) {
3859 CASE(OP_INEX2EX): /* inexact->exact */
3861 if(num_is_integer(x)) {
3863 } else if(modf(rvalue_unchecked(x),&dd)==0.0) {
3864 s_return(sc,mk_integer(sc,ivalue(x)));
3866 Error_1(sc,"inexact->exact: not integral:",x);
3871 s_return(sc, mk_real(sc, exp(rvalue(x))));
3875 s_return(sc, mk_real(sc, log(rvalue(x))));
3879 s_return(sc, mk_real(sc, sin(rvalue(x))));
3883 s_return(sc, mk_real(sc, cos(rvalue(x))));
3887 s_return(sc, mk_real(sc, tan(rvalue(x))));
3891 s_return(sc, mk_real(sc, asin(rvalue(x))));
3895 s_return(sc, mk_real(sc, acos(rvalue(x))));
3899 if(cdr(sc->args)==sc->NIL) {
3900 s_return(sc, mk_real(sc, atan(rvalue(x))));
3902 pointer y=cadr(sc->args);
3903 s_return(sc, mk_real(sc, atan2(rvalue(x),rvalue(y))));
3908 s_return(sc, mk_real(sc, sqrt(rvalue(x))));
3913 pointer y=cadr(sc->args);
3915 if (num_is_integer(x) && num_is_integer(y))
3917 /* This 'if' is an R5RS compatibility fix. */
3918 /* NOTE: Remove this 'if' fix for R6RS. */
3919 if (rvalue(x) == 0 && rvalue(y) < 0) {
3922 result = pow(rvalue(x),rvalue(y));
3924 /* Before returning integer result make sure we can. */
3925 /* If the test fails, result is too big for integer. */
3928 long result_as_long = (long)result;
3929 if (result != (double)result_as_long)
3933 s_return(sc, mk_real(sc, result));
3935 s_return(sc, mk_integer(sc, result));
3941 s_return(sc, mk_real(sc, floor(rvalue(x))));
3945 s_return(sc, mk_real(sc, ceil(rvalue(x))));
3947 CASE(OP_TRUNCATE ): {
3948 double rvalue_of_x ;
3950 rvalue_of_x = rvalue(x) ;
3951 if (rvalue_of_x > 0) {
3952 s_return(sc, mk_real(sc, floor(rvalue_of_x)));
3954 s_return(sc, mk_real(sc, ceil(rvalue_of_x)));
3960 if (num_is_integer(x))
3962 s_return(sc, mk_real(sc, round_per_R5RS(rvalue(x))));
3965 CASE(OP_ADD): /* + */
3967 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
3968 v=num_add(v,nvalue(car(x)));
3971 s_return_enable_gc(sc, mk_number(sc, v));
3973 CASE(OP_MUL): /* * */
3975 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
3976 v=num_mul(v,nvalue(car(x)));
3979 s_return_enable_gc(sc, mk_number(sc, v));
3981 CASE(OP_SUB): /* - */
3982 if(cdr(sc->args)==sc->NIL) {
3987 v = nvalue(car(sc->args));
3989 for (; x != sc->NIL; x = cdr(x)) {
3990 v=num_sub(v,nvalue(car(x)));
3993 s_return_enable_gc(sc, mk_number(sc, v));
3995 CASE(OP_DIV): /* / */
3996 if(cdr(sc->args)==sc->NIL) {
4001 v = nvalue(car(sc->args));
4003 for (; x != sc->NIL; x = cdr(x)) {
4004 if (!is_zero_double(rvalue(car(x))))
4005 v=num_div(v,nvalue(car(x)));
4007 Error_0(sc,"/: division by zero");
4011 s_return_enable_gc(sc, mk_number(sc, v));
4013 CASE(OP_INTDIV): /* quotient */
4014 if(cdr(sc->args)==sc->NIL) {
4019 v = nvalue(car(sc->args));
4021 for (; x != sc->NIL; x = cdr(x)) {
4022 if (ivalue(car(x)) != 0)
4023 v=num_intdiv(v,nvalue(car(x)));
4025 Error_0(sc,"quotient: division by zero");
4029 s_return_enable_gc(sc, mk_number(sc, v));
4031 CASE(OP_REM): /* remainder */
4032 v = nvalue(car(sc->args));
4033 if (ivalue(cadr(sc->args)) != 0)
4034 v=num_rem(v,nvalue(cadr(sc->args)));
4036 Error_0(sc,"remainder: division by zero");
4039 s_return_enable_gc(sc, mk_number(sc, v));
4041 CASE(OP_MOD): /* modulo */
4042 v = nvalue(car(sc->args));
4043 if (ivalue(cadr(sc->args)) != 0)
4044 v=num_mod(v,nvalue(cadr(sc->args)));
4046 Error_0(sc,"modulo: division by zero");
4049 s_return_enable_gc(sc, mk_number(sc, v));
4051 CASE(OP_CAR): /* car */
4052 s_return(sc,caar(sc->args));
4054 CASE(OP_CDR): /* cdr */
4055 s_return(sc,cdar(sc->args));
4057 CASE(OP_CONS): /* cons */
4058 cdr(sc->args) = cadr(sc->args);
4059 s_return(sc,sc->args);
4061 CASE(OP_SETCAR): /* set-car! */
4062 if(!is_immutable(car(sc->args))) {
4063 caar(sc->args) = cadr(sc->args);
4064 s_return(sc,car(sc->args));
4066 Error_0(sc,"set-car!: unable to alter immutable pair");
4069 CASE(OP_SETCDR): /* set-cdr! */
4070 if(!is_immutable(car(sc->args))) {
4071 cdar(sc->args) = cadr(sc->args);
4072 s_return(sc,car(sc->args));
4074 Error_0(sc,"set-cdr!: unable to alter immutable pair");
4077 CASE(OP_CHAR2INT): { /* char->integer */
4079 c=(char)ivalue(car(sc->args));
4081 s_return_enable_gc(sc, mk_integer(sc, (unsigned char) c));
4084 CASE(OP_INT2CHAR): { /* integer->char */
4086 c=(unsigned char)ivalue(car(sc->args));
4088 s_return_enable_gc(sc, mk_character(sc, (char) c));
4091 CASE(OP_CHARUPCASE): {
4093 c=(unsigned char)ivalue(car(sc->args));
4096 s_return_enable_gc(sc, mk_character(sc, (char) c));
4099 CASE(OP_CHARDNCASE): {
4101 c=(unsigned char)ivalue(car(sc->args));
4104 s_return_enable_gc(sc, mk_character(sc, (char) c));
4107 CASE(OP_STR2SYM): /* string->symbol */
4108 gc_disable(sc, gc_reservations (mk_symbol));
4109 s_return_enable_gc(sc, mk_symbol(sc, strvalue(car(sc->args))));
4111 CASE(OP_STR2ATOM): /* string->atom */ {
4112 char *s=strvalue(car(sc->args));
4114 if(cdr(sc->args)!=sc->NIL) {
4115 /* we know cadr(sc->args) is a natural number */
4116 /* see if it is 2, 8, 10, or 16, or error */
4117 pf = ivalue_unchecked(cadr(sc->args));
4118 if(pf == 16 || pf == 10 || pf == 8 || pf == 2) {
4126 Error_1(sc, "string->atom: bad base:", cadr(sc->args));
4127 } else if(*s=='#') /* no use of base! */ {
4128 s_return(sc, mk_sharp_const(sc, s+1));
4130 if (pf == 0 || pf == 10) {
4131 s_return(sc, mk_atom(sc, s));
4135 long iv = strtol(s,&ep,(int )pf);
4137 s_return(sc, mk_integer(sc, iv));
4140 s_return(sc, sc->F);
4146 CASE(OP_SYM2STR): /* symbol->string */
4148 x=mk_string(sc,symname(car(sc->args)));
4150 s_return_enable_gc(sc, x);
4152 CASE(OP_ATOM2STR): /* atom->string */ {
4155 if(cdr(sc->args)!=sc->NIL) {
4156 /* we know cadr(sc->args) is a natural number */
4157 /* see if it is 2, 8, 10, or 16, or error */
4158 pf = ivalue_unchecked(cadr(sc->args));
4159 if(is_number(x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2)) {
4167 Error_1(sc, "atom->string: bad base:", cadr(sc->args));
4168 } else if(is_number(x) || is_character(x) || is_string(x) || is_symbol(x)) {
4171 atom2str(sc,x,(int )pf,&p,&len);
4173 s_return_enable_gc(sc, mk_counted_string(sc, p, len));
4175 Error_1(sc, "atom->string: not an atom:", x);
4179 CASE(OP_MKSTRING): { /* make-string */
4183 len=ivalue(car(sc->args));
4185 if(cdr(sc->args)!=sc->NIL) {
4186 fill=charvalue(cadr(sc->args));
4189 s_return_enable_gc(sc, mk_empty_string(sc, len, (char) fill));
4192 CASE(OP_STRLEN): /* string-length */
4194 s_return_enable_gc(sc, mk_integer(sc, strlength(car(sc->args))));
4196 CASE(OP_STRREF): { /* string-ref */
4200 str=strvalue(car(sc->args));
4202 index=ivalue(cadr(sc->args));
4204 if(index>=strlength(car(sc->args))) {
4205 Error_1(sc,"string-ref: out of bounds:",cadr(sc->args));
4209 s_return_enable_gc(sc,
4210 mk_character(sc, ((unsigned char*) str)[index]));
4213 CASE(OP_STRSET): { /* string-set! */
4218 if(is_immutable(car(sc->args))) {
4219 Error_1(sc,"string-set!: unable to alter immutable string:",car(sc->args));
4221 str=strvalue(car(sc->args));
4223 index=ivalue(cadr(sc->args));
4224 if(index>=strlength(car(sc->args))) {
4225 Error_1(sc,"string-set!: out of bounds:",cadr(sc->args));
4228 c=charvalue(caddr(sc->args));
4231 s_return(sc,car(sc->args));
4234 CASE(OP_STRAPPEND): { /* string-append */
4235 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4240 /* compute needed length for new string */
4241 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
4242 len += strlength(car(x));
4245 newstr = mk_empty_string(sc, len, ' ');
4246 /* store the contents of the argument strings into the new string */
4247 for (pos = strvalue(newstr), x = sc->args; x != sc->NIL;
4248 pos += strlength(car(x)), x = cdr(x)) {
4249 memcpy(pos, strvalue(car(x)), strlength(car(x)));
4251 s_return_enable_gc(sc, newstr);
4254 CASE(OP_SUBSTR): { /* substring */
4260 str=strvalue(car(sc->args));
4262 index0=ivalue(cadr(sc->args));
4264 if(index0>strlength(car(sc->args))) {
4265 Error_1(sc,"substring: start out of bounds:",cadr(sc->args));
4268 if(cddr(sc->args)!=sc->NIL) {
4269 index1=ivalue(caddr(sc->args));
4270 if(index1>strlength(car(sc->args)) || index1<index0) {
4271 Error_1(sc,"substring: end out of bounds:",caddr(sc->args));
4274 index1=strlength(car(sc->args));
4279 x=mk_empty_string(sc,len,' ');
4280 memcpy(strvalue(x),str+index0,len);
4283 s_return_enable_gc(sc, x);
4286 CASE(OP_VECTOR): { /* vector */
4289 int len=list_length(sc,sc->args);
4291 Error_1(sc,"vector: not a proper list:",sc->args);
4293 vec=mk_vector(sc,len);
4294 if(sc->no_memory) { s_return(sc, sc->sink); }
4295 for (x = sc->args, i = 0; is_pair(x); x = cdr(x), i++) {
4296 set_vector_elem(vec,i,car(x));
4301 CASE(OP_MKVECTOR): { /* make-vector */
4302 pointer fill=sc->NIL;
4306 len=ivalue(car(sc->args));
4308 if(cdr(sc->args)!=sc->NIL) {
4309 fill=cadr(sc->args);
4311 vec=mk_vector(sc,len);
4312 if(sc->no_memory) { s_return(sc, sc->sink); }
4314 fill_vector(vec,fill);
4319 CASE(OP_VECLEN): /* vector-length */
4321 s_return_enable_gc(sc, mk_integer(sc, ivalue(car(sc->args))));
4323 CASE(OP_VECREF): { /* vector-ref */
4326 index=ivalue(cadr(sc->args));
4328 if(index>=ivalue(car(sc->args))) {
4329 Error_1(sc,"vector-ref: out of bounds:",cadr(sc->args));
4332 s_return(sc,vector_elem(car(sc->args),index));
4335 CASE(OP_VECSET): { /* vector-set! */
4338 if(is_immutable(car(sc->args))) {
4339 Error_1(sc,"vector-set!: unable to alter immutable vector:",car(sc->args));
4342 index=ivalue(cadr(sc->args));
4343 if(index>=ivalue(car(sc->args))) {
4344 Error_1(sc,"vector-set!: out of bounds:",cadr(sc->args));
4347 set_vector_elem(car(sc->args),index,caddr(sc->args));
4348 s_return(sc,car(sc->args));
4352 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
4353 Error_0(sc,sc->strbuff);
4358 static int is_list(scheme *sc, pointer a)
4359 { return list_length(sc,a) >= 0; }
4365 dotted list: -2 minus length before dot
4367 int list_length(scheme *sc, pointer a) {
4374 if (fast == sc->NIL)
4380 if (fast == sc->NIL)
4387 /* Safe because we would have already returned if `fast'
4388 encountered a non-pair. */
4392 /* the fast pointer has looped back around and caught up
4393 with the slow pointer, hence the structure is circular,
4394 not of finite length, and therefore not a list */
4400 static pointer opexe_3(scheme *sc, enum scheme_opcodes op) {
4403 int (*comp_func)(num,num)=0;
4406 CASE(OP_NOT): /* not */
4407 s_retbool(is_false(car(sc->args)));
4408 CASE(OP_BOOLP): /* boolean? */
4409 s_retbool(car(sc->args) == sc->F || car(sc->args) == sc->T);
4410 CASE(OP_EOFOBJP): /* boolean? */
4411 s_retbool(car(sc->args) == sc->EOF_OBJ);
4412 CASE(OP_NULLP): /* null? */
4413 s_retbool(car(sc->args) == sc->NIL);
4414 CASE(OP_NUMEQ): /* = */
4415 CASE(OP_LESS): /* < */
4416 CASE(OP_GRE): /* > */
4417 CASE(OP_LEQ): /* <= */
4418 CASE(OP_GEQ): /* >= */
4420 case OP_NUMEQ: comp_func=num_eq; break;
4421 case OP_LESS: comp_func=num_lt; break;
4422 case OP_GRE: comp_func=num_gt; break;
4423 case OP_LEQ: comp_func=num_le; break;
4424 case OP_GEQ: comp_func=num_ge; break;
4425 default: assert (! "reached");
4431 for (; x != sc->NIL; x = cdr(x)) {
4432 if(!comp_func(v,nvalue(car(x)))) {
4438 CASE(OP_SYMBOLP): /* symbol? */
4439 s_retbool(is_symbol(car(sc->args)));
4440 CASE(OP_NUMBERP): /* number? */
4441 s_retbool(is_number(car(sc->args)));
4442 CASE(OP_STRINGP): /* string? */
4443 s_retbool(is_string(car(sc->args)));
4444 CASE(OP_INTEGERP): /* integer? */
4445 s_retbool(is_integer(car(sc->args)));
4446 CASE(OP_REALP): /* real? */
4447 s_retbool(is_number(car(sc->args))); /* All numbers are real */
4448 CASE(OP_CHARP): /* char? */
4449 s_retbool(is_character(car(sc->args)));
4450 #if USE_CHAR_CLASSIFIERS
4451 CASE(OP_CHARAP): /* char-alphabetic? */
4452 s_retbool(Cisalpha(ivalue(car(sc->args))));
4453 CASE(OP_CHARNP): /* char-numeric? */
4454 s_retbool(Cisdigit(ivalue(car(sc->args))));
4455 CASE(OP_CHARWP): /* char-whitespace? */
4456 s_retbool(Cisspace(ivalue(car(sc->args))));
4457 CASE(OP_CHARUP): /* char-upper-case? */
4458 s_retbool(Cisupper(ivalue(car(sc->args))));
4459 CASE(OP_CHARLP): /* char-lower-case? */
4460 s_retbool(Cislower(ivalue(car(sc->args))));
4462 CASE(OP_PORTP): /* port? */
4463 s_retbool(is_port(car(sc->args)));
4464 CASE(OP_INPORTP): /* input-port? */
4465 s_retbool(is_inport(car(sc->args)));
4466 CASE(OP_OUTPORTP): /* output-port? */
4467 s_retbool(is_outport(car(sc->args)));
4468 CASE(OP_PROCP): /* procedure? */
4470 * continuation should be procedure by the example
4471 * (call-with-current-continuation procedure?) ==> #t
4472 * in R^3 report sec. 6.9
4474 s_retbool(is_proc(car(sc->args)) || is_closure(car(sc->args))
4475 || is_continuation(car(sc->args)) || is_foreign(car(sc->args)));
4476 CASE(OP_PAIRP): /* pair? */
4477 s_retbool(is_pair(car(sc->args)));
4478 CASE(OP_LISTP): /* list? */
4479 s_retbool(list_length(sc,car(sc->args)) >= 0);
4481 CASE(OP_ENVP): /* environment? */
4482 s_retbool(is_environment(car(sc->args)));
4483 CASE(OP_VECTORP): /* vector? */
4484 s_retbool(is_vector(car(sc->args)));
4485 CASE(OP_EQ): /* eq? */
4486 s_retbool(car(sc->args) == cadr(sc->args));
4487 CASE(OP_EQV): /* eqv? */
4488 s_retbool(eqv(car(sc->args), cadr(sc->args)));
4490 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
4491 Error_0(sc,sc->strbuff);
4496 static pointer opexe_4(scheme *sc, enum scheme_opcodes op) {
4500 CASE(OP_FORCE): /* force */
4501 sc->code = car(sc->args);
4502 if (is_promise(sc->code)) {
4503 /* Should change type to closure here */
4504 s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code);
4506 s_goto(sc,OP_APPLY);
4508 s_return(sc,sc->code);
4511 CASE(OP_SAVE_FORCED): /* Save forced value replacing promise */
4512 memcpy(sc->code,sc->value,sizeof(struct cell));
4513 s_return(sc,sc->value);
4515 CASE(OP_WRITE): /* write */
4516 CASE(OP_DISPLAY): /* display */
4517 CASE(OP_WRITE_CHAR): /* write-char */
4518 if(is_pair(cdr(sc->args))) {
4519 if(cadr(sc->args)!=sc->outport) {
4520 x=cons(sc,sc->outport,sc->NIL);
4521 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
4522 sc->outport=cadr(sc->args);
4525 sc->args = car(sc->args);
4531 s_goto(sc,OP_P0LIST);
4533 CASE(OP_NEWLINE): /* newline */
4534 if(is_pair(sc->args)) {
4535 if(car(sc->args)!=sc->outport) {
4536 x=cons(sc,sc->outport,sc->NIL);
4537 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
4538 sc->outport=car(sc->args);
4544 CASE(OP_ERR0): /* error */
4546 if (!is_string(car(sc->args))) {
4547 sc->args=cons(sc,mk_string(sc," -- "),sc->args);
4548 setimmutable(car(sc->args));
4550 putstr(sc, "Error: ");
4551 putstr(sc, strvalue(car(sc->args)));
4552 sc->args = cdr(sc->args);
4553 s_thread_to(sc,OP_ERR1);
4555 CASE(OP_ERR1): /* error */
4557 if (sc->args != sc->NIL) {
4558 s_save(sc,OP_ERR1, cdr(sc->args), sc->NIL);
4559 sc->args = car(sc->args);
4561 s_goto(sc,OP_P0LIST);
4564 if(sc->interactive_repl) {
4565 s_goto(sc,OP_T0LVL);
4571 CASE(OP_REVERSE): /* reverse */
4572 s_return(sc,reverse(sc, sc->NIL, car(sc->args)));
4574 CASE(OP_LIST_STAR): /* list* */
4575 s_return(sc,list_star(sc,sc->args));
4577 CASE(OP_APPEND): /* append */
4584 /* cdr() in the while condition is not a typo. If car() */
4585 /* is used (append '() 'a) will return the wrong result.*/
4586 while (cdr(y) != sc->NIL) {
4587 x = revappend(sc, x, car(y));
4590 Error_0(sc, "non-list argument to append");
4594 s_return(sc, reverse_in_place(sc, car(y), x));
4597 CASE(OP_SET_SYMBOL_PROPERTY): /* set-symbol-property! */
4598 gc_disable(sc, gc_reservations(set_property));
4599 s_return_enable_gc(sc,
4600 set_property(sc, car(sc->args),
4601 cadr(sc->args), caddr(sc->args)));
4603 CASE(OP_SYMBOL_PROPERTY): /* symbol-property */
4604 s_return(sc, get_property(sc, car(sc->args), cadr(sc->args)));
4605 #endif /* USE_PLIST */
4608 CASE(OP_TAG_VALUE): { /* not exposed */
4609 /* This tags sc->value with car(sc->args). Useful to tag
4610 * results of opcode evaluations. */
4612 free_cons(sc, sc->args, &a, &b);
4613 free_cons(sc, b, &b, &c);
4614 assert(c == sc->NIL);
4615 s_return(sc, mk_tagged_value(sc, sc->value, a, b));
4618 CASE(OP_MK_TAGGED): /* make-tagged-value */
4619 if (is_vector(car(sc->args)))
4620 Error_0(sc, "cannot tag vector");
4621 s_return(sc, mk_tagged_value(sc, car(sc->args),
4622 car(cadr(sc->args)),
4623 cdr(cadr(sc->args))));
4625 CASE(OP_GET_TAG): /* get-tag */
4626 s_return(sc, get_tag(sc, car(sc->args)));
4627 #endif /* USE_TAGS */
4629 CASE(OP_QUIT): /* quit */
4630 if(is_pair(sc->args)) {
4631 sc->retcode=ivalue(car(sc->args));
4635 CASE(OP_GC): /* gc */
4636 gc(sc, sc->NIL, sc->NIL);
4639 CASE(OP_GCVERB): /* gc-verbose */
4640 { int was = sc->gc_verbose;
4642 sc->gc_verbose = (car(sc->args) != sc->F);
4646 CASE(OP_NEWSEGMENT): /* new-segment */
4647 if (!is_pair(sc->args) || !is_number(car(sc->args))) {
4648 Error_0(sc,"new-segment: argument must be a number");
4650 alloc_cellseg(sc, (int) ivalue(car(sc->args)));
4653 CASE(OP_OBLIST): /* oblist */
4654 s_return(sc, oblist_all_symbols(sc));
4656 CASE(OP_CURR_INPORT): /* current-input-port */
4657 s_return(sc,sc->inport);
4659 CASE(OP_CURR_OUTPORT): /* current-output-port */
4660 s_return(sc,sc->outport);
4662 CASE(OP_OPEN_INFILE): /* open-input-file */
4663 CASE(OP_OPEN_OUTFILE): /* open-output-file */
4664 CASE(OP_OPEN_INOUTFILE): /* open-input-output-file */ {
4668 case OP_OPEN_INFILE: prop=port_input; break;
4669 case OP_OPEN_OUTFILE: prop=port_output; break;
4670 case OP_OPEN_INOUTFILE: prop=port_input|port_output; break;
4671 default: assert (! "reached");
4673 p=port_from_filename(sc,strvalue(car(sc->args)),prop);
4679 default: assert (! "reached");
4682 #if USE_STRING_PORTS
4683 CASE(OP_OPEN_INSTRING): /* open-input-string */
4684 CASE(OP_OPEN_INOUTSTRING): /* open-input-output-string */ {
4688 case OP_OPEN_INSTRING: prop=port_input; break;
4689 case OP_OPEN_INOUTSTRING: prop=port_input|port_output; break;
4690 default: assert (! "reached");
4692 p=port_from_string(sc, strvalue(car(sc->args)),
4693 strvalue(car(sc->args))+strlength(car(sc->args)), prop);
4699 CASE(OP_OPEN_OUTSTRING): /* open-output-string */ {
4701 if(car(sc->args)==sc->NIL) {
4702 p=port_from_scratch(sc);
4707 p=port_from_string(sc, strvalue(car(sc->args)),
4708 strvalue(car(sc->args))+strlength(car(sc->args)),
4716 CASE(OP_GET_OUTSTRING): /* get-output-string */ {
4719 if ((p=car(sc->args)->_object._port)->kind&port_string) {
4723 size=p->rep.string.curr-p->rep.string.start+1;
4724 str=sc->malloc(size);
4728 memcpy(str,p->rep.string.start,size-1);
4730 s=mk_string(sc,str);
4739 CASE(OP_CLOSE_INPORT): /* close-input-port */
4740 port_close(sc,car(sc->args),port_input);
4743 CASE(OP_CLOSE_OUTPORT): /* close-output-port */
4744 port_close(sc,car(sc->args),port_output);
4747 CASE(OP_INT_ENV): /* interaction-environment */
4748 s_return(sc,sc->global_env);
4750 CASE(OP_CURR_ENV): /* current-environment */
4751 s_return(sc,sc->envir);
4757 static pointer opexe_5(scheme *sc, enum scheme_opcodes op) {
4760 if(sc->nesting!=0) {
4764 Error_1(sc,"unmatched parentheses:",mk_integer(sc,n));
4768 /* ========== reading part ========== */
4770 if(!is_pair(sc->args)) {
4771 s_goto(sc,OP_READ_INTERNAL);
4773 if(!is_inport(car(sc->args))) {
4774 Error_1(sc,"read: not an input port:",car(sc->args));
4776 if(car(sc->args)==sc->inport) {
4777 s_goto(sc,OP_READ_INTERNAL);
4780 sc->inport=car(sc->args);
4781 x=cons(sc,x,sc->NIL);
4782 s_save(sc,OP_SET_INPORT, x, sc->NIL);
4783 s_goto(sc,OP_READ_INTERNAL);
4785 CASE(OP_READ_CHAR): /* read-char */
4786 CASE(OP_PEEK_CHAR): /* peek-char */ {
4788 if(is_pair(sc->args)) {
4789 if(car(sc->args)!=sc->inport) {
4791 x=cons(sc,x,sc->NIL);
4792 s_save(sc,OP_SET_INPORT, x, sc->NIL);
4793 sc->inport=car(sc->args);
4798 s_return(sc,sc->EOF_OBJ);
4800 if(sc->op==OP_PEEK_CHAR) {
4803 s_return(sc,mk_character(sc,c));
4806 CASE(OP_CHAR_READY): /* char-ready? */ {
4807 pointer p=sc->inport;
4809 if(is_pair(sc->args)) {
4812 res=p->_object._port->kind&port_string;
4816 CASE(OP_SET_INPORT): /* set-input-port */
4817 sc->inport=car(sc->args);
4818 s_return(sc,sc->value);
4820 CASE(OP_SET_OUTPORT): /* set-output-port */
4821 sc->outport=car(sc->args);
4822 s_return(sc,sc->value);
4827 s_return(sc,sc->EOF_OBJ);
4830 s_save(sc,OP_RDVEC,sc->NIL,sc->NIL);
4833 sc->tok = token(sc);
4834 if (sc->tok == TOK_RPAREN) {
4835 s_return(sc,sc->NIL);
4836 } else if (sc->tok == TOK_DOT) {
4837 Error_0(sc,"syntax error: illegal dot expression");
4839 sc->nesting_stack[sc->file_i]++;
4840 #if USE_TAGS && SHOW_ERROR_LINE
4841 if (sc->load_stack[sc->file_i].kind & port_file) {
4842 const char *filename =
4843 sc->load_stack[sc->file_i].rep.stdio.filename;
4845 sc->load_stack[sc->file_i].rep.stdio.curr_line;
4847 s_save(sc, OP_TAG_VALUE,
4848 cons(sc, mk_string(sc, filename),
4849 cons(sc, mk_integer(sc, lineno), sc->NIL)),
4853 s_save(sc,OP_RDLIST, sc->NIL, sc->NIL);
4854 s_thread_to(sc,OP_RDSEXPR);
4857 s_save(sc,OP_RDQUOTE, sc->NIL, sc->NIL);
4858 sc->tok = token(sc);
4859 s_thread_to(sc,OP_RDSEXPR);
4861 sc->tok = token(sc);
4862 if(sc->tok==TOK_VEC) {
4863 s_save(sc,OP_RDQQUOTEVEC, sc->NIL, sc->NIL);
4865 s_thread_to(sc,OP_RDSEXPR);
4867 s_save(sc,OP_RDQQUOTE, sc->NIL, sc->NIL);
4869 s_thread_to(sc,OP_RDSEXPR);
4871 s_save(sc,OP_RDUNQUOTE, sc->NIL, sc->NIL);
4872 sc->tok = token(sc);
4873 s_thread_to(sc,OP_RDSEXPR);
4875 s_save(sc,OP_RDUQTSP, sc->NIL, sc->NIL);
4876 sc->tok = token(sc);
4877 s_thread_to(sc,OP_RDSEXPR);
4879 s_return(sc,mk_atom(sc, readstr_upto(sc, DELIMITERS)));
4883 Error_0(sc,"Error reading string");
4888 pointer f=find_slot_in_env(sc,sc->envir,sc->SHARP_HOOK,1);
4890 Error_0(sc,"undefined sharp expression");
4892 sc->code=cons(sc,slot_value_in_env(f),sc->NIL);
4896 case TOK_SHARP_CONST:
4897 if ((x = mk_sharp_const(sc, readstr_upto(sc, DELIMITERS))) == sc->NIL) {
4898 Error_0(sc,"undefined sharp expression");
4903 Error_0(sc,"syntax error: illegal token");
4909 sc->args = cons(sc, sc->value, sc->args);
4911 sc->tok = token(sc);
4912 if (sc->tok == TOK_EOF)
4913 { s_return(sc,sc->EOF_OBJ); }
4914 else if (sc->tok == TOK_RPAREN) {
4919 else if (sc->load_stack[sc->file_i].kind & port_file)
4920 sc->load_stack[sc->file_i].rep.stdio.curr_line++;
4922 sc->nesting_stack[sc->file_i]--;
4923 s_return(sc,reverse_in_place(sc, sc->NIL, sc->args));
4924 } else if (sc->tok == TOK_DOT) {
4925 s_save(sc,OP_RDDOT, sc->args, sc->NIL);
4926 sc->tok = token(sc);
4927 s_thread_to(sc,OP_RDSEXPR);
4929 s_save(sc,OP_RDLIST, sc->args, sc->NIL);;
4930 s_thread_to(sc,OP_RDSEXPR);
4935 if (token(sc) != TOK_RPAREN) {
4936 Error_0(sc,"syntax error: illegal dot expression");
4938 sc->nesting_stack[sc->file_i]--;
4939 s_return(sc,reverse_in_place(sc, sc->value, sc->args));
4944 s_return_enable_gc(sc, cons(sc, sc->QUOTE,
4945 cons(sc, sc->value, sc->NIL)));
4949 s_return_enable_gc(sc, cons(sc, sc->QQUOTE,
4950 cons(sc, sc->value, sc->NIL)));
4952 CASE(OP_RDQQUOTEVEC):
4953 gc_disable(sc, 5 + 2 * gc_reservations (mk_symbol));
4954 s_return_enable_gc(sc,cons(sc, mk_symbol(sc,"apply"),
4955 cons(sc, mk_symbol(sc,"vector"),
4956 cons(sc,cons(sc, sc->QQUOTE,
4957 cons(sc,sc->value,sc->NIL)),
4962 s_return_enable_gc(sc, cons(sc, sc->UNQUOTE,
4963 cons(sc, sc->value, sc->NIL)));
4967 s_return_enable_gc(sc, cons(sc, sc->UNQUOTESP,
4968 cons(sc, sc->value, sc->NIL)));
4971 /*sc->code=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
4972 s_goto(sc,OP_EVAL); Cannot be quoted*/
4973 /*x=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
4974 s_return(sc,x); Cannot be part of pairs*/
4975 /*sc->code=mk_proc(sc,OP_VECTOR);
4977 s_goto(sc,OP_APPLY);*/
4979 s_goto(sc,OP_VECTOR);
4981 /* ========== printing part ========== */
4983 if(is_vector(sc->args)) {
4985 sc->args=cons(sc,sc->args,mk_integer(sc,0));
4986 s_thread_to(sc,OP_PVECFROM);
4987 } else if(is_environment(sc->args)) {
4988 putstr(sc,"#<ENVIRONMENT>");
4990 } else if (!is_pair(sc->args)) {
4991 printatom(sc, sc->args, sc->print_flag);
4993 } else if (car(sc->args) == sc->QUOTE && ok_abbrev(cdr(sc->args))) {
4995 sc->args = cadr(sc->args);
4996 s_thread_to(sc,OP_P0LIST);
4997 } else if (car(sc->args) == sc->QQUOTE && ok_abbrev(cdr(sc->args))) {
4999 sc->args = cadr(sc->args);
5000 s_thread_to(sc,OP_P0LIST);
5001 } else if (car(sc->args) == sc->UNQUOTE && ok_abbrev(cdr(sc->args))) {
5003 sc->args = cadr(sc->args);
5004 s_thread_to(sc,OP_P0LIST);
5005 } else if (car(sc->args) == sc->UNQUOTESP && ok_abbrev(cdr(sc->args))) {
5007 sc->args = cadr(sc->args);
5008 s_thread_to(sc,OP_P0LIST);
5011 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
5012 sc->args = car(sc->args);
5013 s_thread_to(sc,OP_P0LIST);
5017 if (is_pair(sc->args)) {
5018 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
5020 sc->args = car(sc->args);
5021 s_thread_to(sc,OP_P0LIST);
5022 } else if(is_vector(sc->args)) {
5023 s_save(sc,OP_P1LIST,sc->NIL,sc->NIL);
5025 s_thread_to(sc,OP_P0LIST);
5027 if (sc->args != sc->NIL) {
5029 printatom(sc, sc->args, sc->print_flag);
5034 CASE(OP_PVECFROM): {
5035 int i=ivalue_unchecked(cdr(sc->args));
5036 pointer vec=car(sc->args);
5037 int len=ivalue_unchecked(vec);
5042 pointer elem=vector_elem(vec,i);
5043 ivalue_unchecked(cdr(sc->args))=i+1;
5044 s_save(sc,OP_PVECFROM, sc->args, sc->NIL);
5048 s_thread_to(sc,OP_P0LIST);
5053 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
5054 Error_0(sc,sc->strbuff);
5060 static pointer opexe_6(scheme *sc, enum scheme_opcodes op) {
5065 CASE(OP_LIST_LENGTH): /* length */ /* a.k */
5066 v=list_length(sc,car(sc->args));
5068 Error_1(sc,"length: not a list:",car(sc->args));
5071 s_return_enable_gc(sc, mk_integer(sc, v));
5073 CASE(OP_ASSQ): /* assq */ /* a.k */
5075 for (y = cadr(sc->args); is_pair(y); y = cdr(y)) {
5076 if (!is_pair(car(y))) {
5077 Error_0(sc,"unable to handle non pair element");
5083 s_return(sc,car(y));
5089 CASE(OP_GET_CLOSURE): /* get-closure-code */ /* a.k */
5090 sc->args = car(sc->args);
5091 if (sc->args == sc->NIL) {
5093 } else if (is_closure(sc->args)) {
5095 s_return_enable_gc(sc, cons(sc, sc->LAMBDA,
5096 closure_code(sc->value)));
5097 } else if (is_macro(sc->args)) {
5099 s_return_enable_gc(sc, cons(sc, sc->LAMBDA,
5100 closure_code(sc->value)));
5104 CASE(OP_CLOSUREP): /* closure? */
5106 * Note, macro object is also a closure.
5107 * Therefore, (closure? <#MACRO>) ==> #t
5109 s_retbool(is_closure(car(sc->args)));
5110 CASE(OP_MACROP): /* macro? */
5111 s_retbool(is_macro(car(sc->args)));
5112 CASE(OP_VM_HISTORY): /* *vm-history* */
5113 s_return(sc, history_flatten(sc));
5115 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
5116 Error_0(sc,sc->strbuff);
5118 return sc->T; /* NOTREACHED */
5121 typedef pointer (*dispatch_func)(scheme *, enum scheme_opcodes);
5123 typedef int (*test_predicate)(pointer);
5125 static int is_any(pointer p) {
5130 static int is_nonneg(pointer p) {
5131 return ivalue(p)>=0 && is_integer(p);
5134 /* Correspond carefully with following defines! */
5141 {is_string, "string"},
5142 {is_symbol, "symbol"},
5144 {is_inport,"input port"},
5145 {is_outport,"output port"},
5146 {is_environment, "environment"},
5149 {is_character, "character"},
5150 {is_vector, "vector"},
5151 {is_number, "number"},
5152 {is_integer, "integer"},
5153 {is_nonneg, "non-negative integer"}
5157 #define TST_ANY "\001"
5158 #define TST_STRING "\002"
5159 #define TST_SYMBOL "\003"
5160 #define TST_PORT "\004"
5161 #define TST_INPORT "\005"
5162 #define TST_OUTPORT "\006"
5163 #define TST_ENVIRONMENT "\007"
5164 #define TST_PAIR "\010"
5165 #define TST_LIST "\011"
5166 #define TST_CHAR "\012"
5167 #define TST_VECTOR "\013"
5168 #define TST_NUMBER "\014"
5169 #define TST_INTEGER "\015"
5170 #define TST_NATURAL "\016"
5177 char *arg_tests_encoding;
5180 #define INF_ARG 0xffff
5182 static op_code_info dispatch_table[]= {
5183 #define _OP_DEF(A,B,C,D,E,OP) {A,B,C,D,E},
5184 #include "opdefines.h"
5188 static const char *procname(pointer x) {
5190 const char *name=dispatch_table[n].name;
5197 /* kernel of this interpreter */
5198 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op) {
5201 op_code_info *pcd=dispatch_table+sc->op;
5202 if (pcd->name!=0) { /* if built-in function, check arguments */
5203 char msg[STRBUFFSIZE];
5205 int n=list_length(sc,sc->args);
5207 /* Check number of arguments */
5208 if(n<pcd->min_arity) {
5210 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5212 pcd->min_arity==pcd->max_arity?"":" at least",
5215 if(ok && n>pcd->max_arity) {
5217 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5219 pcd->min_arity==pcd->max_arity?"":" at most",
5223 if(pcd->arg_tests_encoding!=0) {
5226 const char *t=pcd->arg_tests_encoding;
5227 pointer arglist=sc->args;
5229 pointer arg=car(arglist);
5231 if(j==TST_LIST[0]) {
5232 if(arg!=sc->NIL && !is_pair(arg)) break;
5234 if(!tests[j].fct(arg)) break;
5237 if(t[1]!=0) {/* last test is replicated as necessary */
5240 arglist=cdr(arglist);
5245 snprintf(msg, STRBUFFSIZE, "%s: argument %d must be: %s, got: %s",
5249 type_to_string(type(car(arglist))));
5254 if(_Error_1(sc,msg,0)==sc->NIL) {
5257 pcd=dispatch_table+sc->op;
5260 ok_to_freely_gc(sc);
5261 if (pcd->func(sc, (enum scheme_opcodes)sc->op) == sc->NIL) {
5265 fprintf(stderr,"No memory!\n");
5271 /* ========== Initialization of internal keywords ========== */
5273 static void assign_syntax(scheme *sc, char *name) {
5276 x = oblist_add_by_name(sc, name);
5277 typeflag(x) |= T_SYNTAX;
5280 static void assign_proc(scheme *sc, enum scheme_opcodes op, char *name) {
5283 x = mk_symbol(sc, name);
5285 new_slot_in_env(sc, x, y);
5288 static pointer mk_proc(scheme *sc, enum scheme_opcodes op) {
5291 y = get_cell(sc, sc->NIL, sc->NIL);
5292 typeflag(y) = (T_PROC | T_ATOM);
5293 ivalue_unchecked(y) = (long) op;
5298 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5299 static int syntaxnum(pointer p) {
5300 const char *s=strvalue(car(p));
5301 switch(strlength(car(p))) {
5303 if(s[0]=='i') return OP_IF0; /* if */
5304 else return OP_OR0; /* or */
5306 if(s[0]=='a') return OP_AND0; /* and */
5307 else return OP_LET0; /* let */
5310 case 'e': return OP_CASE0; /* case */
5311 case 'd': return OP_COND0; /* cond */
5312 case '*': return OP_LET0AST; /* let* */
5313 default: return OP_SET0; /* set! */
5317 case 'g': return OP_BEGIN; /* begin */
5318 case 'l': return OP_DELAY; /* delay */
5319 case 'c': return OP_MACRO0; /* macro */
5320 default: return OP_QUOTE; /* quote */
5324 case 'm': return OP_LAMBDA; /* lambda */
5325 case 'f': return OP_DEF0; /* define */
5326 default: return OP_LET0REC; /* letrec */
5329 return OP_C0STREAM; /* cons-stream */
5333 /* initialization of TinyScheme */
5335 INTERFACE static pointer s_cons(scheme *sc, pointer a, pointer b) {
5336 return cons(sc,a,b);
5338 INTERFACE static pointer s_immutable_cons(scheme *sc, pointer a, pointer b) {
5339 return immutable_cons(sc,a,b);
5342 static struct scheme_interface vtbl ={
5357 get_foreign_object_vtable,
5358 get_foreign_object_data,
5410 scheme *scheme_init_new() {
5411 scheme *sc=(scheme*)malloc(sizeof(scheme));
5412 if(!scheme_init(sc)) {
5420 scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free) {
5421 scheme *sc=(scheme*)malloc(sizeof(scheme));
5422 if(!scheme_init_custom_alloc(sc,malloc,free)) {
5431 int scheme_init(scheme *sc) {
5432 return scheme_init_custom_alloc(sc,malloc,free);
5435 int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
5436 int i, n=sizeof(dispatch_table)/sizeof(dispatch_table[0]);
5439 num_zero.is_fixnum=1;
5440 num_zero.value.ivalue=0;
5441 num_one.is_fixnum=1;
5442 num_one.value.ivalue=1;
5450 sc->last_cell_seg = -1;
5451 sc->sink = &sc->_sink;
5452 sc->NIL = &sc->_NIL;
5453 sc->T = &sc->_HASHT;
5454 sc->F = &sc->_HASHF;
5455 sc->EOF_OBJ=&sc->_EOF_OBJ;
5457 #if USE_SMALL_INTEGERS
5458 if (initialize_small_integers(sc)) {
5464 sc->free_cell = &sc->_NIL;
5466 sc->inhibit_gc = GC_ENABLED;
5467 sc->reserved_cells = 0;
5468 sc->reserved_lineno = 0;
5471 sc->outport=sc->NIL;
5472 sc->save_inport=sc->NIL;
5473 sc->loadport=sc->NIL;
5475 memset (sc->nesting_stack, 0, sizeof sc->nesting_stack);
5476 sc->interactive_repl=0;
5477 sc->strbuff = sc->malloc(STRBUFFSIZE);
5478 if (sc->strbuff == 0) {
5482 sc->strbuff_size = STRBUFFSIZE;
5484 if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
5489 dump_stack_initialize(sc);
5496 typeflag(sc->NIL) = (T_NIL | T_ATOM | MARK);
5497 car(sc->NIL) = cdr(sc->NIL) = sc->NIL;
5499 typeflag(sc->T) = (T_BOOLEAN | T_ATOM | MARK);
5500 car(sc->T) = cdr(sc->T) = sc->T;
5502 typeflag(sc->F) = (T_BOOLEAN | T_ATOM | MARK);
5503 car(sc->F) = cdr(sc->F) = sc->F;
5505 typeflag(sc->EOF_OBJ) = (T_EOF_OBJ | T_ATOM | MARK);
5506 car(sc->EOF_OBJ) = cdr(sc->EOF_OBJ) = sc->EOF_OBJ;
5508 typeflag(sc->sink) = (T_SINK | T_PAIR | MARK);
5509 car(sc->sink) = cdr(sc->sink) = sc->NIL;
5511 sc->c_nest = sc->NIL;
5513 sc->oblist = oblist_initial_value(sc);
5514 /* init global_env */
5515 new_frame_in_env(sc, sc->NIL);
5516 sc->global_env = sc->envir;
5518 x = mk_symbol(sc,"else");
5519 new_slot_in_env(sc, x, sc->T);
5521 assign_syntax(sc, "lambda");
5522 assign_syntax(sc, "quote");
5523 assign_syntax(sc, "define");
5524 assign_syntax(sc, "if");
5525 assign_syntax(sc, "begin");
5526 assign_syntax(sc, "set!");
5527 assign_syntax(sc, "let");
5528 assign_syntax(sc, "let*");
5529 assign_syntax(sc, "letrec");
5530 assign_syntax(sc, "cond");
5531 assign_syntax(sc, "delay");
5532 assign_syntax(sc, "and");
5533 assign_syntax(sc, "or");
5534 assign_syntax(sc, "cons-stream");
5535 assign_syntax(sc, "macro");
5536 assign_syntax(sc, "case");
5538 for(i=0; i<n; i++) {
5539 if(dispatch_table[i].name!=0) {
5540 assign_proc(sc, (enum scheme_opcodes)i, dispatch_table[i].name);
5544 history_init(sc, 8, 8);
5546 /* initialization of global pointers to special symbols */
5547 sc->LAMBDA = mk_symbol(sc, "lambda");
5548 sc->QUOTE = mk_symbol(sc, "quote");
5549 sc->QQUOTE = mk_symbol(sc, "quasiquote");
5550 sc->UNQUOTE = mk_symbol(sc, "unquote");
5551 sc->UNQUOTESP = mk_symbol(sc, "unquote-splicing");
5552 sc->FEED_TO = mk_symbol(sc, "=>");
5553 sc->COLON_HOOK = mk_symbol(sc,"*colon-hook*");
5554 sc->ERROR_HOOK = mk_symbol(sc, "*error-hook*");
5555 sc->SHARP_HOOK = mk_symbol(sc, "*sharp-hook*");
5556 #if USE_COMPILE_HOOK
5557 sc->COMPILE_HOOK = mk_symbol(sc, "*compile-hook*");
5560 return !sc->no_memory;
5563 void scheme_set_input_port_file(scheme *sc, FILE *fin) {
5564 sc->inport=port_from_file(sc,fin,port_input);
5567 void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end) {
5568 sc->inport=port_from_string(sc,start,past_the_end,port_input);
5571 void scheme_set_output_port_file(scheme *sc, FILE *fout) {
5572 sc->outport=port_from_file(sc,fout,port_output);
5575 void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end) {
5576 sc->outport=port_from_string(sc,start,past_the_end,port_output);
5579 void scheme_set_external_data(scheme *sc, void *p) {
5583 void scheme_deinit(scheme *sc) {
5591 sc->global_env=sc->NIL;
5592 dump_stack_free(sc);
5598 if(is_port(sc->inport)) {
5599 typeflag(sc->inport) = T_ATOM;
5602 sc->outport=sc->NIL;
5603 if(is_port(sc->save_inport)) {
5604 typeflag(sc->save_inport) = T_ATOM;
5606 sc->save_inport=sc->NIL;
5607 if(is_port(sc->loadport)) {
5608 typeflag(sc->loadport) = T_ATOM;
5610 sc->loadport=sc->NIL;
5612 gc(sc,sc->NIL,sc->NIL);
5614 #if USE_SMALL_INTEGERS
5615 sc->free(sc->integer_alloc);
5618 for(i=0; i<=sc->last_cell_seg; i++) {
5619 sc->free(sc->alloc_seg[i]);
5621 sc->free(sc->strbuff);
5624 for(i=0; i<=sc->file_i; i++) {
5625 if (sc->load_stack[i].kind & port_file) {
5626 fname = sc->load_stack[i].rep.stdio.filename;
5634 void scheme_load_file(scheme *sc, FILE *fin)
5635 { scheme_load_named_file(sc,fin,0); }
5637 void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename) {
5638 dump_stack_reset(sc);
5639 sc->envir = sc->global_env;
5641 sc->load_stack[0].kind=port_input|port_file;
5642 sc->load_stack[0].rep.stdio.file=fin;
5643 sc->loadport=mk_port(sc,sc->load_stack);
5646 sc->interactive_repl=1;
5650 sc->load_stack[0].rep.stdio.curr_line = 0;
5651 if(fin!=stdin && filename)
5652 sc->load_stack[0].rep.stdio.filename = store_string(sc, strlen(filename), filename, 0);
5654 sc->load_stack[0].rep.stdio.filename = NULL;
5657 sc->inport=sc->loadport;
5658 sc->args = mk_integer(sc,sc->file_i);
5659 Eval_Cycle(sc, OP_T0LVL);
5660 typeflag(sc->loadport)=T_ATOM;
5661 if(sc->retcode==0) {
5662 sc->retcode=sc->nesting!=0;
5666 sc->free(sc->load_stack[0].rep.stdio.filename);
5667 sc->load_stack[0].rep.stdio.filename = NULL;
5671 void scheme_load_string(scheme *sc, const char *cmd) {
5672 dump_stack_reset(sc);
5673 sc->envir = sc->global_env;
5675 sc->load_stack[0].kind=port_input|port_string;
5676 sc->load_stack[0].rep.string.start=(char*)cmd; /* This func respects const */
5677 sc->load_stack[0].rep.string.past_the_end=(char*)cmd+strlen(cmd);
5678 sc->load_stack[0].rep.string.curr=(char*)cmd;
5679 sc->loadport=mk_port(sc,sc->load_stack);
5681 sc->interactive_repl=0;
5682 sc->inport=sc->loadport;
5683 sc->args = mk_integer(sc,sc->file_i);
5684 Eval_Cycle(sc, OP_T0LVL);
5685 typeflag(sc->loadport)=T_ATOM;
5686 if(sc->retcode==0) {
5687 sc->retcode=sc->nesting!=0;
5691 void scheme_define(scheme *sc, pointer envir, pointer symbol, pointer value) {
5694 x=find_slot_in_env(sc,envir,symbol,0);
5696 set_slot_in_env(sc, x, value);
5698 new_slot_spec_in_env(sc, envir, symbol, value);
5703 void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr)
5707 mk_symbol(sc,sr->name),
5708 mk_foreign_func(sc, sr->f));
5711 void scheme_register_foreign_func_list(scheme * sc,
5712 scheme_registerable * list,
5716 for(i = 0; i < count; i++)
5718 scheme_register_foreign_func(sc, list + i);
5722 pointer scheme_apply0(scheme *sc, const char *procname)
5723 { return scheme_eval(sc, cons(sc,mk_symbol(sc,procname),sc->NIL)); }
5725 void save_from_C_call(scheme *sc)
5727 pointer saved_data =
5734 sc->c_nest = cons(sc, saved_data, sc->c_nest);
5735 /* Truncate the dump stack so TS will return here when done, not
5736 directly resume pre-C-call operations. */
5737 dump_stack_reset(sc);
5739 void restore_from_C_call(scheme *sc)
5741 car(sc->sink) = caar(sc->c_nest);
5742 sc->envir = cadar(sc->c_nest);
5743 sc->dump = cdr(cdar(sc->c_nest));
5745 sc->c_nest = cdr(sc->c_nest);
5748 /* "func" and "args" are assumed to be already eval'ed. */
5749 pointer scheme_call(scheme *sc, pointer func, pointer args)
5751 int old_repl = sc->interactive_repl;
5752 sc->interactive_repl = 0;
5753 save_from_C_call(sc);
5754 sc->envir = sc->global_env;
5758 Eval_Cycle(sc, OP_APPLY);
5759 sc->interactive_repl = old_repl;
5760 restore_from_C_call(sc);
5764 pointer scheme_eval(scheme *sc, pointer obj)
5766 int old_repl = sc->interactive_repl;
5767 sc->interactive_repl = 0;
5768 save_from_C_call(sc);
5772 Eval_Cycle(sc, OP_EVAL);
5773 sc->interactive_repl = old_repl;
5774 restore_from_C_call(sc);
5781 /* ========== Main ========== */
5785 #if defined(__APPLE__) && !defined (OSX)
5788 extern MacTS_main(int argc, char **argv);
5790 int argc = ccommand(&argv);
5791 MacTS_main(argc,argv);
5794 int MacTS_main(int argc, char **argv) {
5796 int main(int argc, char **argv) {
5800 char *file_name=InitFile;
5807 if(argc==2 && strcmp(argv[1],"-?")==0) {
5808 printf("Usage: tinyscheme -?\n");
5809 printf("or: tinyscheme [<file1> <file2> ...]\n");
5810 printf("followed by\n");
5811 printf(" -1 <file> [<arg1> <arg2> ...]\n");
5812 printf(" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5813 printf("assuming that the executable is named tinyscheme.\n");
5814 printf("Use - as filename for stdin.\n");
5817 if(!scheme_init(&sc)) {
5818 fprintf(stderr,"Could not initialize!\n");
5821 scheme_set_input_port_file(&sc, stdin);
5822 scheme_set_output_port_file(&sc, stdout);
5824 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"load-extension"),mk_foreign_func(&sc, scm_load_ext));
5827 if(access(file_name,0)!=0) {
5828 char *p=getenv("TINYSCHEMEINIT");
5834 if(strcmp(file_name,"-")==0) {
5836 } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0) {
5837 pointer args=sc.NIL;
5838 isfile=file_name[1]=='1';
5840 if(strcmp(file_name,"-")==0) {
5843 fin=fopen(file_name,"r");
5845 for(;*argv;argv++) {
5846 pointer value=mk_string(&sc,*argv);
5847 args=cons(&sc,value,args);
5849 args=reverse_in_place(&sc,sc.NIL,args);
5850 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args);
5853 fin=fopen(file_name,"r");
5855 if(isfile && fin==0) {
5856 fprintf(stderr,"Could not open file %s\n",file_name);
5859 scheme_load_named_file(&sc,fin,file_name);
5861 scheme_load_string(&sc,file_name);
5863 if(!isfile || fin!=stdin) {
5865 fprintf(stderr,"Errors encountered reading %s\n",file_name);
5873 } while(file_name!=0);
5875 scheme_load_named_file(&sc,stdin,0);