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
37 # define stricmp strcasecmp
41 /* Used for documentation purposes, to signal functions in 'interface' */
56 #define TOK_SHARP_CONST 11
60 #define DELIMITERS "()\";\f\t\v\n\r "
63 * Basic memory allocation units
66 #define banner "TinyScheme 1.41"
72 static int stricmp(const char *s1, const char *s2)
86 #endif /* __APPLE__ */
89 static const char *strlwr(char *s) {
100 # define prompt "ts> "
104 # define InitFile "init.scm"
107 #ifndef FIRST_CELLSEGS
108 # define FIRST_CELLSEGS 3
126 T_LAST_SYSTEM_TYPE=14
129 /* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */
132 #define T_MASKTYPE 31 /* 0000000000011111 */
133 #define T_SYNTAX 4096 /* 0001000000000000 */
134 #define T_IMMUTABLE 8192 /* 0010000000000000 */
135 #define T_ATOM 16384 /* 0100000000000000 */ /* only for gc */
136 #define CLRATOM 49151 /* 1011111111111111 */ /* only for gc */
137 #define MARK 32768 /* 1000000000000000 */
138 #define UNMARK 32767 /* 0111111111111111 */
141 static num num_add(num a, num b);
142 static num num_mul(num a, num b);
143 static num num_div(num a, num b);
144 static num num_intdiv(num a, num b);
145 static num num_sub(num a, num b);
146 static num num_rem(num a, num b);
147 static num num_mod(num a, num b);
148 static int num_eq(num a, num b);
149 static int num_gt(num a, num b);
150 static int num_ge(num a, num b);
151 static int num_lt(num a, num b);
152 static int num_le(num a, num b);
155 static double round_per_R5RS(double x);
157 static int is_zero_double(double x);
158 static INLINE int num_is_integer(pointer p) {
159 return ((p)->_object._number.is_fixnum);
165 /* macros for cell operations */
166 #define typeflag(p) ((p)->_flag)
167 #define type(p) (typeflag(p)&T_MASKTYPE)
169 INTERFACE INLINE int is_string(pointer p) { return (type(p)==T_STRING); }
170 #define strvalue(p) ((p)->_object._string._svalue)
171 #define strlength(p) ((p)->_object._string._length)
173 INTERFACE static int is_list(scheme *sc, pointer p);
174 INTERFACE INLINE int is_vector(pointer p) { return (type(p)==T_VECTOR); }
175 INTERFACE static void fill_vector(pointer vec, pointer obj);
176 INTERFACE static pointer vector_elem(pointer vec, int ielem);
177 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a);
178 INTERFACE INLINE int is_number(pointer p) { return (type(p)==T_NUMBER); }
179 INTERFACE INLINE int is_integer(pointer p) {
182 if (num_is_integer(p) || (double)ivalue(p) == rvalue(p))
187 INTERFACE INLINE int is_real(pointer p) {
188 return is_number(p) && (!(p)->_object._number.is_fixnum);
191 INTERFACE INLINE int is_character(pointer p) { return (type(p)==T_CHARACTER); }
192 INTERFACE INLINE char *string_value(pointer p) { return strvalue(p); }
193 INLINE num nvalue(pointer p) { return ((p)->_object._number); }
194 INTERFACE long ivalue(pointer p) { return (num_is_integer(p)?(p)->_object._number.value.ivalue:(long)(p)->_object._number.value.rvalue); }
195 INTERFACE double rvalue(pointer p) { return (!num_is_integer(p)?(p)->_object._number.value.rvalue:(double)(p)->_object._number.value.ivalue); }
196 #define ivalue_unchecked(p) ((p)->_object._number.value.ivalue)
197 #define rvalue_unchecked(p) ((p)->_object._number.value.rvalue)
198 #define set_num_integer(p) (p)->_object._number.is_fixnum=1;
199 #define set_num_real(p) (p)->_object._number.is_fixnum=0;
200 INTERFACE long charvalue(pointer p) { return ivalue_unchecked(p); }
202 INTERFACE INLINE int is_port(pointer p) { return (type(p)==T_PORT); }
203 INTERFACE INLINE int is_inport(pointer p) { return is_port(p) && p->_object._port->kind & port_input; }
204 INTERFACE INLINE int is_outport(pointer p) { return is_port(p) && p->_object._port->kind & port_output; }
206 INTERFACE INLINE int is_pair(pointer p) { return (type(p)==T_PAIR); }
207 #define car(p) ((p)->_object._cons._car)
208 #define cdr(p) ((p)->_object._cons._cdr)
209 INTERFACE pointer pair_car(pointer p) { return car(p); }
210 INTERFACE pointer pair_cdr(pointer p) { return cdr(p); }
211 INTERFACE pointer set_car(pointer p, pointer q) { return car(p)=q; }
212 INTERFACE pointer set_cdr(pointer p, pointer q) { return cdr(p)=q; }
214 INTERFACE INLINE int is_symbol(pointer p) { return (type(p)==T_SYMBOL); }
215 INTERFACE INLINE char *symname(pointer p) { return strvalue(car(p)); }
217 SCHEME_EXPORT INLINE int hasprop(pointer p) { return (typeflag(p)&T_SYMBOL); }
218 #define symprop(p) cdr(p)
221 INTERFACE INLINE int is_syntax(pointer p) { return (typeflag(p)&T_SYNTAX); }
222 INTERFACE INLINE int is_proc(pointer p) { return (type(p)==T_PROC); }
223 INTERFACE INLINE int is_foreign(pointer p) { return (type(p)==T_FOREIGN); }
224 INTERFACE INLINE char *syntaxname(pointer p) { return strvalue(car(p)); }
225 #define procnum(p) ivalue(p)
226 static const char *procname(pointer x);
228 INTERFACE INLINE int is_closure(pointer p) { return (type(p)==T_CLOSURE); }
229 INTERFACE INLINE int is_macro(pointer p) { return (type(p)==T_MACRO); }
230 INTERFACE INLINE pointer closure_code(pointer p) { return car(p); }
231 INTERFACE INLINE pointer closure_env(pointer p) { return cdr(p); }
233 INTERFACE INLINE int is_continuation(pointer p) { return (type(p)==T_CONTINUATION); }
234 #define cont_dump(p) cdr(p)
236 /* To do: promise should be forced ONCE only */
237 INTERFACE INLINE int is_promise(pointer p) { return (type(p)==T_PROMISE); }
239 INTERFACE INLINE int is_environment(pointer p) { return (type(p)==T_ENVIRONMENT); }
240 #define setenvironment(p) typeflag(p) = T_ENVIRONMENT
242 #define is_atom(p) (typeflag(p)&T_ATOM)
243 #define setatom(p) typeflag(p) |= T_ATOM
244 #define clratom(p) typeflag(p) &= CLRATOM
246 #define is_mark(p) (typeflag(p)&MARK)
247 #define setmark(p) typeflag(p) |= MARK
248 #define clrmark(p) typeflag(p) &= UNMARK
250 INTERFACE INLINE int is_immutable(pointer p) { return (typeflag(p)&T_IMMUTABLE); }
251 /*#define setimmutable(p) typeflag(p) |= T_IMMUTABLE*/
252 INTERFACE INLINE void setimmutable(pointer p) { typeflag(p) |= T_IMMUTABLE; }
254 #define caar(p) car(car(p))
255 #define cadr(p) car(cdr(p))
256 #define cdar(p) cdr(car(p))
257 #define cddr(p) cdr(cdr(p))
258 #define cadar(p) car(cdr(car(p)))
259 #define caddr(p) car(cdr(cdr(p)))
260 #define cdaar(p) cdr(car(car(p)))
261 #define cadaar(p) car(cdr(car(car(p))))
262 #define cadddr(p) car(cdr(cdr(cdr(p))))
263 #define cddddr(p) cdr(cdr(cdr(cdr(p))))
265 #if USE_CHAR_CLASSIFIERS
266 static INLINE int Cisalpha(int c) { return isascii(c) && isalpha(c); }
267 static INLINE int Cisdigit(int c) { return isascii(c) && isdigit(c); }
268 static INLINE int Cisspace(int c) { return isascii(c) && isspace(c); }
269 static INLINE int Cisupper(int c) { return isascii(c) && isupper(c); }
270 static INLINE int Cislower(int c) { return isascii(c) && islower(c); }
274 static const char *charnames[32]={
309 static int is_ascii_name(const char *name, int *pc) {
311 for(i=0; i<32; i++) {
312 if(stricmp(name,charnames[i])==0) {
317 if(stricmp(name,"del")==0) {
326 static int file_push(scheme *sc, const char *fname);
327 static void file_pop(scheme *sc);
328 static int file_interactive(scheme *sc);
329 static INLINE int is_one_of(char *s, int c);
330 static int alloc_cellseg(scheme *sc, int n);
331 static long binary_decode(const char *s);
332 static INLINE pointer get_cell(scheme *sc, pointer a, pointer b);
333 static pointer _get_cell(scheme *sc, pointer a, pointer b);
334 static pointer reserve_cells(scheme *sc, int n);
335 static pointer get_consecutive_cells(scheme *sc, int n);
336 static pointer find_consecutive_cells(scheme *sc, int n);
337 static void finalize_cell(scheme *sc, pointer a);
338 static int count_consecutive_cells(pointer x, int needed);
339 static pointer find_slot_in_env(scheme *sc, pointer env, pointer sym, int all);
340 static pointer mk_number(scheme *sc, num n);
341 static char *store_string(scheme *sc, int len, const char *str, char fill);
342 static pointer mk_vector(scheme *sc, int len);
343 static pointer mk_atom(scheme *sc, char *q);
344 static pointer mk_sharp_const(scheme *sc, char *name);
345 static pointer mk_port(scheme *sc, port *p);
346 static pointer port_from_filename(scheme *sc, const char *fn, int prop);
347 static pointer port_from_file(scheme *sc, FILE *, int prop);
348 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop);
349 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop);
350 static port *port_rep_from_file(scheme *sc, FILE *, int prop);
351 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop);
352 static void port_close(scheme *sc, pointer p, int flag);
353 static void mark(pointer a);
354 static void gc(scheme *sc, pointer a, pointer b);
355 static int basic_inchar(port *pt);
356 static int inchar(scheme *sc);
357 static void backchar(scheme *sc, int c);
358 static char *readstr_upto(scheme *sc, char *delim);
359 static pointer readstrexp(scheme *sc);
360 static INLINE int skipspace(scheme *sc);
361 static int token(scheme *sc);
362 static void printslashstring(scheme *sc, char *s, int len);
363 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen);
364 static void printatom(scheme *sc, pointer l, int f);
365 static pointer mk_proc(scheme *sc, enum scheme_opcodes op);
366 static pointer mk_closure(scheme *sc, pointer c, pointer e);
367 static pointer mk_continuation(scheme *sc, pointer d);
368 static pointer reverse(scheme *sc, pointer a);
369 static pointer reverse_in_place(scheme *sc, pointer term, pointer list);
370 static pointer revappend(scheme *sc, pointer a, pointer b);
371 static void dump_stack_mark(scheme *);
372 static pointer opexe_0(scheme *sc, enum scheme_opcodes op);
373 static pointer opexe_1(scheme *sc, enum scheme_opcodes op);
374 static pointer opexe_2(scheme *sc, enum scheme_opcodes op);
375 static pointer opexe_3(scheme *sc, enum scheme_opcodes op);
376 static pointer opexe_4(scheme *sc, enum scheme_opcodes op);
377 static pointer opexe_5(scheme *sc, enum scheme_opcodes op);
378 static pointer opexe_6(scheme *sc, enum scheme_opcodes op);
379 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op);
380 static void assign_syntax(scheme *sc, char *name);
381 static int syntaxnum(pointer p);
382 static void assign_proc(scheme *sc, enum scheme_opcodes, char *name);
384 #define num_ivalue(n) (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue)
385 #define num_rvalue(n) (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue)
387 static num num_add(num a, num b) {
389 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
391 ret.value.ivalue= a.value.ivalue+b.value.ivalue;
393 ret.value.rvalue=num_rvalue(a)+num_rvalue(b);
398 static num num_mul(num a, num b) {
400 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
402 ret.value.ivalue= a.value.ivalue*b.value.ivalue;
404 ret.value.rvalue=num_rvalue(a)*num_rvalue(b);
409 static num num_div(num a, num b) {
411 ret.is_fixnum=a.is_fixnum && b.is_fixnum && a.value.ivalue%b.value.ivalue==0;
413 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
415 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
420 static num num_intdiv(num a, num b) {
422 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
424 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
426 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
431 static num num_sub(num a, num b) {
433 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
435 ret.value.ivalue= a.value.ivalue-b.value.ivalue;
437 ret.value.rvalue=num_rvalue(a)-num_rvalue(b);
442 static num num_rem(num a, num b) {
445 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
449 /* remainder should have same sign as second operand */
454 } else if (res < 0) {
459 ret.value.ivalue=res;
463 static num num_mod(num a, num b) {
466 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
470 /* modulo should have same sign as second operand */
474 ret.value.ivalue=res;
478 static int num_eq(num a, num b) {
480 int is_fixnum=a.is_fixnum && b.is_fixnum;
482 ret= a.value.ivalue==b.value.ivalue;
484 ret=num_rvalue(a)==num_rvalue(b);
490 static int num_gt(num a, num b) {
492 int is_fixnum=a.is_fixnum && b.is_fixnum;
494 ret= a.value.ivalue>b.value.ivalue;
496 ret=num_rvalue(a)>num_rvalue(b);
501 static int num_ge(num a, num b) {
505 static int num_lt(num a, num b) {
507 int is_fixnum=a.is_fixnum && b.is_fixnum;
509 ret= a.value.ivalue<b.value.ivalue;
511 ret=num_rvalue(a)<num_rvalue(b);
516 static int num_le(num a, num b) {
521 /* Round to nearest. Round to even if midway */
522 static double round_per_R5RS(double x) {
532 if(fmod(fl,2.0)==0.0) { /* I imagine this holds */
541 static int is_zero_double(double x) {
542 return x<DBL_MIN && x>-DBL_MIN;
545 static long binary_decode(const char *s) {
548 while(*s!=0 && (*s=='1' || *s=='0')) {
557 /* allocate new cell segment */
558 static int alloc_cellseg(scheme *sc, int n) {
567 if(adj<sizeof(struct cell)) {
568 adj=sizeof(struct cell);
571 for (k = 0; k < n; k++) {
572 if (sc->last_cell_seg >= CELL_NSEGMENT - 1)
574 cp = (char*) sc->malloc(CELL_SEGSIZE * sizeof(struct cell)+adj);
577 i = ++sc->last_cell_seg ;
578 sc->alloc_seg[i] = cp;
579 /* adjust in TYPE_BITS-bit boundary */
580 if(((unsigned long)cp)%adj!=0) {
581 cp=(char*)(adj*((unsigned long)cp/adj+1));
583 /* insert new segment in address order */
585 sc->cell_seg[i] = newp;
586 while (i > 0 && sc->cell_seg[i - 1] > sc->cell_seg[i]) {
588 sc->cell_seg[i] = sc->cell_seg[i - 1];
589 sc->cell_seg[--i] = p;
591 sc->fcells += CELL_SEGSIZE;
592 last = newp + CELL_SEGSIZE - 1;
593 for (p = newp; p <= last; p++) {
598 /* insert new cells in address order on free list */
599 if (sc->free_cell == sc->NIL || p < sc->free_cell) {
600 cdr(last) = sc->free_cell;
601 sc->free_cell = newp;
604 while (cdr(p) != sc->NIL && newp > cdr(p))
613 static INLINE pointer get_cell_x(scheme *sc, pointer a, pointer b) {
614 if (sc->free_cell != sc->NIL) {
615 pointer x = sc->free_cell;
616 sc->free_cell = cdr(x);
620 return _get_cell (sc, a, b);
624 /* get new cell. parameter a, b is marked by gc. */
625 static pointer _get_cell(scheme *sc, pointer a, pointer b) {
632 if (sc->free_cell == sc->NIL) {
633 const int min_to_be_recovered = sc->last_cell_seg*8;
635 if (sc->fcells < min_to_be_recovered
636 || sc->free_cell == sc->NIL) {
637 /* if only a few recovered, get more to avoid fruitless gc's */
638 if (!alloc_cellseg(sc,1) && sc->free_cell == sc->NIL) {
645 sc->free_cell = cdr(x);
650 /* make sure that there is a given number of cells free */
651 static pointer reserve_cells(scheme *sc, int n) {
656 /* Are there enough cells available? */
657 if (sc->fcells < n) {
658 /* If not, try gc'ing some */
659 gc(sc, sc->NIL, sc->NIL);
660 if (sc->fcells < n) {
661 /* If there still aren't, try getting more heap */
662 if (!alloc_cellseg(sc,1)) {
667 if (sc->fcells < n) {
668 /* If all fail, report failure */
676 static pointer get_consecutive_cells(scheme *sc, int n) {
679 if(sc->no_memory) { return sc->sink; }
681 /* Are there any cells available? */
682 x=find_consecutive_cells(sc,n);
683 if (x != sc->NIL) { return x; }
685 /* If not, try gc'ing some */
686 gc(sc, sc->NIL, sc->NIL);
687 x=find_consecutive_cells(sc,n);
688 if (x != sc->NIL) { return x; }
690 /* If there still aren't, try getting more heap */
691 if (!alloc_cellseg(sc,1))
697 x=find_consecutive_cells(sc,n);
698 if (x != sc->NIL) { return x; }
700 /* If all fail, report failure */
705 static int count_consecutive_cells(pointer x, int needed) {
710 if(n>needed) return n;
715 static pointer find_consecutive_cells(scheme *sc, int n) {
720 while(*pp!=sc->NIL) {
721 cnt=count_consecutive_cells(*pp,n);
733 /* To retain recent allocs before interpreter knows about them -
736 static void push_recent_alloc(scheme *sc, pointer recent, pointer extra)
738 pointer holder = get_cell_x(sc, recent, extra);
739 typeflag(holder) = T_PAIR | T_IMMUTABLE;
740 car(holder) = recent;
741 cdr(holder) = car(sc->sink);
742 car(sc->sink) = holder;
746 static pointer get_cell(scheme *sc, pointer a, pointer b)
748 pointer cell = get_cell_x(sc, a, b);
749 /* For right now, include "a" and "b" in "cell" so that gc doesn't
750 think they are garbage. */
751 /* Tentatively record it as a pair so gc understands it. */
752 typeflag(cell) = T_PAIR;
755 push_recent_alloc(sc, cell, sc->NIL);
759 static pointer get_vector_object(scheme *sc, int len, pointer init)
761 pointer cells = get_consecutive_cells(sc,len/2+len%2+1);
762 if(sc->no_memory) { return sc->sink; }
763 /* Record it as a vector so that gc understands it. */
764 typeflag(cells) = (T_VECTOR | T_ATOM);
765 ivalue_unchecked(cells)=len;
766 set_num_integer(cells);
767 fill_vector(cells,init);
768 push_recent_alloc(sc, cells, sc->NIL);
772 static INLINE void ok_to_freely_gc(scheme *sc)
774 car(sc->sink) = sc->NIL;
779 static void check_cell_alloced(pointer p, int expect_alloced)
781 /* Can't use putstr(sc,str) because callers have no access to
783 if(typeflag(p) & !expect_alloced)
785 fprintf(stderr,"Cell is already allocated!\n");
787 if(!(typeflag(p)) & expect_alloced)
789 fprintf(stderr,"Cell is not allocated!\n");
793 static void check_range_alloced(pointer p, int n, int expect_alloced)
797 { (void)check_cell_alloced(p+i,expect_alloced); }
802 /* Medium level cell allocation */
804 /* get new cons cell */
805 pointer _cons(scheme *sc, pointer a, pointer b, int immutable) {
806 pointer x = get_cell(sc,a, b);
808 typeflag(x) = T_PAIR;
817 /* ========== oblist implementation ========== */
819 #ifndef USE_OBJECT_LIST
821 static int hash_fn(const char *key, int table_size);
823 static pointer oblist_initial_value(scheme *sc)
825 return mk_vector(sc, 461); /* probably should be bigger */
828 /* returns the new symbol */
829 static pointer oblist_add_by_name(scheme *sc, const char *name)
834 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
835 typeflag(x) = T_SYMBOL;
836 setimmutable(car(x));
838 location = hash_fn(name, ivalue_unchecked(sc->oblist));
839 set_vector_elem(sc->oblist, location,
840 immutable_cons(sc, x, vector_elem(sc->oblist, location)));
844 static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
850 location = hash_fn(name, ivalue_unchecked(sc->oblist));
851 for (x = vector_elem(sc->oblist, location); x != sc->NIL; x = cdr(x)) {
853 /* case-insensitive, per R5RS section 2. */
854 if(stricmp(name, s) == 0) {
861 static pointer oblist_all_symbols(scheme *sc)
865 pointer ob_list = sc->NIL;
867 for (i = 0; i < ivalue_unchecked(sc->oblist); i++) {
868 for (x = vector_elem(sc->oblist, i); x != sc->NIL; x = cdr(x)) {
869 ob_list = cons(sc, x, ob_list);
877 static pointer oblist_initial_value(scheme *sc)
882 static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
887 for (x = sc->oblist; x != sc->NIL; x = cdr(x)) {
889 /* case-insensitive, per R5RS section 2. */
890 if(stricmp(name, s) == 0) {
897 /* returns the new symbol */
898 static pointer oblist_add_by_name(scheme *sc, const char *name)
902 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
903 typeflag(x) = T_SYMBOL;
904 setimmutable(car(x));
905 sc->oblist = immutable_cons(sc, x, sc->oblist);
908 static pointer oblist_all_symbols(scheme *sc)
915 static pointer mk_port(scheme *sc, port *p) {
916 pointer x = get_cell(sc, sc->NIL, sc->NIL);
918 typeflag(x) = T_PORT|T_ATOM;
923 pointer mk_foreign_func(scheme *sc, foreign_func f) {
924 pointer x = get_cell(sc, sc->NIL, sc->NIL);
926 typeflag(x) = (T_FOREIGN | T_ATOM);
931 INTERFACE pointer mk_character(scheme *sc, int c) {
932 pointer x = get_cell(sc,sc->NIL, sc->NIL);
934 typeflag(x) = (T_CHARACTER | T_ATOM);
935 ivalue_unchecked(x)= c;
940 /* get number atom (integer) */
941 INTERFACE pointer mk_integer(scheme *sc, long num) {
942 pointer x = get_cell(sc,sc->NIL, sc->NIL);
944 typeflag(x) = (T_NUMBER | T_ATOM);
945 ivalue_unchecked(x)= num;
950 INTERFACE pointer mk_real(scheme *sc, double n) {
951 pointer x = get_cell(sc,sc->NIL, sc->NIL);
953 typeflag(x) = (T_NUMBER | T_ATOM);
954 rvalue_unchecked(x)= n;
959 static pointer mk_number(scheme *sc, num n) {
961 return mk_integer(sc,n.value.ivalue);
963 return mk_real(sc,n.value.rvalue);
967 /* allocate name to string area */
968 static char *store_string(scheme *sc, int len_str, const char *str, char fill) {
971 q=(char*)sc->malloc(len_str+1);
977 snprintf(q, len_str+1, "%s", str);
979 memset(q, fill, len_str);
986 INTERFACE pointer mk_string(scheme *sc, const char *str) {
987 return mk_counted_string(sc,str,strlen(str));
990 INTERFACE pointer mk_counted_string(scheme *sc, const char *str, int len) {
991 pointer x = get_cell(sc, sc->NIL, sc->NIL);
992 typeflag(x) = (T_STRING | T_ATOM);
993 strvalue(x) = store_string(sc,len,str,0);
998 INTERFACE pointer mk_empty_string(scheme *sc, int len, char fill) {
999 pointer x = get_cell(sc, sc->NIL, sc->NIL);
1000 typeflag(x) = (T_STRING | T_ATOM);
1001 strvalue(x) = store_string(sc,len,0,fill);
1006 INTERFACE static pointer mk_vector(scheme *sc, int len)
1007 { return get_vector_object(sc,len,sc->NIL); }
1009 INTERFACE static void fill_vector(pointer vec, pointer obj) {
1011 int num=ivalue(vec)/2+ivalue(vec)%2;
1012 for(i=0; i<num; i++) {
1013 typeflag(vec+1+i) = T_PAIR;
1014 setimmutable(vec+1+i);
1020 INTERFACE static pointer vector_elem(pointer vec, int ielem) {
1023 return car(vec+1+n);
1025 return cdr(vec+1+n);
1029 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a) {
1032 return car(vec+1+n)=a;
1034 return cdr(vec+1+n)=a;
1038 /* get new symbol */
1039 INTERFACE pointer mk_symbol(scheme *sc, const char *name) {
1042 /* first check oblist */
1043 x = oblist_find_by_name(sc, name);
1047 x = oblist_add_by_name(sc, name);
1052 INTERFACE pointer gensym(scheme *sc) {
1056 for(; sc->gensym_cnt<LONG_MAX; sc->gensym_cnt++) {
1057 snprintf(name,40,"gensym-%ld",sc->gensym_cnt);
1059 /* first check oblist */
1060 x = oblist_find_by_name(sc, name);
1065 x = oblist_add_by_name(sc, name);
1073 /* make symbol or number atom from string */
1074 static pointer mk_atom(scheme *sc, char *q) {
1076 int has_dec_point=0;
1080 if((p=strstr(q,"::"))!=0) {
1082 return cons(sc, sc->COLON_HOOK,
1086 cons(sc, mk_atom(sc,p+2), sc->NIL)),
1087 cons(sc, mk_symbol(sc,strlwr(q)), sc->NIL)));
1093 if ((c == '+') || (c == '-')) {
1100 return (mk_symbol(sc, strlwr(q)));
1102 } else if (c == '.') {
1106 return (mk_symbol(sc, strlwr(q)));
1108 } else if (!isdigit(c)) {
1109 return (mk_symbol(sc, strlwr(q)));
1112 for ( ; (c = *p) != 0; ++p) {
1115 if(!has_dec_point) {
1120 else if ((c == 'e') || (c == 'E')) {
1122 has_dec_point = 1; /* decimal point illegal
1125 if ((*p == '-') || (*p == '+') || isdigit(*p)) {
1130 return (mk_symbol(sc, strlwr(q)));
1134 return mk_real(sc,atof(q));
1136 return (mk_integer(sc, atol(q)));
1140 static pointer mk_sharp_const(scheme *sc, char *name) {
1142 char tmp[STRBUFFSIZE];
1144 if (!strcmp(name, "t"))
1146 else if (!strcmp(name, "f"))
1148 else if (*name == 'o') {/* #o (octal) */
1149 snprintf(tmp, STRBUFFSIZE, "0%s", name+1);
1150 sscanf(tmp, "%lo", (long unsigned *)&x);
1151 return (mk_integer(sc, x));
1152 } else if (*name == 'd') { /* #d (decimal) */
1153 sscanf(name+1, "%ld", (long int *)&x);
1154 return (mk_integer(sc, x));
1155 } else if (*name == 'x') { /* #x (hex) */
1156 snprintf(tmp, STRBUFFSIZE, "0x%s", name+1);
1157 sscanf(tmp, "%lx", (long unsigned *)&x);
1158 return (mk_integer(sc, x));
1159 } else if (*name == 'b') { /* #b (binary) */
1160 x = binary_decode(name+1);
1161 return (mk_integer(sc, x));
1162 } else if (*name == '\\') { /* #\w (character) */
1164 if(stricmp(name+1,"space")==0) {
1166 } else if(stricmp(name+1,"newline")==0) {
1168 } else if(stricmp(name+1,"return")==0) {
1170 } else if(stricmp(name+1,"tab")==0) {
1172 } else if(name[1]=='x' && name[2]!=0) {
1174 if(sscanf(name+2,"%x",(unsigned int *)&c1)==1 && c1 < UCHAR_MAX) {
1180 } else if(is_ascii_name(name+1,&c)) {
1183 } else if(name[2]==0) {
1188 return mk_character(sc,c);
1193 /* ========== garbage collector ========== */
1196 * We use algorithm E (Knuth, The Art of Computer Programming Vol.1,
1197 * sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm,
1200 static void mark(pointer a) {
1208 int num=ivalue_unchecked(p)/2+ivalue_unchecked(p)%2;
1209 for(i=0; i<num; i++) {
1210 /* Vector cells will be treated like ordinary cells */
1218 if (q && !is_mark(q)) {
1219 setatom(p); /* a note that we have moved car */
1225 E5: q = cdr(p); /* down cdr */
1226 if (q && !is_mark(q)) {
1232 E6: /* up. Undo the link switching from steps E4 and E5. */
1250 /* garbage collection. parameter a, b is marked. */
1251 static void gc(scheme *sc, pointer a, pointer b) {
1255 if(sc->gc_verbose) {
1256 putstr(sc, "gc...");
1259 /* mark system globals */
1261 mark(sc->global_env);
1263 /* mark current registers */
1267 dump_stack_mark(sc);
1270 mark(sc->save_inport);
1274 /* Mark recent objects the interpreter doesn't know about yet. */
1275 mark(car(sc->sink));
1276 /* Mark any older stuff above nested C calls */
1279 /* mark variables a, b */
1283 /* garbage collect */
1286 sc->free_cell = sc->NIL;
1287 /* free-list is kept sorted by address so as to maintain consecutive
1288 ranges, if possible, for use with vectors. Here we scan the cells
1289 (which are also kept sorted by address) downwards to build the
1290 free-list in sorted order.
1292 for (i = sc->last_cell_seg; i >= 0; i--) {
1293 p = sc->cell_seg[i] + CELL_SEGSIZE;
1294 while (--p >= sc->cell_seg[i]) {
1299 if (typeflag(p) != 0) {
1300 finalize_cell(sc, p);
1305 cdr(p) = sc->free_cell;
1311 if (sc->gc_verbose) {
1313 snprintf(msg,80,"done: %ld cells were recovered.\n", sc->fcells);
1318 static void finalize_cell(scheme *sc, pointer a) {
1320 sc->free(strvalue(a));
1321 } else if(is_port(a)) {
1322 if(a->_object._port->kind&port_file
1323 && a->_object._port->rep.stdio.closeit) {
1324 port_close(sc,a,port_input|port_output);
1326 sc->free(a->_object._port);
1330 /* ========== Routines for Reading ========== */
1332 static int file_push(scheme *sc, const char *fname) {
1335 if (sc->file_i == MAXFIL-1)
1337 fin=fopen(fname,"r");
1340 sc->load_stack[sc->file_i].kind=port_file|port_input;
1341 sc->load_stack[sc->file_i].rep.stdio.file=fin;
1342 sc->load_stack[sc->file_i].rep.stdio.closeit=1;
1343 sc->nesting_stack[sc->file_i]=0;
1344 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1347 sc->load_stack[sc->file_i].rep.stdio.curr_line = 0;
1349 sc->load_stack[sc->file_i].rep.stdio.filename = store_string(sc, strlen(fname), fname, 0);
1355 static void file_pop(scheme *sc) {
1356 if(sc->file_i != 0) {
1357 sc->nesting=sc->nesting_stack[sc->file_i];
1358 port_close(sc,sc->loadport,port_input);
1360 sc->loadport->_object._port=sc->load_stack+sc->file_i;
1364 static int file_interactive(scheme *sc) {
1365 return sc->file_i==0 && sc->load_stack[0].rep.stdio.file==stdin
1366 && sc->inport->_object._port->kind&port_file;
1369 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop) {
1373 if(prop==(port_input|port_output)) {
1375 } else if(prop==port_output) {
1384 pt=port_rep_from_file(sc,f,prop);
1385 pt->rep.stdio.closeit=1;
1389 pt->rep.stdio.filename = store_string(sc, strlen(fn), fn, 0);
1391 pt->rep.stdio.curr_line = 0;
1396 static pointer port_from_filename(scheme *sc, const char *fn, int prop) {
1398 pt=port_rep_from_filename(sc,fn,prop);
1402 return mk_port(sc,pt);
1405 static port *port_rep_from_file(scheme *sc, FILE *f, int prop)
1409 pt = (port *)sc->malloc(sizeof *pt);
1413 pt->kind = port_file | prop;
1414 pt->rep.stdio.file = f;
1415 pt->rep.stdio.closeit = 0;
1419 static pointer port_from_file(scheme *sc, FILE *f, int prop) {
1421 pt=port_rep_from_file(sc,f,prop);
1425 return mk_port(sc,pt);
1428 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1430 pt=(port*)sc->malloc(sizeof(port));
1434 pt->kind=port_string|prop;
1435 pt->rep.string.start=start;
1436 pt->rep.string.curr=start;
1437 pt->rep.string.past_the_end=past_the_end;
1441 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
1443 pt=port_rep_from_string(sc,start,past_the_end,prop);
1447 return mk_port(sc,pt);
1450 #define BLOCK_SIZE 256
1452 static port *port_rep_from_scratch(scheme *sc) {
1455 pt=(port*)sc->malloc(sizeof(port));
1459 start=sc->malloc(BLOCK_SIZE);
1463 memset(start,' ',BLOCK_SIZE-1);
1464 start[BLOCK_SIZE-1]='\0';
1465 pt->kind=port_string|port_output|port_srfi6;
1466 pt->rep.string.start=start;
1467 pt->rep.string.curr=start;
1468 pt->rep.string.past_the_end=start+BLOCK_SIZE-1;
1472 static pointer port_from_scratch(scheme *sc) {
1474 pt=port_rep_from_scratch(sc);
1478 return mk_port(sc,pt);
1481 static void port_close(scheme *sc, pointer p, int flag) {
1482 port *pt=p->_object._port;
1484 if((pt->kind & (port_input|port_output))==0) {
1485 if(pt->kind&port_file) {
1488 /* Cleanup is here so (close-*-port) functions could work too */
1489 pt->rep.stdio.curr_line = 0;
1491 if(pt->rep.stdio.filename)
1492 sc->free(pt->rep.stdio.filename);
1495 fclose(pt->rep.stdio.file);
1501 /* get new character from input file */
1502 static int inchar(scheme *sc) {
1506 pt = sc->inport->_object._port;
1507 if(pt->kind & port_saw_EOF)
1509 c = basic_inchar(pt);
1510 if(c == EOF && sc->inport == sc->loadport) {
1511 /* Instead, set port_saw_EOF */
1512 pt->kind |= port_saw_EOF;
1521 static int basic_inchar(port *pt) {
1522 if(pt->kind & port_file) {
1523 return fgetc(pt->rep.stdio.file);
1525 if(*pt->rep.string.curr == 0 ||
1526 pt->rep.string.curr == pt->rep.string.past_the_end) {
1529 return *pt->rep.string.curr++;
1534 /* back character to input buffer */
1535 static void backchar(scheme *sc, int c) {
1538 pt=sc->inport->_object._port;
1539 if(pt->kind&port_file) {
1540 ungetc(c,pt->rep.stdio.file);
1542 if(pt->rep.string.curr!=pt->rep.string.start) {
1543 --pt->rep.string.curr;
1548 static int realloc_port_string(scheme *sc, port *p)
1550 char *start=p->rep.string.start;
1551 size_t new_size=p->rep.string.past_the_end-start+1+BLOCK_SIZE;
1552 char *str=sc->malloc(new_size);
1554 memset(str,' ',new_size-1);
1555 str[new_size-1]='\0';
1557 p->rep.string.start=str;
1558 p->rep.string.past_the_end=str+new_size-1;
1559 p->rep.string.curr-=start-str;
1567 INTERFACE void putstr(scheme *sc, const char *s) {
1568 port *pt=sc->outport->_object._port;
1569 if(pt->kind&port_file) {
1570 fputs(s,pt->rep.stdio.file);
1573 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
1574 *pt->rep.string.curr++=*s;
1575 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
1576 *pt->rep.string.curr++=*s;
1582 static void putchars(scheme *sc, const char *s, int len) {
1583 port *pt=sc->outport->_object._port;
1584 if(pt->kind&port_file) {
1585 fwrite(s,1,len,pt->rep.stdio.file);
1588 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
1589 *pt->rep.string.curr++=*s++;
1590 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
1591 *pt->rep.string.curr++=*s++;
1597 INTERFACE void putcharacter(scheme *sc, int c) {
1598 port *pt=sc->outport->_object._port;
1599 if(pt->kind&port_file) {
1600 fputc(c,pt->rep.stdio.file);
1602 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
1603 *pt->rep.string.curr++=c;
1604 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
1605 *pt->rep.string.curr++=c;
1610 /* read characters up to delimiter, but cater to character constants */
1611 static char *readstr_upto(scheme *sc, char *delim) {
1612 char *p = sc->strbuff;
1614 while ((p - sc->strbuff < sizeof(sc->strbuff)) &&
1615 !is_one_of(delim, (*p++ = inchar(sc))));
1617 if(p == sc->strbuff+2 && p[-2] == '\\') {
1626 /* read string expression "xxx...xxx" */
1627 static pointer readstrexp(scheme *sc) {
1628 char *p = sc->strbuff;
1631 enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state=st_ok;
1635 if(c == EOF || p-sc->strbuff > sizeof(sc->strbuff)-1) {
1646 return mk_counted_string(sc,sc->strbuff,p-sc->strbuff);
1695 if(c>='0' && c<='F') {
1699 c1=(c1<<4)+c-'A'+10;
1713 if (c < '0' || c > '7')
1721 if (state==st_oct2 && c1 >= 32)
1726 if (state == st_oct1)
1740 /* check c is in chars */
1741 static INLINE int is_one_of(char *s, int c) {
1742 if(c==EOF) return 1;
1749 /* skip white characters */
1750 static INLINE int skipspace(scheme *sc) {
1751 int c = 0, curr_line = 0;
1759 } while (isspace(c));
1763 if (sc->load_stack[sc->file_i].kind & port_file)
1764 sc->load_stack[sc->file_i].rep.stdio.curr_line += curr_line;
1776 static int token(scheme *sc) {
1779 if(c == EOF) { return (TOK_EOF); }
1780 switch (c=inchar(sc)) {
1784 return (TOK_LPAREN);
1786 return (TOK_RPAREN);
1789 if(is_one_of(" \n\t",c)) {
1799 while ((c=inchar(sc)) != '\n' && c!=EOF)
1803 if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
1804 sc->load_stack[sc->file_i].rep.stdio.curr_line++;
1808 { return (TOK_EOF); }
1810 { return (token(sc));}
1812 return (TOK_DQUOTE);
1814 return (TOK_BQUOTE);
1816 if ((c=inchar(sc)) == '@') {
1817 return (TOK_ATMARK);
1826 } else if(c == '!') {
1827 while ((c=inchar(sc)) != '\n' && c!=EOF)
1831 if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
1832 sc->load_stack[sc->file_i].rep.stdio.curr_line++;
1836 { return (TOK_EOF); }
1838 { return (token(sc));}
1841 if(is_one_of(" tfodxb\\",c)) {
1842 return TOK_SHARP_CONST;
1853 /* ========== Routines for Printing ========== */
1854 #define ok_abbrev(x) (is_pair(x) && cdr(x) == sc->NIL)
1856 static void printslashstring(scheme *sc, char *p, int len) {
1858 unsigned char *s=(unsigned char*)p;
1859 putcharacter(sc,'"');
1860 for ( i=0; i<len; i++) {
1861 if(*s==0xff || *s=='"' || *s<' ' || *s=='\\') {
1862 putcharacter(sc,'\\');
1865 putcharacter(sc,'"');
1868 putcharacter(sc,'n');
1871 putcharacter(sc,'t');
1874 putcharacter(sc,'r');
1877 putcharacter(sc,'\\');
1881 putcharacter(sc,'x');
1883 putcharacter(sc,d+'0');
1885 putcharacter(sc,d-10+'A');
1889 putcharacter(sc,d+'0');
1891 putcharacter(sc,d-10+'A');
1896 putcharacter(sc,*s);
1900 putcharacter(sc,'"');
1905 static void printatom(scheme *sc, pointer l, int f) {
1908 atom2str(sc,l,f,&p,&len);
1913 /* Uses internal buffer unless string pointer is already available */
1914 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen) {
1919 } else if (l == sc->T) {
1921 } else if (l == sc->F) {
1923 } else if (l == sc->EOF_OBJ) {
1925 } else if (is_port(l)) {
1927 } else if (is_number(l)) {
1929 if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */ {
1930 if(num_is_integer(l)) {
1931 snprintf(p, STRBUFFSIZE, "%ld", ivalue_unchecked(l));
1933 snprintf(p, STRBUFFSIZE, "%.10g", rvalue_unchecked(l));
1934 /* r5rs says there must be a '.' (unless 'e'?) */
1935 f = strcspn(p, ".e");
1937 p[f] = '.'; /* not found, so add '.0' at the end */
1946 snprintf(p, STRBUFFSIZE, "%lx", v);
1948 snprintf(p, STRBUFFSIZE, "-%lx", -v);
1949 } else if (f == 8) {
1951 snprintf(p, STRBUFFSIZE, "%lo", v);
1953 snprintf(p, STRBUFFSIZE, "-%lo", -v);
1954 } else if (f == 2) {
1955 unsigned long b = (v < 0) ? -v : v;
1956 p = &p[STRBUFFSIZE-1];
1958 do { *--p = (b&1) ? '1' : '0'; b >>= 1; } while (b != 0);
1959 if (v < 0) *--p = '-';
1962 } else if (is_string(l)) {
1965 } else { /* Hack, uses the fact that printing is needed */
1968 printslashstring(sc, strvalue(l), strlength(l));
1971 } else if (is_character(l)) {
1997 snprintf(p,STRBUFFSIZE, "#\\%s",charnames[c]);
2002 snprintf(p,STRBUFFSIZE,"#\\x%x",c);
2006 snprintf(p,STRBUFFSIZE,"#\\%c",c);
2010 } else if (is_symbol(l)) {
2012 } else if (is_proc(l)) {
2014 snprintf(p,STRBUFFSIZE,"#<%s PROCEDURE %ld>", procname(l),procnum(l));
2015 } else if (is_macro(l)) {
2017 } else if (is_closure(l)) {
2019 } else if (is_promise(l)) {
2021 } else if (is_foreign(l)) {
2023 snprintf(p,STRBUFFSIZE,"#<FOREIGN PROCEDURE %ld>", procnum(l));
2024 } else if (is_continuation(l)) {
2025 p = "#<CONTINUATION>";
2032 /* ========== Routines for Evaluation Cycle ========== */
2034 /* make closure. c is code. e is environment */
2035 static pointer mk_closure(scheme *sc, pointer c, pointer e) {
2036 pointer x = get_cell(sc, c, e);
2038 typeflag(x) = T_CLOSURE;
2044 /* make continuation. */
2045 static pointer mk_continuation(scheme *sc, pointer d) {
2046 pointer x = get_cell(sc, sc->NIL, d);
2048 typeflag(x) = T_CONTINUATION;
2053 static pointer list_star(scheme *sc, pointer d) {
2055 if(cdr(d)==sc->NIL) {
2058 p=cons(sc,car(d),cdr(d));
2060 while(cdr(cdr(p))!=sc->NIL) {
2061 d=cons(sc,car(p),cdr(p));
2062 if(cdr(cdr(p))!=sc->NIL) {
2070 /* reverse list -- produce new list */
2071 static pointer reverse(scheme *sc, pointer a) {
2072 /* a must be checked by gc */
2073 pointer p = sc->NIL;
2075 for ( ; is_pair(a); a = cdr(a)) {
2076 p = cons(sc, car(a), p);
2081 /* reverse list --- in-place */
2082 static pointer reverse_in_place(scheme *sc, pointer term, pointer list) {
2083 pointer p = list, result = term, q;
2085 while (p != sc->NIL) {
2094 /* append list -- produce new list (in reverse order) */
2095 static pointer revappend(scheme *sc, pointer a, pointer b) {
2099 while (is_pair(p)) {
2100 result = cons(sc, car(p), result);
2108 return sc->F; /* signal an error */
2111 /* equivalence of atoms */
2112 int eqv(pointer a, pointer b) {
2115 return (strvalue(a) == strvalue(b));
2118 } else if (is_number(a)) {
2120 if (num_is_integer(a) == num_is_integer(b))
2121 return num_eq(nvalue(a),nvalue(b));
2124 } else if (is_character(a)) {
2125 if (is_character(b))
2126 return charvalue(a)==charvalue(b);
2129 } else if (is_port(a)) {
2134 } else if (is_proc(a)) {
2136 return procnum(a)==procnum(b);
2144 /* true or false value macro */
2145 /* () is #t in R5RS */
2146 #define is_true(p) ((p) != sc->F)
2147 #define is_false(p) ((p) == sc->F)
2149 /* ========== Environment implementation ========== */
2151 #if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
2153 static int hash_fn(const char *key, int table_size)
2155 unsigned int hashed = 0;
2157 int bits_per_int = sizeof(unsigned int)*8;
2159 for (c = key; *c; c++) {
2160 /* letters have about 5 bits in them */
2161 hashed = (hashed<<5) | (hashed>>(bits_per_int-5));
2164 return hashed % table_size;
2168 #ifndef USE_ALIST_ENV
2171 * In this implementation, each frame of the environment may be
2172 * a hash table: a vector of alists hashed by variable name.
2173 * In practice, we use a vector only for the initial frame;
2174 * subsequent frames are too small and transient for the lookup
2175 * speed to out-weigh the cost of making a new vector.
2178 static void new_frame_in_env(scheme *sc, pointer old_env)
2182 /* The interaction-environment has about 300 variables in it. */
2183 if (old_env == sc->NIL) {
2184 new_frame = mk_vector(sc, 461);
2186 new_frame = sc->NIL;
2189 sc->envir = immutable_cons(sc, new_frame, old_env);
2190 setenvironment(sc->envir);
2193 static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
2194 pointer variable, pointer value)
2196 pointer slot = immutable_cons(sc, variable, value);
2198 if (is_vector(car(env))) {
2199 int location = hash_fn(symname(variable), ivalue_unchecked(car(env)));
2201 set_vector_elem(car(env), location,
2202 immutable_cons(sc, slot, vector_elem(car(env), location)));
2204 car(env) = immutable_cons(sc, slot, car(env));
2208 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
2213 for (x = env; x != sc->NIL; x = cdr(x)) {
2214 if (is_vector(car(x))) {
2215 location = hash_fn(symname(hdl), ivalue_unchecked(car(x)));
2216 y = vector_elem(car(x), location);
2220 for ( ; y != sc->NIL; y = cdr(y)) {
2221 if (caar(y) == hdl) {
2238 #else /* USE_ALIST_ENV */
2240 static INLINE void new_frame_in_env(scheme *sc, pointer old_env)
2242 sc->envir = immutable_cons(sc, sc->NIL, old_env);
2243 setenvironment(sc->envir);
2246 static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
2247 pointer variable, pointer value)
2249 car(env) = immutable_cons(sc, immutable_cons(sc, variable, value), car(env));
2252 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
2255 for (x = env; x != sc->NIL; x = cdr(x)) {
2256 for (y = car(x); y != sc->NIL; y = cdr(y)) {
2257 if (caar(y) == hdl) {
2274 #endif /* USE_ALIST_ENV else */
2276 static INLINE void new_slot_in_env(scheme *sc, pointer variable, pointer value)
2278 new_slot_spec_in_env(sc, sc->envir, variable, value);
2281 static INLINE void set_slot_in_env(scheme *sc, pointer slot, pointer value)
2286 static INLINE pointer slot_value_in_env(pointer slot)
2291 /* ========== Evaluation Cycle ========== */
2294 static pointer _Error_1(scheme *sc, const char *s, pointer a) {
2295 const char *str = s;
2298 pointer hdl=sc->ERROR_HOOK;
2302 char sbuf[STRBUFFSIZE];
2304 /* make sure error is not in REPL */
2305 if (sc->load_stack[sc->file_i].kind & port_file &&
2306 sc->load_stack[sc->file_i].rep.stdio.file != stdin) {
2307 int ln = sc->load_stack[sc->file_i].rep.stdio.curr_line;
2308 const char *fname = sc->load_stack[sc->file_i].rep.stdio.filename;
2310 /* should never happen */
2311 if(!fname) fname = "<unknown>";
2313 /* we started from 0 */
2315 snprintf(sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s);
2317 str = (const char*)sbuf;
2322 x=find_slot_in_env(sc,sc->envir,hdl,1);
2325 sc->code = cons(sc, cons(sc, sc->QUOTE, cons(sc,(a), sc->NIL)), sc->NIL);
2329 sc->code = cons(sc, mk_string(sc, str), sc->code);
2330 setimmutable(car(sc->code));
2331 sc->code = cons(sc, slot_value_in_env(x), sc->code);
2332 sc->op = (int)OP_EVAL;
2338 sc->args = cons(sc, (a), sc->NIL);
2342 sc->args = cons(sc, mk_string(sc, str), sc->args);
2343 setimmutable(car(sc->args));
2344 sc->op = (int)OP_ERR0;
2347 #define Error_1(sc,s, a) return _Error_1(sc,s,a)
2348 #define Error_0(sc,s) return _Error_1(sc,s,0)
2350 /* Too small to turn into function */
2352 # define END } while (0)
2353 #define s_goto(sc,a) BEGIN \
2354 sc->op = (int)(a); \
2357 #define s_return(sc,a) return _s_return(sc,a)
2359 #ifndef USE_SCHEME_STACK
2361 /* this structure holds all the interpreter's registers */
2362 struct dump_stack_frame {
2363 enum scheme_opcodes op;
2369 #define STACK_GROWTH 3
2371 static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code)
2373 int nframes = (int)sc->dump;
2374 struct dump_stack_frame *next_frame;
2376 /* enough room for the next frame? */
2377 if (nframes >= sc->dump_size) {
2378 sc->dump_size += STACK_GROWTH;
2379 /* alas there is no sc->realloc */
2380 sc->dump_base = realloc(sc->dump_base,
2381 sizeof(struct dump_stack_frame) * sc->dump_size);
2383 next_frame = (struct dump_stack_frame *)sc->dump_base + nframes;
2384 next_frame->op = op;
2385 next_frame->args = args;
2386 next_frame->envir = sc->envir;
2387 next_frame->code = code;
2388 sc->dump = (pointer)(nframes+1);
2391 static pointer _s_return(scheme *sc, pointer a)
2393 int nframes = (int)sc->dump;
2394 struct dump_stack_frame *frame;
2401 frame = (struct dump_stack_frame *)sc->dump_base + nframes;
2403 sc->args = frame->args;
2404 sc->envir = frame->envir;
2405 sc->code = frame->code;
2406 sc->dump = (pointer)nframes;
2410 static INLINE void dump_stack_reset(scheme *sc)
2412 /* in this implementation, sc->dump is the number of frames on the stack */
2413 sc->dump = (pointer)0;
2416 static INLINE void dump_stack_initialize(scheme *sc)
2419 sc->dump_base = NULL;
2420 dump_stack_reset(sc);
2423 static void dump_stack_free(scheme *sc)
2425 free(sc->dump_base);
2426 sc->dump_base = NULL;
2427 sc->dump = (pointer)0;
2431 static INLINE void dump_stack_mark(scheme *sc)
2433 int nframes = (int)sc->dump;
2435 for(i=0; i<nframes; i++) {
2436 struct dump_stack_frame *frame;
2437 frame = (struct dump_stack_frame *)sc->dump_base + i;
2446 static INLINE void dump_stack_reset(scheme *sc)
2451 static INLINE void dump_stack_initialize(scheme *sc)
2453 dump_stack_reset(sc);
2456 static void dump_stack_free(scheme *sc)
2461 static pointer _s_return(scheme *sc, pointer a) {
2463 if(sc->dump==sc->NIL) return sc->NIL;
2464 sc->op = ivalue(car(sc->dump));
2465 sc->args = cadr(sc->dump);
2466 sc->envir = caddr(sc->dump);
2467 sc->code = cadddr(sc->dump);
2468 sc->dump = cddddr(sc->dump);
2472 static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) {
2473 sc->dump = cons(sc, sc->envir, cons(sc, (code), sc->dump));
2474 sc->dump = cons(sc, (args), sc->dump);
2475 sc->dump = cons(sc, mk_integer(sc, (long)(op)), sc->dump);
2478 static INLINE void dump_stack_mark(scheme *sc)
2484 #define s_retbool(tf) s_return(sc,(tf) ? sc->T : sc->F)
2486 static pointer opexe_0(scheme *sc, enum scheme_opcodes op) {
2490 case OP_LOAD: /* load */
2491 if(file_interactive(sc)) {
2492 fprintf(sc->outport->_object._port->rep.stdio.file,
2493 "Loading %s\n", strvalue(car(sc->args)));
2495 if (!file_push(sc,strvalue(car(sc->args)))) {
2496 Error_1(sc,"unable to open", car(sc->args));
2500 sc->args = mk_integer(sc,sc->file_i);
2501 s_goto(sc,OP_T0LVL);
2504 case OP_T0LVL: /* top level */
2505 /* If we reached the end of file, this loop is done. */
2506 if(sc->loadport->_object._port->kind & port_saw_EOF)
2516 s_return(sc,sc->value);
2521 /* If interactive, be nice to user. */
2522 if(file_interactive(sc))
2524 sc->envir = sc->global_env;
2525 dump_stack_reset(sc);
2530 /* Set up another iteration of REPL */
2532 sc->save_inport=sc->inport;
2533 sc->inport = sc->loadport;
2534 s_save(sc,OP_T0LVL, sc->NIL, sc->NIL);
2535 s_save(sc,OP_VALUEPRINT, sc->NIL, sc->NIL);
2536 s_save(sc,OP_T1LVL, sc->NIL, sc->NIL);
2537 s_goto(sc,OP_READ_INTERNAL);
2539 case OP_T1LVL: /* top level */
2540 sc->code = sc->value;
2541 sc->inport=sc->save_inport;
2544 case OP_READ_INTERNAL: /* internal read */
2545 sc->tok = token(sc);
2546 if(sc->tok==TOK_EOF)
2547 { s_return(sc,sc->EOF_OBJ); }
2548 s_goto(sc,OP_RDSEXPR);
2551 s_return(sc, gensym(sc));
2553 case OP_VALUEPRINT: /* print evaluation result */
2554 /* OP_VALUEPRINT is always pushed, because when changing from
2555 non-interactive to interactive mode, it needs to be
2556 already on the stack */
2558 putstr(sc,"\nGives: ");
2560 if(file_interactive(sc)) {
2562 sc->args = sc->value;
2563 s_goto(sc,OP_P0LIST);
2565 s_return(sc,sc->value);
2568 case OP_EVAL: /* main part of evaluation */
2571 /*s_save(sc,OP_VALUEPRINT,sc->NIL,sc->NIL);*/
2572 s_save(sc,OP_REAL_EVAL,sc->args,sc->code);
2574 putstr(sc,"\nEval: ");
2575 s_goto(sc,OP_P0LIST);
2580 if (is_symbol(sc->code)) { /* symbol */
2581 x=find_slot_in_env(sc,sc->envir,sc->code,1);
2583 s_return(sc,slot_value_in_env(x));
2585 Error_1(sc,"eval: unbound variable:", sc->code);
2587 } else if (is_pair(sc->code)) {
2588 if (is_syntax(x = car(sc->code))) { /* SYNTAX */
2589 sc->code = cdr(sc->code);
2590 s_goto(sc,syntaxnum(x));
2591 } else {/* first, eval top element and eval arguments */
2592 s_save(sc,OP_E0ARGS, sc->NIL, sc->code);
2593 /* If no macros => s_save(sc,OP_E1ARGS, sc->NIL, cdr(sc->code));*/
2594 sc->code = car(sc->code);
2598 s_return(sc,sc->code);
2601 case OP_E0ARGS: /* eval arguments */
2602 if (is_macro(sc->value)) { /* macro expansion */
2603 s_save(sc,OP_DOMACRO, sc->NIL, sc->NIL);
2604 sc->args = cons(sc,sc->code, sc->NIL);
2605 sc->code = sc->value;
2606 s_goto(sc,OP_APPLY);
2608 sc->code = cdr(sc->code);
2609 s_goto(sc,OP_E1ARGS);
2612 case OP_E1ARGS: /* eval arguments */
2613 sc->args = cons(sc, sc->value, sc->args);
2614 if (is_pair(sc->code)) { /* continue */
2615 s_save(sc,OP_E1ARGS, sc->args, cdr(sc->code));
2616 sc->code = car(sc->code);
2620 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
2621 sc->code = car(sc->args);
2622 sc->args = cdr(sc->args);
2623 s_goto(sc,OP_APPLY);
2629 sc->tracing=ivalue(car(sc->args));
2630 s_return(sc,mk_integer(sc,tr));
2634 case OP_APPLY: /* apply 'code' to 'args' */
2637 s_save(sc,OP_REAL_APPLY,sc->args,sc->code);
2639 /* sc->args=cons(sc,sc->code,sc->args);*/
2640 putstr(sc,"\nApply to: ");
2641 s_goto(sc,OP_P0LIST);
2646 if (is_proc(sc->code)) {
2647 s_goto(sc,procnum(sc->code)); /* PROCEDURE */
2648 } else if (is_foreign(sc->code))
2650 /* Keep nested calls from GC'ing the arglist */
2651 push_recent_alloc(sc,sc->args,sc->NIL);
2652 x=sc->code->_object._ff(sc,sc->args);
2654 } else if (is_closure(sc->code) || is_macro(sc->code)
2655 || is_promise(sc->code)) { /* CLOSURE */
2656 /* Should not accept promise */
2657 /* make environment */
2658 new_frame_in_env(sc, closure_env(sc->code));
2659 for (x = car(closure_code(sc->code)), y = sc->args;
2660 is_pair(x); x = cdr(x), y = cdr(y)) {
2662 Error_0(sc,"not enough arguments");
2664 new_slot_in_env(sc, car(x), car(y));
2669 * if (y != sc->NIL) {
2670 * Error_0(sc,"too many arguments");
2673 } else if (is_symbol(x))
2674 new_slot_in_env(sc, x, y);
2676 Error_1(sc,"syntax error in closure: not a symbol:", x);
2678 sc->code = cdr(closure_code(sc->code));
2680 s_goto(sc,OP_BEGIN);
2681 } else if (is_continuation(sc->code)) { /* CONTINUATION */
2682 sc->dump = cont_dump(sc->code);
2683 s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL);
2685 Error_0(sc,"illegal function");
2688 case OP_DOMACRO: /* do macro */
2689 sc->code = sc->value;
2693 case OP_LAMBDA: /* lambda */
2694 /* If the hook is defined, apply it to sc->code, otherwise
2695 set sc->value fall thru */
2697 pointer f=find_slot_in_env(sc,sc->envir,sc->COMPILE_HOOK,1);
2699 sc->value = sc->code;
2702 s_save(sc,OP_LAMBDA1,sc->args,sc->code);
2703 sc->args=cons(sc,sc->code,sc->NIL);
2704 sc->code=slot_value_in_env(f);
2705 s_goto(sc,OP_APPLY);
2710 s_return(sc,mk_closure(sc, sc->value, sc->envir));
2713 case OP_LAMBDA: /* lambda */
2714 s_return(sc,mk_closure(sc, sc->code, sc->envir));
2718 case OP_MKCLOSURE: /* make-closure */
2720 if(car(x)==sc->LAMBDA) {
2723 if(cdr(sc->args)==sc->NIL) {
2728 s_return(sc,mk_closure(sc, x, y));
2730 case OP_QUOTE: /* quote */
2731 s_return(sc,car(sc->code));
2733 case OP_DEF0: /* define */
2734 if(is_immutable(car(sc->code)))
2735 Error_1(sc,"define: unable to alter immutable", car(sc->code));
2737 if (is_pair(car(sc->code))) {
2739 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
2742 sc->code = cadr(sc->code);
2744 if (!is_symbol(x)) {
2745 Error_0(sc,"variable is not a symbol");
2747 s_save(sc,OP_DEF1, sc->NIL, x);
2750 case OP_DEF1: /* define */
2751 x=find_slot_in_env(sc,sc->envir,sc->code,0);
2753 set_slot_in_env(sc, x, sc->value);
2755 new_slot_in_env(sc, sc->code, sc->value);
2757 s_return(sc,sc->code);
2760 case OP_DEFP: /* defined? */
2762 if(cdr(sc->args)!=sc->NIL) {
2765 s_retbool(find_slot_in_env(sc,x,car(sc->args),1)!=sc->NIL);
2767 case OP_SET0: /* set! */
2768 if(is_immutable(car(sc->code)))
2769 Error_1(sc,"set!: unable to alter immutable variable",car(sc->code));
2770 s_save(sc,OP_SET1, sc->NIL, car(sc->code));
2771 sc->code = cadr(sc->code);
2774 case OP_SET1: /* set! */
2775 y=find_slot_in_env(sc,sc->envir,sc->code,1);
2777 set_slot_in_env(sc, y, sc->value);
2778 s_return(sc,sc->value);
2780 Error_1(sc,"set!: unbound variable:", sc->code);
2784 case OP_BEGIN: /* begin */
2785 if (!is_pair(sc->code)) {
2786 s_return(sc,sc->code);
2788 if (cdr(sc->code) != sc->NIL) {
2789 s_save(sc,OP_BEGIN, sc->NIL, cdr(sc->code));
2791 sc->code = car(sc->code);
2794 case OP_IF0: /* if */
2795 s_save(sc,OP_IF1, sc->NIL, cdr(sc->code));
2796 sc->code = car(sc->code);
2799 case OP_IF1: /* if */
2800 if (is_true(sc->value))
2801 sc->code = car(sc->code);
2803 sc->code = cadr(sc->code); /* (if #f 1) ==> () because
2804 * car(sc->NIL) = sc->NIL */
2807 case OP_LET0: /* let */
2809 sc->value = sc->code;
2810 sc->code = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code);
2813 case OP_LET1: /* let (calculate parameters) */
2814 sc->args = cons(sc, sc->value, sc->args);
2815 if (is_pair(sc->code)) { /* continue */
2816 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
2817 Error_1(sc, "Bad syntax of binding spec in let :",
2820 s_save(sc,OP_LET1, sc->args, cdr(sc->code));
2821 sc->code = cadar(sc->code);
2825 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
2826 sc->code = car(sc->args);
2827 sc->args = cdr(sc->args);
2831 case OP_LET2: /* let */
2832 new_frame_in_env(sc, sc->envir);
2833 for (x = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code), y = sc->args;
2834 y != sc->NIL; x = cdr(x), y = cdr(y)) {
2835 new_slot_in_env(sc, caar(x), car(y));
2837 if (is_symbol(car(sc->code))) { /* named let */
2838 for (x = cadr(sc->code), sc->args = sc->NIL; x != sc->NIL; x = cdr(x)) {
2840 Error_1(sc, "Bad syntax of binding in let :", x);
2841 if (!is_list(sc, car(x)))
2842 Error_1(sc, "Bad syntax of binding in let :", car(x));
2843 sc->args = cons(sc, caar(x), sc->args);
2845 x = mk_closure(sc, cons(sc, reverse_in_place(sc, sc->NIL, sc->args), cddr(sc->code)), sc->envir);
2846 new_slot_in_env(sc, car(sc->code), x);
2847 sc->code = cddr(sc->code);
2850 sc->code = cdr(sc->code);
2853 s_goto(sc,OP_BEGIN);
2855 case OP_LET0AST: /* let* */
2856 if (car(sc->code) == sc->NIL) {
2857 new_frame_in_env(sc, sc->envir);
2858 sc->code = cdr(sc->code);
2859 s_goto(sc,OP_BEGIN);
2861 if(!is_pair(car(sc->code)) || !is_pair(caar(sc->code)) || !is_pair(cdaar(sc->code))) {
2862 Error_1(sc,"Bad syntax of binding spec in let* :",car(sc->code));
2864 s_save(sc,OP_LET1AST, cdr(sc->code), car(sc->code));
2865 sc->code = cadaar(sc->code);
2868 case OP_LET1AST: /* let* (make new frame) */
2869 new_frame_in_env(sc, sc->envir);
2870 s_goto(sc,OP_LET2AST);
2872 case OP_LET2AST: /* let* (calculate parameters) */
2873 new_slot_in_env(sc, caar(sc->code), sc->value);
2874 sc->code = cdr(sc->code);
2875 if (is_pair(sc->code)) { /* continue */
2876 s_save(sc,OP_LET2AST, sc->args, sc->code);
2877 sc->code = cadar(sc->code);
2881 sc->code = sc->args;
2883 s_goto(sc,OP_BEGIN);
2886 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
2887 Error_0(sc,sc->strbuff);
2892 static pointer opexe_1(scheme *sc, enum scheme_opcodes op) {
2896 case OP_LET0REC: /* letrec */
2897 new_frame_in_env(sc, sc->envir);
2899 sc->value = sc->code;
2900 sc->code = car(sc->code);
2901 s_goto(sc,OP_LET1REC);
2903 case OP_LET1REC: /* letrec (calculate parameters) */
2904 sc->args = cons(sc, sc->value, sc->args);
2905 if (is_pair(sc->code)) { /* continue */
2906 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
2907 Error_1(sc, "Bad syntax of binding spec in letrec :",
2910 s_save(sc,OP_LET1REC, sc->args, cdr(sc->code));
2911 sc->code = cadar(sc->code);
2915 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
2916 sc->code = car(sc->args);
2917 sc->args = cdr(sc->args);
2918 s_goto(sc,OP_LET2REC);
2921 case OP_LET2REC: /* letrec */
2922 for (x = car(sc->code), y = sc->args; y != sc->NIL; x = cdr(x), y = cdr(y)) {
2923 new_slot_in_env(sc, caar(x), car(y));
2925 sc->code = cdr(sc->code);
2927 s_goto(sc,OP_BEGIN);
2929 case OP_COND0: /* cond */
2930 if (!is_pair(sc->code)) {
2931 Error_0(sc,"syntax error in cond");
2933 s_save(sc,OP_COND1, sc->NIL, sc->code);
2934 sc->code = caar(sc->code);
2937 case OP_COND1: /* cond */
2938 if (is_true(sc->value)) {
2939 if ((sc->code = cdar(sc->code)) == sc->NIL) {
2940 s_return(sc,sc->value);
2942 if(!sc->code || car(sc->code)==sc->FEED_TO) {
2943 if(!is_pair(cdr(sc->code))) {
2944 Error_0(sc,"syntax error in cond");
2946 x=cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL));
2947 sc->code=cons(sc,cadr(sc->code),cons(sc,x,sc->NIL));
2950 s_goto(sc,OP_BEGIN);
2952 if ((sc->code = cdr(sc->code)) == sc->NIL) {
2953 s_return(sc,sc->NIL);
2955 s_save(sc,OP_COND1, sc->NIL, sc->code);
2956 sc->code = caar(sc->code);
2961 case OP_DELAY: /* delay */
2962 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
2963 typeflag(x)=T_PROMISE;
2966 case OP_AND0: /* and */
2967 if (sc->code == sc->NIL) {
2970 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
2971 sc->code = car(sc->code);
2974 case OP_AND1: /* and */
2975 if (is_false(sc->value)) {
2976 s_return(sc,sc->value);
2977 } else if (sc->code == sc->NIL) {
2978 s_return(sc,sc->value);
2980 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
2981 sc->code = car(sc->code);
2985 case OP_OR0: /* or */
2986 if (sc->code == sc->NIL) {
2989 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
2990 sc->code = car(sc->code);
2993 case OP_OR1: /* or */
2994 if (is_true(sc->value)) {
2995 s_return(sc,sc->value);
2996 } else if (sc->code == sc->NIL) {
2997 s_return(sc,sc->value);
2999 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
3000 sc->code = car(sc->code);
3004 case OP_C0STREAM: /* cons-stream */
3005 s_save(sc,OP_C1STREAM, sc->NIL, cdr(sc->code));
3006 sc->code = car(sc->code);
3009 case OP_C1STREAM: /* cons-stream */
3010 sc->args = sc->value; /* save sc->value to register sc->args for gc */
3011 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
3012 typeflag(x)=T_PROMISE;
3013 s_return(sc,cons(sc, sc->args, x));
3015 case OP_MACRO0: /* macro */
3016 if (is_pair(car(sc->code))) {
3018 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
3021 sc->code = cadr(sc->code);
3023 if (!is_symbol(x)) {
3024 Error_0(sc,"variable is not a symbol");
3026 s_save(sc,OP_MACRO1, sc->NIL, x);
3029 case OP_MACRO1: /* macro */
3030 typeflag(sc->value) = T_MACRO;
3031 x = find_slot_in_env(sc, sc->envir, sc->code, 0);
3033 set_slot_in_env(sc, x, sc->value);
3035 new_slot_in_env(sc, sc->code, sc->value);
3037 s_return(sc,sc->code);
3039 case OP_CASE0: /* case */
3040 s_save(sc,OP_CASE1, sc->NIL, cdr(sc->code));
3041 sc->code = car(sc->code);
3044 case OP_CASE1: /* case */
3045 for (x = sc->code; x != sc->NIL; x = cdr(x)) {
3046 if (!is_pair(y = caar(x))) {
3049 for ( ; y != sc->NIL; y = cdr(y)) {
3050 if (eqv(car(y), sc->value)) {
3059 if (is_pair(caar(x))) {
3061 s_goto(sc,OP_BEGIN);
3063 s_save(sc,OP_CASE2, sc->NIL, cdar(x));
3068 s_return(sc,sc->NIL);
3071 case OP_CASE2: /* case */
3072 if (is_true(sc->value)) {
3073 s_goto(sc,OP_BEGIN);
3075 s_return(sc,sc->NIL);
3078 case OP_PAPPLY: /* apply */
3079 sc->code = car(sc->args);
3080 sc->args = list_star(sc,cdr(sc->args));
3081 /*sc->args = cadr(sc->args);*/
3082 s_goto(sc,OP_APPLY);
3084 case OP_PEVAL: /* eval */
3085 if(cdr(sc->args)!=sc->NIL) {
3086 sc->envir=cadr(sc->args);
3088 sc->code = car(sc->args);
3091 case OP_CONTINUATION: /* call-with-current-continuation */
3092 sc->code = car(sc->args);
3093 sc->args = cons(sc, mk_continuation(sc, sc->dump), sc->NIL);
3094 s_goto(sc,OP_APPLY);
3097 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3098 Error_0(sc,sc->strbuff);
3103 static pointer opexe_2(scheme *sc, enum scheme_opcodes op) {
3112 case OP_INEX2EX: /* inexact->exact */
3114 if(num_is_integer(x)) {
3116 } else if(modf(rvalue_unchecked(x),&dd)==0.0) {
3117 s_return(sc,mk_integer(sc,ivalue(x)));
3119 Error_1(sc,"inexact->exact: not integral:",x);
3124 s_return(sc, mk_real(sc, exp(rvalue(x))));
3128 s_return(sc, mk_real(sc, log(rvalue(x))));
3132 s_return(sc, mk_real(sc, sin(rvalue(x))));
3136 s_return(sc, mk_real(sc, cos(rvalue(x))));
3140 s_return(sc, mk_real(sc, tan(rvalue(x))));
3144 s_return(sc, mk_real(sc, asin(rvalue(x))));
3148 s_return(sc, mk_real(sc, acos(rvalue(x))));
3152 if(cdr(sc->args)==sc->NIL) {
3153 s_return(sc, mk_real(sc, atan(rvalue(x))));
3155 pointer y=cadr(sc->args);
3156 s_return(sc, mk_real(sc, atan2(rvalue(x),rvalue(y))));
3161 s_return(sc, mk_real(sc, sqrt(rvalue(x))));
3166 pointer y=cadr(sc->args);
3168 if (num_is_integer(x) && num_is_integer(y))
3170 /* This 'if' is an R5RS compatibility fix. */
3171 /* NOTE: Remove this 'if' fix for R6RS. */
3172 if (rvalue(x) == 0 && rvalue(y) < 0) {
3175 result = pow(rvalue(x),rvalue(y));
3177 /* Before returning integer result make sure we can. */
3178 /* If the test fails, result is too big for integer. */
3181 long result_as_long = (long)result;
3182 if (result != (double)result_as_long)
3186 s_return(sc, mk_real(sc, result));
3188 s_return(sc, mk_integer(sc, result));
3194 s_return(sc, mk_real(sc, floor(rvalue(x))));
3198 s_return(sc, mk_real(sc, ceil(rvalue(x))));
3200 case OP_TRUNCATE : {
3201 double rvalue_of_x ;
3203 rvalue_of_x = rvalue(x) ;
3204 if (rvalue_of_x > 0) {
3205 s_return(sc, mk_real(sc, floor(rvalue_of_x)));
3207 s_return(sc, mk_real(sc, ceil(rvalue_of_x)));
3213 if (num_is_integer(x))
3215 s_return(sc, mk_real(sc, round_per_R5RS(rvalue(x))));
3218 case OP_ADD: /* + */
3220 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
3221 v=num_add(v,nvalue(car(x)));
3223 s_return(sc,mk_number(sc, v));
3225 case OP_MUL: /* * */
3227 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
3228 v=num_mul(v,nvalue(car(x)));
3230 s_return(sc,mk_number(sc, v));
3232 case OP_SUB: /* - */
3233 if(cdr(sc->args)==sc->NIL) {
3238 v = nvalue(car(sc->args));
3240 for (; x != sc->NIL; x = cdr(x)) {
3241 v=num_sub(v,nvalue(car(x)));
3243 s_return(sc,mk_number(sc, v));
3245 case OP_DIV: /* / */
3246 if(cdr(sc->args)==sc->NIL) {
3251 v = nvalue(car(sc->args));
3253 for (; x != sc->NIL; x = cdr(x)) {
3254 if (!is_zero_double(rvalue(car(x))))
3255 v=num_div(v,nvalue(car(x)));
3257 Error_0(sc,"/: division by zero");
3260 s_return(sc,mk_number(sc, v));
3262 case OP_INTDIV: /* quotient */
3263 if(cdr(sc->args)==sc->NIL) {
3268 v = nvalue(car(sc->args));
3270 for (; x != sc->NIL; x = cdr(x)) {
3271 if (ivalue(car(x)) != 0)
3272 v=num_intdiv(v,nvalue(car(x)));
3274 Error_0(sc,"quotient: division by zero");
3277 s_return(sc,mk_number(sc, v));
3279 case OP_REM: /* remainder */
3280 v = nvalue(car(sc->args));
3281 if (ivalue(cadr(sc->args)) != 0)
3282 v=num_rem(v,nvalue(cadr(sc->args)));
3284 Error_0(sc,"remainder: division by zero");
3286 s_return(sc,mk_number(sc, v));
3288 case OP_MOD: /* modulo */
3289 v = nvalue(car(sc->args));
3290 if (ivalue(cadr(sc->args)) != 0)
3291 v=num_mod(v,nvalue(cadr(sc->args)));
3293 Error_0(sc,"modulo: division by zero");
3295 s_return(sc,mk_number(sc, v));
3297 case OP_CAR: /* car */
3298 s_return(sc,caar(sc->args));
3300 case OP_CDR: /* cdr */
3301 s_return(sc,cdar(sc->args));
3303 case OP_CONS: /* cons */
3304 cdr(sc->args) = cadr(sc->args);
3305 s_return(sc,sc->args);
3307 case OP_SETCAR: /* set-car! */
3308 if(!is_immutable(car(sc->args))) {
3309 caar(sc->args) = cadr(sc->args);
3310 s_return(sc,car(sc->args));
3312 Error_0(sc,"set-car!: unable to alter immutable pair");
3315 case OP_SETCDR: /* set-cdr! */
3316 if(!is_immutable(car(sc->args))) {
3317 cdar(sc->args) = cadr(sc->args);
3318 s_return(sc,car(sc->args));
3320 Error_0(sc,"set-cdr!: unable to alter immutable pair");
3323 case OP_CHAR2INT: { /* char->integer */
3325 c=(char)ivalue(car(sc->args));
3326 s_return(sc,mk_integer(sc,(unsigned char)c));
3329 case OP_INT2CHAR: { /* integer->char */
3331 c=(unsigned char)ivalue(car(sc->args));
3332 s_return(sc,mk_character(sc,(char)c));
3335 case OP_CHARUPCASE: {
3337 c=(unsigned char)ivalue(car(sc->args));
3339 s_return(sc,mk_character(sc,(char)c));
3342 case OP_CHARDNCASE: {
3344 c=(unsigned char)ivalue(car(sc->args));
3346 s_return(sc,mk_character(sc,(char)c));
3349 case OP_STR2SYM: /* string->symbol */
3350 s_return(sc,mk_symbol(sc,strvalue(car(sc->args))));
3352 case OP_STR2ATOM: /* string->atom */ {
3353 char *s=strvalue(car(sc->args));
3355 if(cdr(sc->args)!=sc->NIL) {
3356 /* we know cadr(sc->args) is a natural number */
3357 /* see if it is 2, 8, 10, or 16, or error */
3358 pf = ivalue_unchecked(cadr(sc->args));
3359 if(pf == 16 || pf == 10 || pf == 8 || pf == 2) {
3367 Error_1(sc, "string->atom: bad base:", cadr(sc->args));
3368 } else if(*s=='#') /* no use of base! */ {
3369 s_return(sc, mk_sharp_const(sc, s+1));
3371 if (pf == 0 || pf == 10) {
3372 s_return(sc, mk_atom(sc, s));
3376 long iv = strtol(s,&ep,(int )pf);
3378 s_return(sc, mk_integer(sc, iv));
3381 s_return(sc, sc->F);
3387 case OP_SYM2STR: /* symbol->string */
3388 x=mk_string(sc,symname(car(sc->args)));
3392 case OP_ATOM2STR: /* atom->string */ {
3395 if(cdr(sc->args)!=sc->NIL) {
3396 /* we know cadr(sc->args) is a natural number */
3397 /* see if it is 2, 8, 10, or 16, or error */
3398 pf = ivalue_unchecked(cadr(sc->args));
3399 if(is_number(x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2)) {
3407 Error_1(sc, "atom->string: bad base:", cadr(sc->args));
3408 } else if(is_number(x) || is_character(x) || is_string(x) || is_symbol(x)) {
3411 atom2str(sc,x,(int )pf,&p,&len);
3412 s_return(sc,mk_counted_string(sc,p,len));
3414 Error_1(sc, "atom->string: not an atom:", x);
3418 case OP_MKSTRING: { /* make-string */
3422 len=ivalue(car(sc->args));
3424 if(cdr(sc->args)!=sc->NIL) {
3425 fill=charvalue(cadr(sc->args));
3427 s_return(sc,mk_empty_string(sc,len,(char)fill));
3430 case OP_STRLEN: /* string-length */
3431 s_return(sc,mk_integer(sc,strlength(car(sc->args))));
3433 case OP_STRREF: { /* string-ref */
3437 str=strvalue(car(sc->args));
3439 index=ivalue(cadr(sc->args));
3441 if(index>=strlength(car(sc->args))) {
3442 Error_1(sc,"string-ref: out of bounds:",cadr(sc->args));
3445 s_return(sc,mk_character(sc,((unsigned char*)str)[index]));
3448 case OP_STRSET: { /* string-set! */
3453 if(is_immutable(car(sc->args))) {
3454 Error_1(sc,"string-set!: unable to alter immutable string:",car(sc->args));
3456 str=strvalue(car(sc->args));
3458 index=ivalue(cadr(sc->args));
3459 if(index>=strlength(car(sc->args))) {
3460 Error_1(sc,"string-set!: out of bounds:",cadr(sc->args));
3463 c=charvalue(caddr(sc->args));
3466 s_return(sc,car(sc->args));
3469 case OP_STRAPPEND: { /* string-append */
3470 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
3475 /* compute needed length for new string */
3476 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
3477 len += strlength(car(x));
3479 newstr = mk_empty_string(sc, len, ' ');
3480 /* store the contents of the argument strings into the new string */
3481 for (pos = strvalue(newstr), x = sc->args; x != sc->NIL;
3482 pos += strlength(car(x)), x = cdr(x)) {
3483 memcpy(pos, strvalue(car(x)), strlength(car(x)));
3485 s_return(sc, newstr);
3488 case OP_SUBSTR: { /* substring */
3494 str=strvalue(car(sc->args));
3496 index0=ivalue(cadr(sc->args));
3498 if(index0>strlength(car(sc->args))) {
3499 Error_1(sc,"substring: start out of bounds:",cadr(sc->args));
3502 if(cddr(sc->args)!=sc->NIL) {
3503 index1=ivalue(caddr(sc->args));
3504 if(index1>strlength(car(sc->args)) || index1<index0) {
3505 Error_1(sc,"substring: end out of bounds:",caddr(sc->args));
3508 index1=strlength(car(sc->args));
3512 x=mk_empty_string(sc,len,' ');
3513 memcpy(strvalue(x),str+index0,len);
3519 case OP_VECTOR: { /* vector */
3522 int len=list_length(sc,sc->args);
3524 Error_1(sc,"vector: not a proper list:",sc->args);
3526 vec=mk_vector(sc,len);
3527 if(sc->no_memory) { s_return(sc, sc->sink); }
3528 for (x = sc->args, i = 0; is_pair(x); x = cdr(x), i++) {
3529 set_vector_elem(vec,i,car(x));
3534 case OP_MKVECTOR: { /* make-vector */
3535 pointer fill=sc->NIL;
3539 len=ivalue(car(sc->args));
3541 if(cdr(sc->args)!=sc->NIL) {
3542 fill=cadr(sc->args);
3544 vec=mk_vector(sc,len);
3545 if(sc->no_memory) { s_return(sc, sc->sink); }
3547 fill_vector(vec,fill);
3552 case OP_VECLEN: /* vector-length */
3553 s_return(sc,mk_integer(sc,ivalue(car(sc->args))));
3555 case OP_VECREF: { /* vector-ref */
3558 index=ivalue(cadr(sc->args));
3560 if(index>=ivalue(car(sc->args))) {
3561 Error_1(sc,"vector-ref: out of bounds:",cadr(sc->args));
3564 s_return(sc,vector_elem(car(sc->args),index));
3567 case OP_VECSET: { /* vector-set! */
3570 if(is_immutable(car(sc->args))) {
3571 Error_1(sc,"vector-set!: unable to alter immutable vector:",car(sc->args));
3574 index=ivalue(cadr(sc->args));
3575 if(index>=ivalue(car(sc->args))) {
3576 Error_1(sc,"vector-set!: out of bounds:",cadr(sc->args));
3579 set_vector_elem(car(sc->args),index,caddr(sc->args));
3580 s_return(sc,car(sc->args));
3584 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3585 Error_0(sc,sc->strbuff);
3590 static int is_list(scheme *sc, pointer a)
3591 { return list_length(sc,a) >= 0; }
3597 dotted list: -2 minus length before dot
3599 int list_length(scheme *sc, pointer a) {
3606 if (fast == sc->NIL)
3612 if (fast == sc->NIL)
3619 /* Safe because we would have already returned if `fast'
3620 encountered a non-pair. */
3624 /* the fast pointer has looped back around and caught up
3625 with the slow pointer, hence the structure is circular,
3626 not of finite length, and therefore not a list */
3632 static pointer opexe_3(scheme *sc, enum scheme_opcodes op) {
3635 int (*comp_func)(num,num)=0;
3638 case OP_NOT: /* not */
3639 s_retbool(is_false(car(sc->args)));
3640 case OP_BOOLP: /* boolean? */
3641 s_retbool(car(sc->args) == sc->F || car(sc->args) == sc->T);
3642 case OP_EOFOBJP: /* boolean? */
3643 s_retbool(car(sc->args) == sc->EOF_OBJ);
3644 case OP_NULLP: /* null? */
3645 s_retbool(car(sc->args) == sc->NIL);
3646 case OP_NUMEQ: /* = */
3647 case OP_LESS: /* < */
3648 case OP_GRE: /* > */
3649 case OP_LEQ: /* <= */
3650 case OP_GEQ: /* >= */
3652 case OP_NUMEQ: comp_func=num_eq; break;
3653 case OP_LESS: comp_func=num_lt; break;
3654 case OP_GRE: comp_func=num_gt; break;
3655 case OP_LEQ: comp_func=num_le; break;
3656 case OP_GEQ: comp_func=num_ge; break;
3662 for (; x != sc->NIL; x = cdr(x)) {
3663 if(!comp_func(v,nvalue(car(x)))) {
3669 case OP_SYMBOLP: /* symbol? */
3670 s_retbool(is_symbol(car(sc->args)));
3671 case OP_NUMBERP: /* number? */
3672 s_retbool(is_number(car(sc->args)));
3673 case OP_STRINGP: /* string? */
3674 s_retbool(is_string(car(sc->args)));
3675 case OP_INTEGERP: /* integer? */
3676 s_retbool(is_integer(car(sc->args)));
3677 case OP_REALP: /* real? */
3678 s_retbool(is_number(car(sc->args))); /* All numbers are real */
3679 case OP_CHARP: /* char? */
3680 s_retbool(is_character(car(sc->args)));
3681 #if USE_CHAR_CLASSIFIERS
3682 case OP_CHARAP: /* char-alphabetic? */
3683 s_retbool(Cisalpha(ivalue(car(sc->args))));
3684 case OP_CHARNP: /* char-numeric? */
3685 s_retbool(Cisdigit(ivalue(car(sc->args))));
3686 case OP_CHARWP: /* char-whitespace? */
3687 s_retbool(Cisspace(ivalue(car(sc->args))));
3688 case OP_CHARUP: /* char-upper-case? */
3689 s_retbool(Cisupper(ivalue(car(sc->args))));
3690 case OP_CHARLP: /* char-lower-case? */
3691 s_retbool(Cislower(ivalue(car(sc->args))));
3693 case OP_PORTP: /* port? */
3694 s_retbool(is_port(car(sc->args)));
3695 case OP_INPORTP: /* input-port? */
3696 s_retbool(is_inport(car(sc->args)));
3697 case OP_OUTPORTP: /* output-port? */
3698 s_retbool(is_outport(car(sc->args)));
3699 case OP_PROCP: /* procedure? */
3701 * continuation should be procedure by the example
3702 * (call-with-current-continuation procedure?) ==> #t
3703 * in R^3 report sec. 6.9
3705 s_retbool(is_proc(car(sc->args)) || is_closure(car(sc->args))
3706 || is_continuation(car(sc->args)) || is_foreign(car(sc->args)));
3707 case OP_PAIRP: /* pair? */
3708 s_retbool(is_pair(car(sc->args)));
3709 case OP_LISTP: /* list? */
3710 s_retbool(list_length(sc,car(sc->args)) >= 0);
3712 case OP_ENVP: /* environment? */
3713 s_retbool(is_environment(car(sc->args)));
3714 case OP_VECTORP: /* vector? */
3715 s_retbool(is_vector(car(sc->args)));
3716 case OP_EQ: /* eq? */
3717 s_retbool(car(sc->args) == cadr(sc->args));
3718 case OP_EQV: /* eqv? */
3719 s_retbool(eqv(car(sc->args), cadr(sc->args)));
3721 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
3722 Error_0(sc,sc->strbuff);
3727 static pointer opexe_4(scheme *sc, enum scheme_opcodes op) {
3731 case OP_FORCE: /* force */
3732 sc->code = car(sc->args);
3733 if (is_promise(sc->code)) {
3734 /* Should change type to closure here */
3735 s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code);
3737 s_goto(sc,OP_APPLY);
3739 s_return(sc,sc->code);
3742 case OP_SAVE_FORCED: /* Save forced value replacing promise */
3743 memcpy(sc->code,sc->value,sizeof(struct cell));
3744 s_return(sc,sc->value);
3746 case OP_WRITE: /* write */
3747 case OP_DISPLAY: /* display */
3748 case OP_WRITE_CHAR: /* write-char */
3749 if(is_pair(cdr(sc->args))) {
3750 if(cadr(sc->args)!=sc->outport) {
3751 x=cons(sc,sc->outport,sc->NIL);
3752 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
3753 sc->outport=cadr(sc->args);
3756 sc->args = car(sc->args);
3762 s_goto(sc,OP_P0LIST);
3764 case OP_NEWLINE: /* newline */
3765 if(is_pair(sc->args)) {
3766 if(car(sc->args)!=sc->outport) {
3767 x=cons(sc,sc->outport,sc->NIL);
3768 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
3769 sc->outport=car(sc->args);
3775 case OP_ERR0: /* error */
3777 if (!is_string(car(sc->args))) {
3778 sc->args=cons(sc,mk_string(sc," -- "),sc->args);
3779 setimmutable(car(sc->args));
3781 putstr(sc, "Error: ");
3782 putstr(sc, strvalue(car(sc->args)));
3783 sc->args = cdr(sc->args);
3786 case OP_ERR1: /* error */
3788 if (sc->args != sc->NIL) {
3789 s_save(sc,OP_ERR1, cdr(sc->args), sc->NIL);
3790 sc->args = car(sc->args);
3792 s_goto(sc,OP_P0LIST);
3795 if(sc->interactive_repl) {
3796 s_goto(sc,OP_T0LVL);
3802 case OP_REVERSE: /* reverse */
3803 s_return(sc,reverse(sc, car(sc->args)));
3805 case OP_LIST_STAR: /* list* */
3806 s_return(sc,list_star(sc,sc->args));
3808 case OP_APPEND: /* append */
3815 /* cdr() in the while condition is not a typo. If car() */
3816 /* is used (append '() 'a) will return the wrong result.*/
3817 while (cdr(y) != sc->NIL) {
3818 x = revappend(sc, x, car(y));
3821 Error_0(sc, "non-list argument to append");
3825 s_return(sc, reverse_in_place(sc, car(y), x));
3828 case OP_PUT: /* put */
3829 if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) {
3830 Error_0(sc,"illegal use of put");
3832 for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) {
3838 cdar(x) = caddr(sc->args);
3840 symprop(car(sc->args)) = cons(sc, cons(sc, y, caddr(sc->args)),
3841 symprop(car(sc->args)));
3844 case OP_GET: /* get */
3845 if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) {
3846 Error_0(sc,"illegal use of get");
3848 for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) {
3854 s_return(sc,cdar(x));
3856 s_return(sc,sc->NIL);
3858 #endif /* USE_PLIST */
3859 case OP_QUIT: /* quit */
3860 if(is_pair(sc->args)) {
3861 sc->retcode=ivalue(car(sc->args));
3865 case OP_GC: /* gc */
3866 gc(sc, sc->NIL, sc->NIL);
3869 case OP_GCVERB: /* gc-verbose */
3870 { int was = sc->gc_verbose;
3872 sc->gc_verbose = (car(sc->args) != sc->F);
3876 case OP_NEWSEGMENT: /* new-segment */
3877 if (!is_pair(sc->args) || !is_number(car(sc->args))) {
3878 Error_0(sc,"new-segment: argument must be a number");
3880 alloc_cellseg(sc, (int) ivalue(car(sc->args)));
3883 case OP_OBLIST: /* oblist */
3884 s_return(sc, oblist_all_symbols(sc));
3886 case OP_CURR_INPORT: /* current-input-port */
3887 s_return(sc,sc->inport);
3889 case OP_CURR_OUTPORT: /* current-output-port */
3890 s_return(sc,sc->outport);
3892 case OP_OPEN_INFILE: /* open-input-file */
3893 case OP_OPEN_OUTFILE: /* open-output-file */
3894 case OP_OPEN_INOUTFILE: /* open-input-output-file */ {
3898 case OP_OPEN_INFILE: prop=port_input; break;
3899 case OP_OPEN_OUTFILE: prop=port_output; break;
3900 case OP_OPEN_INOUTFILE: prop=port_input|port_output; break;
3902 p=port_from_filename(sc,strvalue(car(sc->args)),prop);
3909 #if USE_STRING_PORTS
3910 case OP_OPEN_INSTRING: /* open-input-string */
3911 case OP_OPEN_INOUTSTRING: /* open-input-output-string */ {
3915 case OP_OPEN_INSTRING: prop=port_input; break;
3916 case OP_OPEN_INOUTSTRING: prop=port_input|port_output; break;
3918 p=port_from_string(sc, strvalue(car(sc->args)),
3919 strvalue(car(sc->args))+strlength(car(sc->args)), prop);
3925 case OP_OPEN_OUTSTRING: /* open-output-string */ {
3927 if(car(sc->args)==sc->NIL) {
3928 p=port_from_scratch(sc);
3933 p=port_from_string(sc, strvalue(car(sc->args)),
3934 strvalue(car(sc->args))+strlength(car(sc->args)),
3942 case OP_GET_OUTSTRING: /* get-output-string */ {
3945 if ((p=car(sc->args)->_object._port)->kind&port_string) {
3949 size=p->rep.string.curr-p->rep.string.start+1;
3950 str=sc->malloc(size);
3954 memcpy(str,p->rep.string.start,size-1);
3956 s=mk_string(sc,str);
3965 case OP_CLOSE_INPORT: /* close-input-port */
3966 port_close(sc,car(sc->args),port_input);
3969 case OP_CLOSE_OUTPORT: /* close-output-port */
3970 port_close(sc,car(sc->args),port_output);
3973 case OP_INT_ENV: /* interaction-environment */
3974 s_return(sc,sc->global_env);
3976 case OP_CURR_ENV: /* current-environment */
3977 s_return(sc,sc->envir);
3983 static pointer opexe_5(scheme *sc, enum scheme_opcodes op) {
3986 if(sc->nesting!=0) {
3990 Error_1(sc,"unmatched parentheses:",mk_integer(sc,n));
3994 /* ========== reading part ========== */
3996 if(!is_pair(sc->args)) {
3997 s_goto(sc,OP_READ_INTERNAL);
3999 if(!is_inport(car(sc->args))) {
4000 Error_1(sc,"read: not an input port:",car(sc->args));
4002 if(car(sc->args)==sc->inport) {
4003 s_goto(sc,OP_READ_INTERNAL);
4006 sc->inport=car(sc->args);
4007 x=cons(sc,x,sc->NIL);
4008 s_save(sc,OP_SET_INPORT, x, sc->NIL);
4009 s_goto(sc,OP_READ_INTERNAL);
4011 case OP_READ_CHAR: /* read-char */
4012 case OP_PEEK_CHAR: /* peek-char */ {
4014 if(is_pair(sc->args)) {
4015 if(car(sc->args)!=sc->inport) {
4017 x=cons(sc,x,sc->NIL);
4018 s_save(sc,OP_SET_INPORT, x, sc->NIL);
4019 sc->inport=car(sc->args);
4024 s_return(sc,sc->EOF_OBJ);
4026 if(sc->op==OP_PEEK_CHAR) {
4029 s_return(sc,mk_character(sc,c));
4032 case OP_CHAR_READY: /* char-ready? */ {
4033 pointer p=sc->inport;
4035 if(is_pair(sc->args)) {
4038 res=p->_object._port->kind&port_string;
4042 case OP_SET_INPORT: /* set-input-port */
4043 sc->inport=car(sc->args);
4044 s_return(sc,sc->value);
4046 case OP_SET_OUTPORT: /* set-output-port */
4047 sc->outport=car(sc->args);
4048 s_return(sc,sc->value);
4053 s_return(sc,sc->EOF_OBJ);
4056 * Commented out because we now skip comments in the scanner
4060 while ((c=inchar(sc)) != '\n' && c!=EOF)
4062 sc->tok = token(sc);
4063 s_goto(sc,OP_RDSEXPR);
4067 s_save(sc,OP_RDVEC,sc->NIL,sc->NIL);
4070 sc->tok = token(sc);
4071 if (sc->tok == TOK_RPAREN) {
4072 s_return(sc,sc->NIL);
4073 } else if (sc->tok == TOK_DOT) {
4074 Error_0(sc,"syntax error: illegal dot expression");
4076 sc->nesting_stack[sc->file_i]++;
4077 s_save(sc,OP_RDLIST, sc->NIL, sc->NIL);
4078 s_goto(sc,OP_RDSEXPR);
4081 s_save(sc,OP_RDQUOTE, sc->NIL, sc->NIL);
4082 sc->tok = token(sc);
4083 s_goto(sc,OP_RDSEXPR);
4085 sc->tok = token(sc);
4086 if(sc->tok==TOK_VEC) {
4087 s_save(sc,OP_RDQQUOTEVEC, sc->NIL, sc->NIL);
4089 s_goto(sc,OP_RDSEXPR);
4091 s_save(sc,OP_RDQQUOTE, sc->NIL, sc->NIL);
4093 s_goto(sc,OP_RDSEXPR);
4095 s_save(sc,OP_RDUNQUOTE, sc->NIL, sc->NIL);
4096 sc->tok = token(sc);
4097 s_goto(sc,OP_RDSEXPR);
4099 s_save(sc,OP_RDUQTSP, sc->NIL, sc->NIL);
4100 sc->tok = token(sc);
4101 s_goto(sc,OP_RDSEXPR);
4103 s_return(sc,mk_atom(sc, readstr_upto(sc, DELIMITERS)));
4107 Error_0(sc,"Error reading string");
4112 pointer f=find_slot_in_env(sc,sc->envir,sc->SHARP_HOOK,1);
4114 Error_0(sc,"undefined sharp expression");
4116 sc->code=cons(sc,slot_value_in_env(f),sc->NIL);
4120 case TOK_SHARP_CONST:
4121 if ((x = mk_sharp_const(sc, readstr_upto(sc, DELIMITERS))) == sc->NIL) {
4122 Error_0(sc,"undefined sharp expression");
4127 Error_0(sc,"syntax error: illegal token");
4132 sc->args = cons(sc, sc->value, sc->args);
4133 sc->tok = token(sc);
4134 /* We now skip comments in the scanner
4135 while (sc->tok == TOK_COMMENT) {
4137 while ((c=inchar(sc)) != '\n' && c!=EOF)
4139 sc->tok = token(sc);
4142 if (sc->tok == TOK_EOF)
4143 { s_return(sc,sc->EOF_OBJ); }
4144 else if (sc->tok == TOK_RPAREN) {
4149 else if (sc->load_stack[sc->file_i].kind & port_file)
4150 sc->load_stack[sc->file_i].rep.stdio.curr_line++;
4152 sc->nesting_stack[sc->file_i]--;
4153 s_return(sc,reverse_in_place(sc, sc->NIL, sc->args));
4154 } else if (sc->tok == TOK_DOT) {
4155 s_save(sc,OP_RDDOT, sc->args, sc->NIL);
4156 sc->tok = token(sc);
4157 s_goto(sc,OP_RDSEXPR);
4159 s_save(sc,OP_RDLIST, sc->args, sc->NIL);;
4160 s_goto(sc,OP_RDSEXPR);
4165 if (token(sc) != TOK_RPAREN) {
4166 Error_0(sc,"syntax error: illegal dot expression");
4168 sc->nesting_stack[sc->file_i]--;
4169 s_return(sc,reverse_in_place(sc, sc->value, sc->args));
4173 s_return(sc,cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL)));
4176 s_return(sc,cons(sc, sc->QQUOTE, cons(sc, sc->value, sc->NIL)));
4178 case OP_RDQQUOTEVEC:
4179 s_return(sc,cons(sc, mk_symbol(sc,"apply"),
4180 cons(sc, mk_symbol(sc,"vector"),
4181 cons(sc,cons(sc, sc->QQUOTE,
4182 cons(sc,sc->value,sc->NIL)),
4186 s_return(sc,cons(sc, sc->UNQUOTE, cons(sc, sc->value, sc->NIL)));
4189 s_return(sc,cons(sc, sc->UNQUOTESP, cons(sc, sc->value, sc->NIL)));
4192 /*sc->code=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
4193 s_goto(sc,OP_EVAL); Cannot be quoted*/
4194 /*x=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
4195 s_return(sc,x); Cannot be part of pairs*/
4196 /*sc->code=mk_proc(sc,OP_VECTOR);
4198 s_goto(sc,OP_APPLY);*/
4200 s_goto(sc,OP_VECTOR);
4202 /* ========== printing part ========== */
4204 if(is_vector(sc->args)) {
4206 sc->args=cons(sc,sc->args,mk_integer(sc,0));
4207 s_goto(sc,OP_PVECFROM);
4208 } else if(is_environment(sc->args)) {
4209 putstr(sc,"#<ENVIRONMENT>");
4211 } else if (!is_pair(sc->args)) {
4212 printatom(sc, sc->args, sc->print_flag);
4214 } else if (car(sc->args) == sc->QUOTE && ok_abbrev(cdr(sc->args))) {
4216 sc->args = cadr(sc->args);
4217 s_goto(sc,OP_P0LIST);
4218 } else if (car(sc->args) == sc->QQUOTE && ok_abbrev(cdr(sc->args))) {
4220 sc->args = cadr(sc->args);
4221 s_goto(sc,OP_P0LIST);
4222 } else if (car(sc->args) == sc->UNQUOTE && ok_abbrev(cdr(sc->args))) {
4224 sc->args = cadr(sc->args);
4225 s_goto(sc,OP_P0LIST);
4226 } else if (car(sc->args) == sc->UNQUOTESP && ok_abbrev(cdr(sc->args))) {
4228 sc->args = cadr(sc->args);
4229 s_goto(sc,OP_P0LIST);
4232 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
4233 sc->args = car(sc->args);
4234 s_goto(sc,OP_P0LIST);
4238 if (is_pair(sc->args)) {
4239 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
4241 sc->args = car(sc->args);
4242 s_goto(sc,OP_P0LIST);
4243 } else if(is_vector(sc->args)) {
4244 s_save(sc,OP_P1LIST,sc->NIL,sc->NIL);
4246 s_goto(sc,OP_P0LIST);
4248 if (sc->args != sc->NIL) {
4250 printatom(sc, sc->args, sc->print_flag);
4256 int i=ivalue_unchecked(cdr(sc->args));
4257 pointer vec=car(sc->args);
4258 int len=ivalue_unchecked(vec);
4263 pointer elem=vector_elem(vec,i);
4264 ivalue_unchecked(cdr(sc->args))=i+1;
4265 s_save(sc,OP_PVECFROM, sc->args, sc->NIL);
4269 s_goto(sc,OP_P0LIST);
4274 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
4275 Error_0(sc,sc->strbuff);
4281 static pointer opexe_6(scheme *sc, enum scheme_opcodes op) {
4286 case OP_LIST_LENGTH: /* length */ /* a.k */
4287 v=list_length(sc,car(sc->args));
4289 Error_1(sc,"length: not a list:",car(sc->args));
4291 s_return(sc,mk_integer(sc, v));
4293 case OP_ASSQ: /* assq */ /* a.k */
4295 for (y = cadr(sc->args); is_pair(y); y = cdr(y)) {
4296 if (!is_pair(car(y))) {
4297 Error_0(sc,"unable to handle non pair element");
4303 s_return(sc,car(y));
4309 case OP_GET_CLOSURE: /* get-closure-code */ /* a.k */
4310 sc->args = car(sc->args);
4311 if (sc->args == sc->NIL) {
4313 } else if (is_closure(sc->args)) {
4314 s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value)));
4315 } else if (is_macro(sc->args)) {
4316 s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value)));
4320 case OP_CLOSUREP: /* closure? */
4322 * Note, macro object is also a closure.
4323 * Therefore, (closure? <#MACRO>) ==> #t
4325 s_retbool(is_closure(car(sc->args)));
4326 case OP_MACROP: /* macro? */
4327 s_retbool(is_macro(car(sc->args)));
4329 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
4330 Error_0(sc,sc->strbuff);
4332 return sc->T; /* NOTREACHED */
4335 typedef pointer (*dispatch_func)(scheme *, enum scheme_opcodes);
4337 typedef int (*test_predicate)(pointer);
4338 static int is_any(pointer p) { return 1;}
4340 static int is_nonneg(pointer p) {
4341 return ivalue(p)>=0 && is_integer(p);
4344 /* Correspond carefully with following defines! */
4351 {is_string, "string"},
4352 {is_symbol, "symbol"},
4354 {is_inport,"input port"},
4355 {is_outport,"output port"},
4356 {is_environment, "environment"},
4359 {is_character, "character"},
4360 {is_vector, "vector"},
4361 {is_number, "number"},
4362 {is_integer, "integer"},
4363 {is_nonneg, "non-negative integer"}
4367 #define TST_ANY "\001"
4368 #define TST_STRING "\002"
4369 #define TST_SYMBOL "\003"
4370 #define TST_PORT "\004"
4371 #define TST_INPORT "\005"
4372 #define TST_OUTPORT "\006"
4373 #define TST_ENVIRONMENT "\007"
4374 #define TST_PAIR "\010"
4375 #define TST_LIST "\011"
4376 #define TST_CHAR "\012"
4377 #define TST_VECTOR "\013"
4378 #define TST_NUMBER "\014"
4379 #define TST_INTEGER "\015"
4380 #define TST_NATURAL "\016"
4387 char *arg_tests_encoding;
4390 #define INF_ARG 0xffff
4392 static op_code_info dispatch_table[]= {
4393 #define _OP_DEF(A,B,C,D,E,OP) {A,B,C,D,E},
4394 #include "opdefines.h"
4398 static const char *procname(pointer x) {
4400 const char *name=dispatch_table[n].name;
4407 /* kernel of this interpreter */
4408 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op) {
4411 op_code_info *pcd=dispatch_table+sc->op;
4412 if (pcd->name!=0) { /* if built-in function, check arguments */
4413 char msg[STRBUFFSIZE];
4415 int n=list_length(sc,sc->args);
4417 /* Check number of arguments */
4418 if(n<pcd->min_arity) {
4420 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
4422 pcd->min_arity==pcd->max_arity?"":" at least",
4425 if(ok && n>pcd->max_arity) {
4427 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
4429 pcd->min_arity==pcd->max_arity?"":" at most",
4433 if(pcd->arg_tests_encoding!=0) {
4436 const char *t=pcd->arg_tests_encoding;
4437 pointer arglist=sc->args;
4439 pointer arg=car(arglist);
4441 if(j==TST_LIST[0]) {
4442 if(arg!=sc->NIL && !is_pair(arg)) break;
4444 if(!tests[j].fct(arg)) break;
4447 if(t[1]!=0) {/* last test is replicated as necessary */
4450 arglist=cdr(arglist);
4455 snprintf(msg, STRBUFFSIZE, "%s: argument %d must be: %s",
4463 if(_Error_1(sc,msg,0)==sc->NIL) {
4466 pcd=dispatch_table+sc->op;
4469 ok_to_freely_gc(sc);
4470 if (pcd->func(sc, (enum scheme_opcodes)sc->op) == sc->NIL) {
4474 fprintf(stderr,"No memory!\n");
4480 /* ========== Initialization of internal keywords ========== */
4482 static void assign_syntax(scheme *sc, char *name) {
4485 x = oblist_add_by_name(sc, name);
4486 typeflag(x) |= T_SYNTAX;
4489 static void assign_proc(scheme *sc, enum scheme_opcodes op, char *name) {
4492 x = mk_symbol(sc, name);
4494 new_slot_in_env(sc, x, y);
4497 static pointer mk_proc(scheme *sc, enum scheme_opcodes op) {
4500 y = get_cell(sc, sc->NIL, sc->NIL);
4501 typeflag(y) = (T_PROC | T_ATOM);
4502 ivalue_unchecked(y) = (long) op;
4507 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
4508 static int syntaxnum(pointer p) {
4509 const char *s=strvalue(car(p));
4510 switch(strlength(car(p))) {
4512 if(s[0]=='i') return OP_IF0; /* if */
4513 else return OP_OR0; /* or */
4515 if(s[0]=='a') return OP_AND0; /* and */
4516 else return OP_LET0; /* let */
4519 case 'e': return OP_CASE0; /* case */
4520 case 'd': return OP_COND0; /* cond */
4521 case '*': return OP_LET0AST; /* let* */
4522 default: return OP_SET0; /* set! */
4526 case 'g': return OP_BEGIN; /* begin */
4527 case 'l': return OP_DELAY; /* delay */
4528 case 'c': return OP_MACRO0; /* macro */
4529 default: return OP_QUOTE; /* quote */
4533 case 'm': return OP_LAMBDA; /* lambda */
4534 case 'f': return OP_DEF0; /* define */
4535 default: return OP_LET0REC; /* letrec */
4538 return OP_C0STREAM; /* cons-stream */
4542 /* initialization of TinyScheme */
4544 INTERFACE static pointer s_cons(scheme *sc, pointer a, pointer b) {
4545 return cons(sc,a,b);
4547 INTERFACE static pointer s_immutable_cons(scheme *sc, pointer a, pointer b) {
4548 return immutable_cons(sc,a,b);
4551 static struct scheme_interface vtbl ={
4615 scheme *scheme_init_new() {
4616 scheme *sc=(scheme*)malloc(sizeof(scheme));
4617 if(!scheme_init(sc)) {
4625 scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free) {
4626 scheme *sc=(scheme*)malloc(sizeof(scheme));
4627 if(!scheme_init_custom_alloc(sc,malloc,free)) {
4636 int scheme_init(scheme *sc) {
4637 return scheme_init_custom_alloc(sc,malloc,free);
4640 int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
4641 int i, n=sizeof(dispatch_table)/sizeof(dispatch_table[0]);
4644 num_zero.is_fixnum=1;
4645 num_zero.value.ivalue=0;
4646 num_one.is_fixnum=1;
4647 num_one.value.ivalue=1;
4655 sc->last_cell_seg = -1;
4656 sc->sink = &sc->_sink;
4657 sc->NIL = &sc->_NIL;
4658 sc->T = &sc->_HASHT;
4659 sc->F = &sc->_HASHF;
4660 sc->EOF_OBJ=&sc->_EOF_OBJ;
4661 sc->free_cell = &sc->_NIL;
4665 sc->outport=sc->NIL;
4666 sc->save_inport=sc->NIL;
4667 sc->loadport=sc->NIL;
4669 sc->interactive_repl=0;
4671 if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
4676 dump_stack_initialize(sc);
4681 typeflag(sc->NIL) = (T_ATOM | MARK);
4682 car(sc->NIL) = cdr(sc->NIL) = sc->NIL;
4684 typeflag(sc->T) = (T_ATOM | MARK);
4685 car(sc->T) = cdr(sc->T) = sc->T;
4687 typeflag(sc->F) = (T_ATOM | MARK);
4688 car(sc->F) = cdr(sc->F) = sc->F;
4690 typeflag(sc->sink) = (T_PAIR | MARK);
4691 car(sc->sink) = sc->NIL;
4693 sc->c_nest = sc->NIL;
4695 sc->oblist = oblist_initial_value(sc);
4696 /* init global_env */
4697 new_frame_in_env(sc, sc->NIL);
4698 sc->global_env = sc->envir;
4700 x = mk_symbol(sc,"else");
4701 new_slot_in_env(sc, x, sc->T);
4703 assign_syntax(sc, "lambda");
4704 assign_syntax(sc, "quote");
4705 assign_syntax(sc, "define");
4706 assign_syntax(sc, "if");
4707 assign_syntax(sc, "begin");
4708 assign_syntax(sc, "set!");
4709 assign_syntax(sc, "let");
4710 assign_syntax(sc, "let*");
4711 assign_syntax(sc, "letrec");
4712 assign_syntax(sc, "cond");
4713 assign_syntax(sc, "delay");
4714 assign_syntax(sc, "and");
4715 assign_syntax(sc, "or");
4716 assign_syntax(sc, "cons-stream");
4717 assign_syntax(sc, "macro");
4718 assign_syntax(sc, "case");
4720 for(i=0; i<n; i++) {
4721 if(dispatch_table[i].name!=0) {
4722 assign_proc(sc, (enum scheme_opcodes)i, dispatch_table[i].name);
4726 /* initialization of global pointers to special symbols */
4727 sc->LAMBDA = mk_symbol(sc, "lambda");
4728 sc->QUOTE = mk_symbol(sc, "quote");
4729 sc->QQUOTE = mk_symbol(sc, "quasiquote");
4730 sc->UNQUOTE = mk_symbol(sc, "unquote");
4731 sc->UNQUOTESP = mk_symbol(sc, "unquote-splicing");
4732 sc->FEED_TO = mk_symbol(sc, "=>");
4733 sc->COLON_HOOK = mk_symbol(sc,"*colon-hook*");
4734 sc->ERROR_HOOK = mk_symbol(sc, "*error-hook*");
4735 sc->SHARP_HOOK = mk_symbol(sc, "*sharp-hook*");
4736 sc->COMPILE_HOOK = mk_symbol(sc, "*compile-hook*");
4738 return !sc->no_memory;
4741 void scheme_set_input_port_file(scheme *sc, FILE *fin) {
4742 sc->inport=port_from_file(sc,fin,port_input);
4745 void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end) {
4746 sc->inport=port_from_string(sc,start,past_the_end,port_input);
4749 void scheme_set_output_port_file(scheme *sc, FILE *fout) {
4750 sc->outport=port_from_file(sc,fout,port_output);
4753 void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end) {
4754 sc->outport=port_from_string(sc,start,past_the_end,port_output);
4757 void scheme_set_external_data(scheme *sc, void *p) {
4761 void scheme_deinit(scheme *sc) {
4769 sc->global_env=sc->NIL;
4770 dump_stack_free(sc);
4775 if(is_port(sc->inport)) {
4776 typeflag(sc->inport) = T_ATOM;
4779 sc->outport=sc->NIL;
4780 if(is_port(sc->save_inport)) {
4781 typeflag(sc->save_inport) = T_ATOM;
4783 sc->save_inport=sc->NIL;
4784 if(is_port(sc->loadport)) {
4785 typeflag(sc->loadport) = T_ATOM;
4787 sc->loadport=sc->NIL;
4789 gc(sc,sc->NIL,sc->NIL);
4791 for(i=0; i<=sc->last_cell_seg; i++) {
4792 sc->free(sc->alloc_seg[i]);
4796 for(i=0; i<=sc->file_i; i++) {
4797 if (sc->load_stack[i].kind & port_file) {
4798 fname = sc->load_stack[i].rep.stdio.filename;
4806 void scheme_load_file(scheme *sc, FILE *fin)
4807 { scheme_load_named_file(sc,fin,0); }
4809 void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename) {
4810 dump_stack_reset(sc);
4811 sc->envir = sc->global_env;
4813 sc->load_stack[0].kind=port_input|port_file;
4814 sc->load_stack[0].rep.stdio.file=fin;
4815 sc->loadport=mk_port(sc,sc->load_stack);
4818 sc->interactive_repl=1;
4822 sc->load_stack[0].rep.stdio.curr_line = 0;
4823 if(fin!=stdin && filename)
4824 sc->load_stack[0].rep.stdio.filename = store_string(sc, strlen(filename), filename, 0);
4826 sc->load_stack[0].rep.stdio.filename = NULL;
4829 sc->inport=sc->loadport;
4830 sc->args = mk_integer(sc,sc->file_i);
4831 Eval_Cycle(sc, OP_T0LVL);
4832 typeflag(sc->loadport)=T_ATOM;
4833 if(sc->retcode==0) {
4834 sc->retcode=sc->nesting!=0;
4838 void scheme_load_string(scheme *sc, const char *cmd) {
4839 dump_stack_reset(sc);
4840 sc->envir = sc->global_env;
4842 sc->load_stack[0].kind=port_input|port_string;
4843 sc->load_stack[0].rep.string.start=(char*)cmd; /* This func respects const */
4844 sc->load_stack[0].rep.string.past_the_end=(char*)cmd+strlen(cmd);
4845 sc->load_stack[0].rep.string.curr=(char*)cmd;
4846 sc->loadport=mk_port(sc,sc->load_stack);
4848 sc->interactive_repl=0;
4849 sc->inport=sc->loadport;
4850 sc->args = mk_integer(sc,sc->file_i);
4851 Eval_Cycle(sc, OP_T0LVL);
4852 typeflag(sc->loadport)=T_ATOM;
4853 if(sc->retcode==0) {
4854 sc->retcode=sc->nesting!=0;
4858 void scheme_define(scheme *sc, pointer envir, pointer symbol, pointer value) {
4861 x=find_slot_in_env(sc,envir,symbol,0);
4863 set_slot_in_env(sc, x, value);
4865 new_slot_spec_in_env(sc, envir, symbol, value);
4870 void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr)
4874 mk_symbol(sc,sr->name),
4875 mk_foreign_func(sc, sr->f));
4878 void scheme_register_foreign_func_list(scheme * sc,
4879 scheme_registerable * list,
4883 for(i = 0; i < count; i++)
4885 scheme_register_foreign_func(sc, list + i);
4889 pointer scheme_apply0(scheme *sc, const char *procname)
4890 { return scheme_eval(sc, cons(sc,mk_symbol(sc,procname),sc->NIL)); }
4892 void save_from_C_call(scheme *sc)
4894 pointer saved_data =
4901 sc->c_nest = cons(sc, saved_data, sc->c_nest);
4902 /* Truncate the dump stack so TS will return here when done, not
4903 directly resume pre-C-call operations. */
4904 dump_stack_reset(sc);
4906 void restore_from_C_call(scheme *sc)
4908 car(sc->sink) = caar(sc->c_nest);
4909 sc->envir = cadar(sc->c_nest);
4910 sc->dump = cdr(cdar(sc->c_nest));
4912 sc->c_nest = cdr(sc->c_nest);
4915 /* "func" and "args" are assumed to be already eval'ed. */
4916 pointer scheme_call(scheme *sc, pointer func, pointer args)
4918 int old_repl = sc->interactive_repl;
4919 sc->interactive_repl = 0;
4920 save_from_C_call(sc);
4921 sc->envir = sc->global_env;
4925 Eval_Cycle(sc, OP_APPLY);
4926 sc->interactive_repl = old_repl;
4927 restore_from_C_call(sc);
4931 pointer scheme_eval(scheme *sc, pointer obj)
4933 int old_repl = sc->interactive_repl;
4934 sc->interactive_repl = 0;
4935 save_from_C_call(sc);
4939 Eval_Cycle(sc, OP_EVAL);
4940 sc->interactive_repl = old_repl;
4941 restore_from_C_call(sc);
4948 /* ========== Main ========== */
4952 #if defined(__APPLE__) && !defined (OSX)
4955 extern MacTS_main(int argc, char **argv);
4957 int argc = ccommand(&argv);
4958 MacTS_main(argc,argv);
4961 int MacTS_main(int argc, char **argv) {
4963 int main(int argc, char **argv) {
4967 char *file_name=InitFile;
4974 if(argc==2 && strcmp(argv[1],"-?")==0) {
4975 printf("Usage: tinyscheme -?\n");
4976 printf("or: tinyscheme [<file1> <file2> ...]\n");
4977 printf("followed by\n");
4978 printf(" -1 <file> [<arg1> <arg2> ...]\n");
4979 printf(" -c <Scheme commands> [<arg1> <arg2> ...]\n");
4980 printf("assuming that the executable is named tinyscheme.\n");
4981 printf("Use - as filename for stdin.\n");
4984 if(!scheme_init(&sc)) {
4985 fprintf(stderr,"Could not initialize!\n");
4988 scheme_set_input_port_file(&sc, stdin);
4989 scheme_set_output_port_file(&sc, stdout);
4991 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"load-extension"),mk_foreign_func(&sc, scm_load_ext));
4994 if(access(file_name,0)!=0) {
4995 char *p=getenv("TINYSCHEMEINIT");
5001 if(strcmp(file_name,"-")==0) {
5003 } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0) {
5004 pointer args=sc.NIL;
5005 isfile=file_name[1]=='1';
5007 if(strcmp(file_name,"-")==0) {
5010 fin=fopen(file_name,"r");
5012 for(;*argv;argv++) {
5013 pointer value=mk_string(&sc,*argv);
5014 args=cons(&sc,value,args);
5016 args=reverse_in_place(&sc,sc.NIL,args);
5017 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args);
5020 fin=fopen(file_name,"r");
5022 if(isfile && fin==0) {
5023 fprintf(stderr,"Could not open file %s\n",file_name);
5026 scheme_load_named_file(&sc,fin,file_name);
5028 scheme_load_string(&sc,file_name);
5030 if(!isfile || fin!=stdin) {
5032 fprintf(stderr,"Errors encountered reading %s\n",file_name);
5040 } while(file_name!=0);
5042 scheme_load_named_file(&sc,stdin,0);