ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.5
Committed: Wed Nov 25 10:50:24 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.4: +1 -3 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1
2     /* T I N Y S C H E M E 1 . 4 1
3     * Dimitrios Souflis (dsouflis@acm.org)
4     * Based on MiniScheme (original credits follow)
5     * (MINISCM) coded by Atsushi Moriwaki (11/5/1989)
6     * (MINISCM) E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp
7     * (MINISCM) This version has been modified by R.C. Secrist.
8     * (MINISCM)
9     * (MINISCM) Mini-Scheme is now maintained by Akira KIDA.
10     * (MINISCM)
11     * (MINISCM) This is a revised and modified version by Akira KIDA.
12     * (MINISCM) current version is 0.85k4 (15 May 1994)
13     *
14     */
15    
16     #define PAGE_SIZE 4096 /* does not work on sparc/alpha */
17     #include "malloc.c"
18    
19     #define SCHEME_SOURCE
20     #include "scheme-private.h"
21     #ifndef WIN32
22     # include <unistd.h>
23     #endif
24     #if USE_MATH
25     # include <math.h>
26     #endif
27    
28     #include <sys/types.h>
29     #include <sys/stat.h>
30     #include <fcntl.h>
31    
32 root 1.2 #include <string.h>
33     #include <stdlib.h>
34    
35 root 1.1 #include <limits.h>
36     #include <inttypes.h>
37     #include <float.h>
38     //#include <ctype.h>
39    
40     enum {
41     TOK_EOF,
42     TOK_LPAREN,
43     TOK_RPAREN,
44     TOK_DOT,
45     TOK_ATOM,
46     TOK_QUOTE,
47     TOK_DQUOTE,
48     TOK_BQUOTE,
49     TOK_COMMA,
50     TOK_ATMARK,
51     TOK_SHARP,
52     TOK_SHARP_CONST,
53     TOK_VEC
54     };
55    
56     #define BACKQUOTE '`'
57     #define DELIMITERS "()\";\f\t\v\n\r "
58    
59     #define NIL (&SCHEME_V->xNIL) //TODO: make this 0?
60 root 1.2 #define S_T (&SCHEME_V->xT) //TODO: magic ptr value?
61     #define S_F (&SCHEME_V->xF) //TODO: magic ptr value?
62 root 1.1 #define S_SINK (&SCHEME_V->xsink)
63     #define S_EOF (&SCHEME_V->xEOF_OBJ)
64    
65     #if !USE_MULTIPLICITY
66     static scheme sc;
67     #endif
68    
69     static void
70     xbase (char *s, long n, int base)
71     {
72     if (n < 0)
73     {
74     *s++ = '-';
75     n = -n;
76     }
77    
78     char *p = s;
79    
80     do {
81     *p++ = '0' + n % base;
82     n /= base;
83     } while (n);
84    
85     *p-- = 0;
86    
87     while (p > s)
88     {
89     char x = *s; *s = *p; *p = x;
90     --p; ++s;
91     }
92     }
93    
94     static void
95     xnum (char *s, long n)
96     {
97     xbase (s, n, 10);
98     }
99    
100     static void
101     xwrstr (const char *s)
102     {
103     write (1, s, strlen (s));
104     }
105    
106     static void
107     xwrnum (long n)
108     {
109     char buf[64];
110    
111     xnum (buf, n);
112     xwrstr (buf);
113     }
114    
115     static char
116     xtoupper (char c)
117     {
118     if (c >= 'a' && c <= 'z')
119     c -= 'a' - 'A';
120    
121     return c;
122     }
123    
124     static char
125     xtolower (char c)
126     {
127     if (c >= 'A' && c <= 'Z')
128     c += 'a' - 'A';
129    
130     return c;
131     }
132    
133     #if USE_STRLWR
134     static const char *
135     strlwr (char *s)
136     {
137     const char *p = s;
138    
139     while (*s)
140     {
141     *s = tolower (*s);
142     s++;
143     }
144    
145     return p;
146     }
147     #endif
148    
149     #define stricmp(a,b) strcmp (a, b)
150     #define strlwr(s) (s)
151     #define toupper(c) xtoupper(c)
152     #define tolower(c) xtolower(c)
153    
154     #ifndef prompt
155     # define prompt "ts> "
156     #endif
157    
158     #ifndef InitFile
159     # define InitFile "init.scm"
160     #endif
161    
162     #ifndef FIRST_CELLSEGS
163     # define FIRST_CELLSEGS 3
164     #endif
165    
166     enum scheme_types
167     {
168 root 1.2 T_FREE,
169 root 1.1 T_STRING,
170     T_NUMBER,
171     T_SYMBOL,
172     T_PROC,
173     T_PAIR,
174     T_CLOSURE,
175     T_CONTINUATION,
176     T_FOREIGN,
177     T_CHARACTER,
178     T_PORT,
179     T_VECTOR,
180     T_MACRO,
181     T_PROMISE,
182     T_ENVIRONMENT,
183 root 1.2 /* one more... */
184 root 1.1 T_NUM_SYSTEM_TYPES
185     };
186    
187 root 1.2 #define T_MASKTYPE 0x000f
188     #define T_SYNTAX 0x0010
189     #define T_IMMUTABLE 0x0020
190     #define T_ATOM 0x0040 /* only for gc */
191     #define T_MARK 0x0080 /* only for gc */
192 root 1.1
193     static num num_add (num a, num b);
194     static num num_mul (num a, num b);
195     static num num_div (num a, num b);
196     static num num_intdiv (num a, num b);
197     static num num_sub (num a, num b);
198     static num num_rem (num a, num b);
199     static num num_mod (num a, num b);
200     static int num_eq (num a, num b);
201     static int num_gt (num a, num b);
202     static int num_ge (num a, num b);
203     static int num_lt (num a, num b);
204     static int num_le (num a, num b);
205    
206     #if USE_MATH
207     static double round_per_R5RS (double x);
208     #endif
209     static int is_zero_rvalue (RVALUE x);
210    
211     static INLINE int
212     num_is_integer (pointer p)
213     {
214     return num_is_fixnum (p->object.number);
215     }
216    
217     static num num_zero;
218     static num num_one;
219    
220     /* macros for cell operations */
221     #define typeflag(p) ((p)->flag + 0)
222     #define set_typeflag(p,v) ((p)->flag = (v))
223     #define type(p) (typeflag (p) & T_MASKTYPE)
224    
225     INTERFACE INLINE int
226     is_string (pointer p)
227     {
228     return type (p) == T_STRING;
229     }
230    
231     #define strvalue(p) ((p)->object.string.svalue)
232     #define strlength(p) ((p)->object.string.length)
233    
234     INTERFACE int is_list (SCHEME_P_ pointer p);
235     INTERFACE INLINE int
236     is_vector (pointer p)
237     {
238     return type (p) == T_VECTOR;
239     }
240    
241     INTERFACE void fill_vector (pointer vec, pointer obj);
242 root 1.3 INTERFACE uint32_t vector_length (pointer vec);
243     INTERFACE pointer vector_elem (pointer vec, uint32_t ielem);
244     INTERFACE void set_vector_elem (pointer vec, uint32_t ielem, pointer a);
245    
246     INTERFACE uint32_t
247     vector_length (pointer vec)
248     {
249     return vec->object.vector.length;
250     }
251 root 1.1
252     INTERFACE INLINE int
253     is_number (pointer p)
254     {
255     return type (p) == T_NUMBER;
256     }
257    
258     INTERFACE INLINE int
259     is_integer (pointer p)
260     {
261     if (!is_number (p))
262     return 0;
263    
264     if (num_is_integer (p) || ivalue (p) == rvalue (p))
265     return 1;
266    
267     return 0;
268     }
269    
270     INTERFACE INLINE int
271     is_real (pointer p)
272     {
273     return is_number (p) && !num_is_fixnum (p->object.number);
274     }
275    
276     INTERFACE INLINE int
277     is_character (pointer p)
278     {
279     return type (p) == T_CHARACTER;
280     }
281    
282     INTERFACE INLINE char *
283     string_value (pointer p)
284     {
285     return strvalue (p);
286     }
287    
288     INLINE num
289     nvalue (pointer p)
290     {
291     return (p)->object.number;
292     }
293    
294 root 1.2 static IVALUE
295     num_get_ivalue (const num n)
296     {
297     return num_is_fixnum (n) ? num_ivalue (n) : (IVALUE)num_rvalue (n);
298     }
299    
300     static RVALUE
301     num_get_rvalue (const num n)
302     {
303     return num_is_fixnum (n) ? (RVALUE)num_ivalue (n) : num_rvalue (n);
304     }
305    
306     INTERFACE IVALUE
307 root 1.1 ivalue (pointer p)
308     {
309 root 1.2 return num_get_ivalue (p->object.number);
310 root 1.1 }
311    
312     INTERFACE RVALUE
313     rvalue (pointer p)
314     {
315 root 1.2 return num_get_rvalue (p->object.number);
316 root 1.1 }
317    
318     #define ivalue_unchecked(p) ((p)->object.number.value.ivalue)
319     #if USE_FLOAT
320     # define rvalue_unchecked(p) ((p)->object.number.value.rvalue)
321     # define set_num_integer(p) (p)->object.number.is_fixnum=1;
322     # define set_num_real(p) (p)->object.number.is_fixnum=0;
323     #else
324     # define rvalue_unchecked(p) ((p)->object.number.value.ivalue)
325     # define set_num_integer(p) 0
326     # define set_num_real(p) 0
327     #endif
328     INTERFACE long
329     charvalue (pointer p)
330     {
331     return ivalue_unchecked (p);
332     }
333    
334     INTERFACE INLINE int
335     is_port (pointer p)
336     {
337     return type (p) == T_PORT;
338     }
339    
340     INTERFACE INLINE int
341     is_inport (pointer p)
342     {
343     return is_port (p) && p->object.port->kind & port_input;
344     }
345    
346     INTERFACE INLINE int
347     is_outport (pointer p)
348     {
349     return is_port (p) && p->object.port->kind & port_output;
350     }
351    
352     INTERFACE INLINE int
353     is_pair (pointer p)
354     {
355     return type (p) == T_PAIR;
356     }
357    
358     #define car(p) ((p)->object.cons.car + 0)
359     #define cdr(p) ((p)->object.cons.cdr) /* find_consecutive_cells uses &cdr */
360    
361     #define caar(p) car (car (p))
362     #define cadr(p) car (cdr (p))
363     #define cdar(p) cdr (car (p))
364     #define cddr(p) cdr (cdr (p))
365    
366     #define cadar(p) car (cdr (car (p)))
367     #define caddr(p) car (cdr (cdr (p)))
368     #define cdaar(p) cdr (car (car (p)))
369    
370     INTERFACE void
371     set_car (pointer p, pointer q)
372     {
373     p->object.cons.car = q;
374     }
375    
376     INTERFACE void
377     set_cdr (pointer p, pointer q)
378     {
379     p->object.cons.cdr = q;
380     }
381    
382     INTERFACE pointer
383     pair_car (pointer p)
384     {
385     return car (p);
386     }
387    
388     INTERFACE pointer
389     pair_cdr (pointer p)
390     {
391     return cdr (p);
392     }
393    
394     INTERFACE INLINE int
395     is_symbol (pointer p)
396     {
397     return type (p) == T_SYMBOL;
398     }
399    
400     INTERFACE INLINE char *
401     symname (pointer p)
402     {
403     return strvalue (car (p));
404     }
405    
406     #if USE_PLIST
407     SCHEME_EXPORT INLINE int
408     hasprop (pointer p)
409     {
410     return typeflag (p) & T_SYMBOL;
411     }
412    
413     # define symprop(p) cdr(p)
414     #endif
415    
416     INTERFACE INLINE int
417     is_syntax (pointer p)
418     {
419     return typeflag (p) & T_SYNTAX;
420     }
421    
422     INTERFACE INLINE int
423     is_proc (pointer p)
424     {
425     return type (p) == T_PROC;
426     }
427    
428     INTERFACE INLINE int
429     is_foreign (pointer p)
430     {
431     return type (p) == T_FOREIGN;
432     }
433    
434     INTERFACE INLINE char *
435     syntaxname (pointer p)
436     {
437     return strvalue (car (p));
438     }
439    
440 root 1.2 #define procnum(p) ivalue (p)
441 root 1.1 static const char *procname (pointer x);
442    
443     INTERFACE INLINE int
444     is_closure (pointer p)
445     {
446     return type (p) == T_CLOSURE;
447     }
448    
449     INTERFACE INLINE int
450     is_macro (pointer p)
451     {
452     return type (p) == T_MACRO;
453     }
454    
455     INTERFACE INLINE pointer
456     closure_code (pointer p)
457     {
458     return car (p);
459     }
460    
461     INTERFACE INLINE pointer
462     closure_env (pointer p)
463     {
464     return cdr (p);
465     }
466    
467     INTERFACE INLINE int
468     is_continuation (pointer p)
469     {
470     return type (p) == T_CONTINUATION;
471     }
472    
473     #define cont_dump(p) cdr (p)
474     #define set_cont_dump(p,v) set_cdr ((p), (v))
475    
476     /* To do: promise should be forced ONCE only */
477     INTERFACE INLINE int
478     is_promise (pointer p)
479     {
480     return type (p) == T_PROMISE;
481     }
482    
483     INTERFACE INLINE int
484     is_environment (pointer p)
485     {
486     return type (p) == T_ENVIRONMENT;
487     }
488    
489     #define setenvironment(p) set_typeflag ((p), T_ENVIRONMENT)
490    
491 root 1.2 #define is_atom1(p) (TYPESET_ATOM & (1U << type (p)))
492 root 1.1 #define is_atom(p) (typeflag (p) & T_ATOM)
493     #define setatom(p) set_typeflag ((p), typeflag (p) | T_ATOM)
494 root 1.2 #define clratom(p) set_typeflag ((p), typeflag (p) & ~T_ATOM)
495    
496     #define is_mark(p) (typeflag (p) & T_MARK)
497     #define setmark(p) set_typeflag ((p), typeflag (p) | T_MARK)
498     #define clrmark(p) set_typeflag ((p), typeflag (p) & ~T_MARK)
499    
500     #if 0
501     static int
502     is_atom(pointer p)
503     {
504     if (!is_atom1(p) != !is_atom2(p))
505     printf ("atoms disagree %x\n", typeflag(p));
506 root 1.1
507 root 1.2 return is_atom2(p);
508     }
509     #endif
510 root 1.1
511     INTERFACE INLINE int
512     is_immutable (pointer p)
513     {
514 root 1.2 return typeflag (p) & T_IMMUTABLE && USE_ERROR_CHECKING;
515 root 1.1 }
516    
517     INTERFACE INLINE void
518     setimmutable (pointer p)
519     {
520 root 1.2 #if USE_ERROR_CHECKING
521     set_typeflag (p, typeflag (p) | T_IMMUTABLE);
522     #endif
523 root 1.1 }
524    
525     #if USE_CHAR_CLASSIFIERS
526     static INLINE int
527     Cisalpha (int c)
528     {
529     return isascii (c) && isalpha (c);
530     }
531    
532     static INLINE int
533     Cisdigit (int c)
534     {
535     return isascii (c) && isdigit (c);
536     }
537    
538     static INLINE int
539     Cisspace (int c)
540     {
541     return isascii (c) && isspace (c);
542     }
543    
544     static INLINE int
545     Cisupper (int c)
546     {
547     return isascii (c) && isupper (c);
548     }
549    
550     static INLINE int
551     Cislower (int c)
552     {
553     return isascii (c) && islower (c);
554     }
555     #endif
556    
557     #if USE_ASCII_NAMES
558     static const char *charnames[32] = {
559     "nul",
560     "soh",
561     "stx",
562     "etx",
563     "eot",
564     "enq",
565     "ack",
566     "bel",
567     "bs",
568     "ht",
569     "lf",
570     "vt",
571     "ff",
572     "cr",
573     "so",
574     "si",
575     "dle",
576     "dc1",
577     "dc2",
578     "dc3",
579     "dc4",
580     "nak",
581     "syn",
582     "etb",
583     "can",
584     "em",
585     "sub",
586     "esc",
587     "fs",
588     "gs",
589     "rs",
590     "us"
591     };
592    
593     static int
594     is_ascii_name (const char *name, int *pc)
595     {
596     int i;
597    
598     for (i = 0; i < 32; i++)
599     {
600     if (stricmp (name, charnames[i]) == 0)
601     {
602     *pc = i;
603     return 1;
604     }
605     }
606    
607     if (stricmp (name, "del") == 0)
608     {
609     *pc = 127;
610     return 1;
611     }
612    
613     return 0;
614     }
615    
616     #endif
617    
618     static int file_push (SCHEME_P_ const char *fname);
619     static void file_pop (SCHEME_P);
620     static int file_interactive (SCHEME_P);
621     static INLINE int is_one_of (char *s, int c);
622     static int alloc_cellseg (SCHEME_P_ int n);
623     static long binary_decode (const char *s);
624     static INLINE pointer get_cell (SCHEME_P_ pointer a, pointer b);
625     static void finalize_cell (SCHEME_P_ pointer a);
626     static int count_consecutive_cells (pointer x, int needed);
627     static pointer find_slot_in_env (SCHEME_P_ pointer env, pointer sym, int all);
628 root 1.2 static pointer mk_number (SCHEME_P_ const num n);
629 root 1.3 static char *store_string (SCHEME_P_ uint32_t len, const char *str, char fill);
630     static pointer mk_vector (SCHEME_P_ uint32_t len);
631 root 1.1 static pointer mk_atom (SCHEME_P_ char *q);
632     static pointer mk_sharp_const (SCHEME_P_ char *name);
633    
634     #if USE_PORTS
635     static pointer mk_port (SCHEME_P_ port *p);
636     static pointer port_from_filename (SCHEME_P_ const char *fn, int prop);
637     static pointer port_from_file (SCHEME_P_ int, int prop);
638     static pointer port_from_string (SCHEME_P_ char *start, char *past_the_end, int prop);
639     static port *port_rep_from_filename (SCHEME_P_ const char *fn, int prop);
640     static port *port_rep_from_file (SCHEME_P_ int, int prop);
641     static port *port_rep_from_string (SCHEME_P_ char *start, char *past_the_end, int prop);
642     static void port_close (SCHEME_P_ pointer p, int flag);
643     #endif
644     static void mark (pointer a);
645     static void gc (SCHEME_P_ pointer a, pointer b);
646     static int basic_inchar (port *pt);
647     static int inchar (SCHEME_P);
648     static void backchar (SCHEME_P_ int c);
649     static char *readstr_upto (SCHEME_P_ char *delim);
650     static pointer readstrexp (SCHEME_P);
651     static INLINE int skipspace (SCHEME_P);
652     static int token (SCHEME_P);
653     static void printslashstring (SCHEME_P_ char *s, int len);
654     static void atom2str (SCHEME_P_ pointer l, int f, char **pp, int *plen);
655     static void printatom (SCHEME_P_ pointer l, int f);
656     static pointer mk_proc (SCHEME_P_ enum scheme_opcodes op);
657     static pointer mk_closure (SCHEME_P_ pointer c, pointer e);
658     static pointer mk_continuation (SCHEME_P_ pointer d);
659     static pointer reverse (SCHEME_P_ pointer a);
660     static pointer reverse_in_place (SCHEME_P_ pointer term, pointer list);
661     static pointer revappend (SCHEME_P_ pointer a, pointer b);
662     static pointer ss_get_cont (SCHEME_P);
663     static void ss_set_cont (SCHEME_P_ pointer cont);
664     static void dump_stack_mark (SCHEME_P);
665     static pointer opexe_0 (SCHEME_P_ enum scheme_opcodes op);
666     static pointer opexe_2 (SCHEME_P_ enum scheme_opcodes op);
667     static pointer opexe_3 (SCHEME_P_ enum scheme_opcodes op);
668     static pointer opexe_4 (SCHEME_P_ enum scheme_opcodes op);
669     static pointer opexe_5 (SCHEME_P_ enum scheme_opcodes op);
670     static pointer opexe_6 (SCHEME_P_ enum scheme_opcodes op);
671     static void Eval_Cycle (SCHEME_P_ enum scheme_opcodes op);
672 root 1.2 static void assign_syntax (SCHEME_P_ const char *name);
673 root 1.1 static int syntaxnum (pointer p);
674 root 1.2 static void assign_proc (SCHEME_P_ enum scheme_opcodes, const char *name);
675 root 1.1
676     static num
677     num_add (num a, num b)
678     {
679     num ret;
680    
681     num_set_fixnum (ret, num_is_fixnum (a) && num_is_fixnum (b));
682    
683     if (num_is_fixnum (ret))
684 root 1.2 num_set_ivalue (ret, num_get_ivalue (a) + num_get_ivalue (b));
685 root 1.1 else
686 root 1.2 num_set_rvalue (ret, num_get_rvalue (a) + num_get_rvalue (b));
687 root 1.1
688     return ret;
689     }
690    
691     static num
692     num_mul (num a, num b)
693     {
694     num ret;
695    
696     num_set_fixnum (ret, num_is_fixnum (a) && num_is_fixnum (b));
697    
698     if (num_is_fixnum (ret))
699 root 1.2 num_set_ivalue (ret, num_get_ivalue (a) * num_get_ivalue (b));
700 root 1.1 else
701 root 1.2 num_set_rvalue (ret, num_get_rvalue (a) * num_get_rvalue (b));
702 root 1.1
703     return ret;
704     }
705    
706     static num
707     num_div (num a, num b)
708     {
709     num ret;
710    
711 root 1.2 num_set_fixnum (ret, num_is_fixnum (a) && num_is_fixnum (b) && num_get_ivalue (a) % num_get_ivalue (b) == 0);
712 root 1.1
713     if (num_is_fixnum (ret))
714 root 1.2 num_set_ivalue (ret, num_get_ivalue (a) / num_get_ivalue (b));
715 root 1.1 else
716 root 1.2 num_set_rvalue (ret, num_get_rvalue (a) / num_get_rvalue (b));
717 root 1.1
718     return ret;
719     }
720    
721     static num
722     num_intdiv (num a, num b)
723     {
724     num ret;
725    
726     num_set_fixnum (ret, num_is_fixnum (a) && num_is_fixnum (b));
727    
728     if (num_is_fixnum (ret))
729 root 1.2 num_set_ivalue (ret, num_get_ivalue (a) / num_get_ivalue (b));
730 root 1.1 else
731 root 1.2 num_set_rvalue (ret, num_get_rvalue (a) / num_get_rvalue (b));
732 root 1.1
733     return ret;
734     }
735    
736     static num
737     num_sub (num a, num b)
738     {
739     num ret;
740    
741     num_set_fixnum (ret, num_is_fixnum (a) && num_is_fixnum (b));
742    
743     if (num_is_fixnum (ret))
744 root 1.2 num_set_ivalue (ret, num_get_ivalue (a) - num_get_ivalue (b));
745 root 1.1 else
746 root 1.2 num_set_rvalue (ret, num_get_rvalue (a) - num_get_rvalue (b));
747 root 1.1
748     return ret;
749     }
750    
751     static num
752     num_rem (num a, num b)
753     {
754     num ret;
755     long e1, e2, res;
756    
757     num_set_fixnum (ret, num_is_fixnum (a) && num_is_fixnum (b));
758 root 1.2 e1 = num_get_ivalue (a);
759     e2 = num_get_ivalue (b);
760 root 1.1 res = e1 % e2;
761    
762     /* remainder should have same sign as second operand */
763     if (res > 0)
764     {
765     if (e1 < 0)
766     res -= labs (e2);
767     }
768     else if (res < 0)
769     {
770     if (e1 > 0)
771     res += labs (e2);
772     }
773    
774     num_set_ivalue (ret, res);
775     return ret;
776     }
777    
778     static num
779     num_mod (num a, num b)
780     {
781     num ret;
782     long e1, e2, res;
783    
784     num_set_fixnum (ret, num_is_fixnum (a) && num_is_fixnum (b));
785 root 1.2 e1 = num_get_ivalue (a);
786     e2 = num_get_ivalue (b);
787 root 1.1 res = e1 % e2;
788    
789     /* modulo should have same sign as second operand */
790     if (res * e2 < 0)
791     res += e2;
792    
793     num_set_ivalue (ret, res);
794     return ret;
795     }
796    
797     static int
798     num_eq (num a, num b)
799     {
800     int ret;
801     int is_fixnum = num_is_fixnum (a) && num_is_fixnum (b);
802    
803     if (is_fixnum)
804 root 1.2 ret = num_get_ivalue (a) == num_get_ivalue (b);
805 root 1.1 else
806 root 1.2 ret = num_get_rvalue (a) == num_get_rvalue (b);
807 root 1.1
808     return ret;
809     }
810    
811    
812     static int
813     num_gt (num a, num b)
814     {
815     int ret;
816     int is_fixnum = num_is_fixnum (a) && num_is_fixnum (b);
817    
818     if (is_fixnum)
819 root 1.2 ret = num_get_ivalue (a) > num_get_ivalue (b);
820 root 1.1 else
821 root 1.2 ret = num_get_rvalue (a) > num_get_rvalue (b);
822 root 1.1
823     return ret;
824     }
825    
826     static int
827     num_ge (num a, num b)
828     {
829     return !num_lt (a, b);
830     }
831    
832     static int
833     num_lt (num a, num b)
834     {
835     int ret;
836     int is_fixnum = num_is_fixnum (a) && num_is_fixnum (b);
837    
838     if (is_fixnum)
839 root 1.2 ret = num_get_ivalue (a) < num_get_ivalue (b);
840 root 1.1 else
841 root 1.2 ret = num_get_rvalue (a) < num_get_rvalue (b);
842 root 1.1
843     return ret;
844     }
845    
846     static int
847     num_le (num a, num b)
848     {
849     return !num_gt (a, b);
850     }
851    
852     #if USE_MATH
853    
854     /* Round to nearest. Round to even if midway */
855     static double
856     round_per_R5RS (double x)
857     {
858     double fl = floor (x);
859     double ce = ceil (x);
860     double dfl = x - fl;
861     double dce = ce - x;
862    
863     if (dfl > dce)
864     return ce;
865     else if (dfl < dce)
866     return fl;
867     else
868     {
869     if (fmod (fl, 2.0) == 0.0) /* I imagine this holds */
870     return fl;
871     else
872     return ce;
873     }
874     }
875     #endif
876    
877     static int
878     is_zero_rvalue (RVALUE x)
879     {
880     #if USE_FLOAT
881     return x < DBL_MIN && x > -DBL_MIN; /* why the hate of denormals? this should be == 0. */
882     #else
883     return x == 0;
884     #endif
885     }
886    
887     static long
888     binary_decode (const char *s)
889     {
890     long x = 0;
891    
892     while (*s != 0 && (*s == '1' || *s == '0'))
893     {
894     x <<= 1;
895     x += *s - '0';
896     s++;
897     }
898    
899     return x;
900     }
901    
902     /* allocate new cell segment */
903     static int
904     alloc_cellseg (SCHEME_P_ int n)
905     {
906     pointer newp;
907     pointer last;
908     pointer p;
909     char *cp;
910     long i;
911     int k;
912    
913     static int segsize = CELL_SEGSIZE >> 1;
914     segsize <<= 1;
915    
916     for (k = 0; k < n; k++)
917     {
918     if (SCHEME_V->last_cell_seg >= CELL_NSEGMENT - 1)
919     return k;
920    
921     cp = malloc (segsize * sizeof (struct cell));
922    
923     if (!cp && USE_ERROR_CHECKING)
924     return k;
925    
926     i = ++SCHEME_V->last_cell_seg;
927     SCHEME_V->alloc_seg[i] = cp;
928    
929     /* insert new segment in address order */
930     newp = (pointer)cp;
931     SCHEME_V->cell_seg[i] = newp;
932     SCHEME_V->cell_segsize[i] = segsize;
933    
934     //TODO: insert, not swap
935     while (i > 0 && SCHEME_V->cell_seg[i - 1] > SCHEME_V->cell_seg[i])
936     {
937     p = SCHEME_V->cell_seg[i];
938     SCHEME_V->cell_seg[i] = SCHEME_V->cell_seg[i - 1];
939     SCHEME_V->cell_seg[i - 1] = p;
940    
941     k = SCHEME_V->cell_segsize[i];
942     SCHEME_V->cell_segsize[i] = SCHEME_V->cell_segsize[i - 1];
943     SCHEME_V->cell_segsize[i - 1] = k;
944    
945     --i;
946     }
947    
948     SCHEME_V->fcells += segsize;
949     last = newp + segsize - 1;
950    
951     for (p = newp; p <= last; p++)
952     {
953 root 1.2 set_typeflag (p, T_FREE);
954     set_car (p, NIL);
955 root 1.1 set_cdr (p, p + 1);
956     }
957    
958     /* insert new cells in address order on free list */
959     if (SCHEME_V->free_cell == NIL || p < SCHEME_V->free_cell)
960     {
961     set_cdr (last, SCHEME_V->free_cell);
962     SCHEME_V->free_cell = newp;
963     }
964     else
965     {
966     p = SCHEME_V->free_cell;
967    
968     while (cdr (p) != NIL && newp > cdr (p))
969     p = cdr (p);
970    
971     set_cdr (last, cdr (p));
972     set_cdr (p, newp);
973     }
974     }
975    
976     return n;
977     }
978    
979 root 1.2 /* get new cell. parameter a, b is marked by gc. */
980 root 1.1 static INLINE pointer
981     get_cell_x (SCHEME_P_ pointer a, pointer b)
982     {
983     if (SCHEME_V->free_cell == NIL)
984     {
985     if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
986     return S_SINK;
987    
988     if (SCHEME_V->free_cell == NIL)
989     {
990     const int min_to_be_recovered = SCHEME_V->last_cell_seg < 128 ? 128 * 8 : SCHEME_V->last_cell_seg * 8;
991    
992     gc (SCHEME_A_ a, b);
993    
994     if (SCHEME_V->fcells < min_to_be_recovered || SCHEME_V->free_cell == NIL)
995     {
996     /* if only a few recovered, get more to avoid fruitless gc's */
997     if (!alloc_cellseg (SCHEME_A_ 1) && SCHEME_V->free_cell == NIL)
998     {
999     #if USE_ERROR_CHECKING
1000     SCHEME_V->no_memory = 1;
1001     return S_SINK;
1002     #endif
1003     }
1004     }
1005     }
1006     }
1007    
1008     {
1009     pointer x = SCHEME_V->free_cell;
1010    
1011     SCHEME_V->free_cell = cdr (x);
1012     --SCHEME_V->fcells;
1013     return x;
1014     }
1015     }
1016    
1017     /* To retain recent allocs before interpreter knows about them -
1018     Tehom */
1019    
1020     static void
1021     push_recent_alloc (SCHEME_P_ pointer recent, pointer extra)
1022     {
1023     pointer holder = get_cell_x (SCHEME_A_ recent, extra);
1024    
1025 root 1.2 set_typeflag (holder, T_PAIR);
1026     setimmutable (holder);
1027 root 1.1 set_car (holder, recent);
1028     set_cdr (holder, car (S_SINK));
1029     set_car (S_SINK, holder);
1030     }
1031    
1032     static pointer
1033     get_cell (SCHEME_P_ pointer a, pointer b)
1034     {
1035     pointer cell = get_cell_x (SCHEME_A_ a, b);
1036    
1037     /* For right now, include "a" and "b" in "cell" so that gc doesn't
1038     think they are garbage. */
1039     /* Tentatively record it as a pair so gc understands it. */
1040     set_typeflag (cell, T_PAIR);
1041     set_car (cell, a);
1042     set_cdr (cell, b);
1043     push_recent_alloc (SCHEME_A_ cell, NIL);
1044    
1045     return cell;
1046     }
1047    
1048     static pointer
1049 root 1.3 get_vector_object (SCHEME_P_ uint32_t len, pointer init)
1050 root 1.1 {
1051 root 1.3 pointer v = get_cell_x (SCHEME_A_ 0, 0);
1052     pointer *e = malloc (len * sizeof (pointer));
1053 root 1.1
1054 root 1.3 if (!e && USE_ERROR_CHECKING)
1055 root 1.1 return S_SINK;
1056    
1057     /* Record it as a vector so that gc understands it. */
1058 root 1.3 set_typeflag (v, T_VECTOR | T_ATOM);
1059    
1060     v->object.vector.vvalue = e;
1061     v->object.vector.length = len;
1062     fill_vector (v, init);
1063     push_recent_alloc (SCHEME_A_ v, NIL);
1064 root 1.1
1065 root 1.3 return v;
1066 root 1.1 }
1067    
1068     static INLINE void
1069     ok_to_freely_gc (SCHEME_P)
1070     {
1071     set_car (S_SINK, NIL);
1072     }
1073    
1074     #if defined TSGRIND
1075     static void
1076     check_cell_alloced (pointer p, int expect_alloced)
1077     {
1078 root 1.2 /* Can't use putstr(SCHEME_A_ str) because callers have no access to sc. */
1079 root 1.1 if (typeflag (p) & !expect_alloced)
1080     xwrstr ("Cell is already allocated!\n");
1081    
1082     if (!(typeflag (p)) & expect_alloced)
1083     xwrstr ("Cell is not allocated!\n");
1084     }
1085    
1086     static void
1087     check_range_alloced (pointer p, int n, int expect_alloced)
1088     {
1089     int i;
1090    
1091     for (i = 0; i < n; i++)
1092     check_cell_alloced (p + i, expect_alloced);
1093     }
1094     #endif
1095    
1096     /* Medium level cell allocation */
1097    
1098     /* get new cons cell */
1099     pointer
1100     xcons (SCHEME_P_ pointer a, pointer b, int immutable)
1101     {
1102     pointer x = get_cell (SCHEME_A_ a, b);
1103    
1104     set_typeflag (x, T_PAIR);
1105    
1106     if (immutable)
1107     setimmutable (x);
1108    
1109     set_car (x, a);
1110     set_cdr (x, b);
1111 root 1.3
1112 root 1.1 return x;
1113     }
1114    
1115     /* ========== oblist implementation ========== */
1116    
1117     #ifndef USE_OBJECT_LIST
1118    
1119     static int hash_fn (const char *key, int table_size);
1120    
1121     static pointer
1122     oblist_initial_value (SCHEME_P)
1123     {
1124     return mk_vector (SCHEME_A_ 461); /* probably should be bigger */
1125     }
1126    
1127     /* returns the new symbol */
1128     static pointer
1129     oblist_add_by_name (SCHEME_P_ const char *name)
1130     {
1131     int location;
1132    
1133 root 1.2 pointer x = immutable_cons (mk_string (SCHEME_A_ name), NIL);
1134 root 1.1 set_typeflag (x, T_SYMBOL);
1135     setimmutable (car (x));
1136    
1137 root 1.3 location = hash_fn (name, vector_length (SCHEME_V->oblist));
1138 root 1.1 set_vector_elem (SCHEME_V->oblist, location, immutable_cons (x, vector_elem (SCHEME_V->oblist, location)));
1139     return x;
1140     }
1141    
1142     static INLINE pointer
1143     oblist_find_by_name (SCHEME_P_ const char *name)
1144     {
1145     int location;
1146     pointer x;
1147     char *s;
1148    
1149 root 1.3 location = hash_fn (name, vector_length (SCHEME_V->oblist));
1150 root 1.1
1151     for (x = vector_elem (SCHEME_V->oblist, location); x != NIL; x = cdr (x))
1152     {
1153     s = symname (car (x));
1154    
1155     /* case-insensitive, per R5RS section 2 */
1156     if (stricmp (name, s) == 0)
1157     return car (x);
1158     }
1159    
1160     return NIL;
1161     }
1162    
1163     static pointer
1164     oblist_all_symbols (SCHEME_P)
1165     {
1166     int i;
1167     pointer x;
1168     pointer ob_list = NIL;
1169    
1170 root 1.3 for (i = 0; i < vector_length (SCHEME_V->oblist); i++)
1171 root 1.1 for (x = vector_elem (SCHEME_V->oblist, i); x != NIL; x = cdr (x))
1172     ob_list = cons (x, ob_list);
1173    
1174     return ob_list;
1175     }
1176    
1177     #else
1178    
1179     static pointer
1180     oblist_initial_value (SCHEME_P)
1181     {
1182     return NIL;
1183     }
1184    
1185     static INLINE pointer
1186     oblist_find_by_name (SCHEME_P_ const char *name)
1187     {
1188     pointer x;
1189     char *s;
1190    
1191     for (x = SCHEME_V->oblist; x != NIL; x = cdr (x))
1192     {
1193     s = symname (car (x));
1194    
1195     /* case-insensitive, per R5RS section 2 */
1196     if (stricmp (name, s) == 0)
1197     return car (x);
1198     }
1199    
1200     return NIL;
1201     }
1202    
1203     /* returns the new symbol */
1204     static pointer
1205     oblist_add_by_name (SCHEME_P_ const char *name)
1206     {
1207     pointer x;
1208    
1209     x = immutable_cons (mk_string (SCHEME_A_ name), NIL);
1210     set_typeflag (x, T_SYMBOL);
1211     setimmutable (car (x));
1212     SCHEME_V->oblist = immutable_cons (x, SCHEME_V->oblist);
1213     return x;
1214     }
1215    
1216     static pointer
1217     oblist_all_symbols (SCHEME_P)
1218     {
1219     return SCHEME_V->oblist;
1220     }
1221    
1222     #endif
1223    
1224     #if USE_PORTS
1225     static pointer
1226     mk_port (SCHEME_P_ port *p)
1227     {
1228     pointer x = get_cell (SCHEME_A_ NIL, NIL);
1229    
1230     set_typeflag (x, T_PORT | T_ATOM);
1231     x->object.port = p;
1232    
1233     return x;
1234     }
1235     #endif
1236    
1237     pointer
1238     mk_foreign_func (SCHEME_P_ foreign_func f)
1239     {
1240     pointer x = get_cell (SCHEME_A_ NIL, NIL);
1241    
1242     set_typeflag (x, (T_FOREIGN | T_ATOM));
1243     x->object.ff = f;
1244    
1245     return x;
1246     }
1247    
1248     INTERFACE pointer
1249     mk_character (SCHEME_P_ int c)
1250     {
1251     pointer x = get_cell (SCHEME_A_ NIL, NIL);
1252    
1253     set_typeflag (x, (T_CHARACTER | T_ATOM));
1254 root 1.2 ivalue_unchecked (x) = c & 0xff;
1255 root 1.1 set_num_integer (x);
1256     return x;
1257     }
1258    
1259     /* get number atom (integer) */
1260     INTERFACE pointer
1261     mk_integer (SCHEME_P_ long num)
1262     {
1263     pointer x = get_cell (SCHEME_A_ NIL, NIL);
1264    
1265     set_typeflag (x, (T_NUMBER | T_ATOM));
1266     ivalue_unchecked (x) = num;
1267     set_num_integer (x);
1268     return x;
1269     }
1270    
1271     INTERFACE pointer
1272     mk_real (SCHEME_P_ RVALUE n)
1273     {
1274     pointer x = get_cell (SCHEME_A_ NIL, NIL);
1275    
1276     set_typeflag (x, (T_NUMBER | T_ATOM));
1277     rvalue_unchecked (x) = n;
1278     set_num_real (x);
1279     return x;
1280     }
1281    
1282     static pointer
1283 root 1.2 mk_number (SCHEME_P_ const num n)
1284 root 1.1 {
1285     if (num_is_fixnum (n))
1286 root 1.2 return mk_integer (SCHEME_A_ num_get_ivalue (n));
1287 root 1.1 else
1288 root 1.2 return mk_real (SCHEME_A_ num_get_rvalue (n));
1289 root 1.1 }
1290    
1291     /* allocate name to string area */
1292     static char *
1293 root 1.3 store_string (SCHEME_P_ uint32_t len_str, const char *str, char fill)
1294 root 1.1 {
1295 root 1.2 char *q = malloc (len_str + 1);
1296 root 1.1
1297 root 1.2 if (q == 0 && USE_ERROR_CHECKING)
1298 root 1.1 {
1299     SCHEME_V->no_memory = 1;
1300     return SCHEME_V->strbuff;
1301     }
1302    
1303     if (str)
1304     {
1305     int l = strlen (str);
1306    
1307     if (l > len_str)
1308     l = len_str;
1309    
1310 root 1.2 memcpy (q, str, l);
1311     q[l] = 0;
1312 root 1.1 }
1313     else
1314     {
1315     memset (q, fill, len_str);
1316     q[len_str] = 0;
1317     }
1318    
1319     return q;
1320     }
1321    
1322     /* get new string */
1323     INTERFACE pointer
1324     mk_string (SCHEME_P_ const char *str)
1325     {
1326     return mk_counted_string (SCHEME_A_ str, strlen (str));
1327     }
1328    
1329     INTERFACE pointer
1330 root 1.3 mk_counted_string (SCHEME_P_ const char *str, uint32_t len)
1331 root 1.1 {
1332     pointer x = get_cell (SCHEME_A_ NIL, NIL);
1333    
1334     set_typeflag (x, T_STRING | T_ATOM);
1335     strvalue (x) = store_string (SCHEME_A_ len, str, 0);
1336     strlength (x) = len;
1337     return x;
1338     }
1339    
1340     INTERFACE pointer
1341 root 1.3 mk_empty_string (SCHEME_P_ uint32_t len, char fill)
1342 root 1.1 {
1343     pointer x = get_cell (SCHEME_A_ NIL, NIL);
1344    
1345     set_typeflag (x, T_STRING | T_ATOM);
1346     strvalue (x) = store_string (SCHEME_A_ len, 0, fill);
1347     strlength (x) = len;
1348     return x;
1349     }
1350    
1351     INTERFACE pointer
1352 root 1.3 mk_vector (SCHEME_P_ uint32_t len)
1353 root 1.1 {
1354     return get_vector_object (SCHEME_A_ len, NIL);
1355     }
1356    
1357     INTERFACE void
1358     fill_vector (pointer vec, pointer obj)
1359     {
1360     int i;
1361    
1362 root 1.3 for (i = 0; i < vec->object.vector.length; i++)
1363     vec->object.vector.vvalue[i] = obj;
1364 root 1.1 }
1365    
1366     INTERFACE pointer
1367 root 1.3 vector_elem (pointer vec, uint32_t ielem)
1368 root 1.1 {
1369 root 1.3 return vec->object.vector.vvalue[ielem];
1370 root 1.1 }
1371    
1372     INTERFACE void
1373 root 1.3 set_vector_elem (pointer vec, uint32_t ielem, pointer a)
1374 root 1.1 {
1375 root 1.3 vec->object.vector.vvalue[ielem] = a;
1376 root 1.1 }
1377    
1378     /* get new symbol */
1379     INTERFACE pointer
1380     mk_symbol (SCHEME_P_ const char *name)
1381     {
1382 root 1.2 /* first check oblist */
1383     pointer x = oblist_find_by_name (SCHEME_A_ name);
1384 root 1.1
1385 root 1.2 if (x == NIL)
1386     x = oblist_add_by_name (SCHEME_A_ name);
1387 root 1.1
1388 root 1.2 return x;
1389 root 1.1 }
1390    
1391     INTERFACE pointer
1392     gensym (SCHEME_P)
1393     {
1394     pointer x;
1395     char name[40];
1396    
1397     for (; SCHEME_V->gensym_cnt < LONG_MAX; SCHEME_V->gensym_cnt++)
1398     {
1399     strcpy (name, "gensym-");
1400     xnum (name + 7, SCHEME_V->gensym_cnt);
1401    
1402     /* first check oblist */
1403     x = oblist_find_by_name (SCHEME_A_ name);
1404    
1405     if (x != NIL)
1406     continue;
1407     else
1408     {
1409     x = oblist_add_by_name (SCHEME_A_ name);
1410     return x;
1411     }
1412     }
1413    
1414     return NIL;
1415     }
1416    
1417     /* make symbol or number atom from string */
1418     static pointer
1419     mk_atom (SCHEME_P_ char *q)
1420     {
1421     char c, *p;
1422     int has_dec_point = 0;
1423     int has_fp_exp = 0;
1424    
1425     #if USE_COLON_HOOK
1426    
1427     if ((p = strstr (q, "::")) != 0)
1428     {
1429     *p = 0;
1430     return cons (SCHEME_V->COLON_HOOK,
1431     cons (cons (SCHEME_V->QUOTE,
1432     cons (mk_atom (SCHEME_A_ p + 2), NIL)), cons (mk_symbol (SCHEME_A_ strlwr (q)), NIL)));
1433     }
1434    
1435     #endif
1436    
1437     p = q;
1438     c = *p++;
1439    
1440     if ((c == '+') || (c == '-'))
1441     {
1442     c = *p++;
1443    
1444     if (c == '.')
1445     {
1446     has_dec_point = 1;
1447     c = *p++;
1448     }
1449    
1450     if (!isdigit (c))
1451 root 1.2 return mk_symbol (SCHEME_A_ strlwr (q));
1452 root 1.1 }
1453     else if (c == '.')
1454     {
1455     has_dec_point = 1;
1456     c = *p++;
1457    
1458     if (!isdigit (c))
1459 root 1.2 return mk_symbol (SCHEME_A_ strlwr (q));
1460 root 1.1 }
1461     else if (!isdigit (c))
1462 root 1.2 return mk_symbol (SCHEME_A_ strlwr (q));
1463 root 1.1
1464     for (; (c = *p) != 0; ++p)
1465     {
1466     if (!isdigit (c))
1467     {
1468     if (c == '.')
1469     {
1470     if (!has_dec_point)
1471     {
1472     has_dec_point = 1;
1473     continue;
1474     }
1475     }
1476     else if ((c == 'e') || (c == 'E'))
1477     {
1478     if (!has_fp_exp)
1479     {
1480     has_dec_point = 1; /* decimal point illegal
1481     from now on */
1482     p++;
1483    
1484     if ((*p == '-') || (*p == '+') || isdigit (*p))
1485 root 1.2 continue;
1486 root 1.1 }
1487     }
1488    
1489     return mk_symbol (SCHEME_A_ strlwr (q));
1490     }
1491     }
1492    
1493     #if USE_FLOAT
1494     if (has_dec_point)
1495     return mk_real (SCHEME_A_ atof (q));
1496     #endif
1497    
1498     return mk_integer (SCHEME_A_ strtol (q, 0, 10));
1499     }
1500    
1501     /* make constant */
1502     static pointer
1503     mk_sharp_const (SCHEME_P_ char *name)
1504     {
1505     long x;
1506     char tmp[STRBUFFSIZE];
1507    
1508     if (!strcmp (name, "t"))
1509     return S_T;
1510     else if (!strcmp (name, "f"))
1511     return S_F;
1512     else if (*name == 'o') /* #o (octal) */
1513     {
1514     x = strtol (name + 1, 0, 8);
1515     return mk_integer (SCHEME_A_ x);
1516     }
1517     else if (*name == 'd') /* #d (decimal) */
1518     {
1519     x = strtol (name + 1, 0, 10);
1520     return mk_integer (SCHEME_A_ x);
1521     }
1522     else if (*name == 'x') /* #x (hex) */
1523     {
1524     x = strtol (name + 1, 0, 16);
1525     return mk_integer (SCHEME_A_ x);
1526     }
1527     else if (*name == 'b') /* #b (binary) */
1528     {
1529     x = binary_decode (name + 1);
1530     return mk_integer (SCHEME_A_ x);
1531     }
1532     else if (*name == '\\') /* #\w (character) */
1533     {
1534     int c = 0;
1535    
1536     if (stricmp (name + 1, "space") == 0)
1537     c = ' ';
1538     else if (stricmp (name + 1, "newline") == 0)
1539     c = '\n';
1540     else if (stricmp (name + 1, "return") == 0)
1541     c = '\r';
1542     else if (stricmp (name + 1, "tab") == 0)
1543     c = '\t';
1544     else if (name[1] == 'x' && name[2] != 0)
1545     {
1546     int c1 = strtol (name + 2, 0, 16);
1547    
1548     if (c1 <= UCHAR_MAX)
1549     c = c1;
1550     else
1551     return NIL;
1552    
1553     #if USE_ASCII_NAMES
1554     }
1555     else if (is_ascii_name (name + 1, &c))
1556     {
1557     /* nothing */
1558     #endif
1559     }
1560     else if (name[2] == 0)
1561     c = name[1];
1562     else
1563     return NIL;
1564    
1565     return mk_character (SCHEME_A_ c);
1566     }
1567     else
1568     return NIL;
1569     }
1570    
1571     /* ========== garbage collector ========== */
1572    
1573     /*--
1574     * We use algorithm E (Knuth, The Art of Computer Programming Vol.1,
1575     * sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm,
1576     * for marking.
1577     */
1578     static void
1579     mark (pointer a)
1580     {
1581     pointer t, q, p;
1582    
1583 root 1.2 t = 0;
1584 root 1.1 p = a;
1585     E2:
1586     setmark (p);
1587    
1588     if (is_vector (p))
1589     {
1590     int i;
1591    
1592 root 1.3 for (i = 0; i < p->object.vector.length; i++)
1593     mark (p->object.vector.vvalue[i]);
1594 root 1.1 }
1595    
1596     if (is_atom (p))
1597     goto E6;
1598    
1599     /* E4: down car */
1600     q = car (p);
1601    
1602     if (q && !is_mark (q))
1603     {
1604     setatom (p); /* a note that we have moved car */
1605     set_car (p, t);
1606     t = p;
1607     p = q;
1608     goto E2;
1609     }
1610    
1611     E5:
1612     q = cdr (p); /* down cdr */
1613    
1614     if (q && !is_mark (q))
1615     {
1616     set_cdr (p, t);
1617     t = p;
1618     p = q;
1619     goto E2;
1620     }
1621    
1622     E6: /* up. Undo the link switching from steps E4 and E5. */
1623     if (!t)
1624     return;
1625    
1626     q = t;
1627    
1628     if (is_atom (q))
1629     {
1630     clratom (q);
1631     t = car (q);
1632     set_car (q, p);
1633     p = q;
1634     goto E5;
1635     }
1636     else
1637     {
1638     t = cdr (q);
1639     set_cdr (q, p);
1640     p = q;
1641     goto E6;
1642     }
1643     }
1644    
1645     /* garbage collection. parameter a, b is marked. */
1646     static void
1647     gc (SCHEME_P_ pointer a, pointer b)
1648     {
1649     pointer p;
1650     int i;
1651    
1652     if (SCHEME_V->gc_verbose)
1653     putstr (SCHEME_A_ "gc...");
1654    
1655     /* mark system globals */
1656     mark (SCHEME_V->oblist);
1657     mark (SCHEME_V->global_env);
1658    
1659     /* mark current registers */
1660     mark (SCHEME_V->args);
1661     mark (SCHEME_V->envir);
1662     mark (SCHEME_V->code);
1663     dump_stack_mark (SCHEME_A);
1664     mark (SCHEME_V->value);
1665     mark (SCHEME_V->inport);
1666     mark (SCHEME_V->save_inport);
1667     mark (SCHEME_V->outport);
1668     mark (SCHEME_V->loadport);
1669    
1670     /* Mark recent objects the interpreter doesn't know about yet. */
1671     mark (car (S_SINK));
1672     /* Mark any older stuff above nested C calls */
1673     mark (SCHEME_V->c_nest);
1674    
1675     /* mark variables a, b */
1676     mark (a);
1677     mark (b);
1678    
1679     /* garbage collect */
1680     clrmark (NIL);
1681     SCHEME_V->fcells = 0;
1682     SCHEME_V->free_cell = NIL;
1683    
1684     /* free-list is kept sorted by address so as to maintain consecutive
1685     ranges, if possible, for use with vectors. Here we scan the cells
1686     (which are also kept sorted by address) downwards to build the
1687     free-list in sorted order.
1688     */
1689     for (i = SCHEME_V->last_cell_seg; i >= 0; i--)
1690     {
1691     p = SCHEME_V->cell_seg[i] + SCHEME_V->cell_segsize [i];
1692    
1693     while (--p >= SCHEME_V->cell_seg[i])
1694     {
1695     if (is_mark (p))
1696     clrmark (p);
1697     else
1698     {
1699     /* reclaim cell */
1700 root 1.2 if (typeflag (p) != T_FREE)
1701 root 1.1 {
1702     finalize_cell (SCHEME_A_ p);
1703 root 1.2 set_typeflag (p, T_FREE);
1704 root 1.1 set_car (p, NIL);
1705     }
1706    
1707     ++SCHEME_V->fcells;
1708     set_cdr (p, SCHEME_V->free_cell);
1709     SCHEME_V->free_cell = p;
1710     }
1711     }
1712     }
1713    
1714     if (SCHEME_V->gc_verbose)
1715     xwrstr ("done: "); xwrnum (SCHEME_V->fcells); xwrstr (" cells were recovered.\n");
1716     }
1717    
1718     static void
1719     finalize_cell (SCHEME_P_ pointer a)
1720     {
1721     if (is_string (a))
1722     free (strvalue (a));
1723 root 1.3 else if (is_vector (a))
1724     free (a->object.vector.vvalue);
1725 root 1.1 #if USE_PORTS
1726     else if (is_port (a))
1727     {
1728     if (a->object.port->kind & port_file && a->object.port->rep.stdio.closeit)
1729     port_close (SCHEME_A_ a, port_input | port_output);
1730    
1731     free (a->object.port);
1732     }
1733     #endif
1734     }
1735    
1736     /* ========== Routines for Reading ========== */
1737    
1738     static int
1739     file_push (SCHEME_P_ const char *fname)
1740     {
1741     #if USE_PORTS
1742     int fin;
1743    
1744     if (SCHEME_V->file_i == MAXFIL - 1)
1745     return 0;
1746    
1747     fin = open (fname, O_RDONLY);
1748    
1749     if (fin >= 0)
1750     {
1751     SCHEME_V->file_i++;
1752     SCHEME_V->load_stack[SCHEME_V->file_i].unget = -1;
1753     SCHEME_V->load_stack[SCHEME_V->file_i].kind = port_file | port_input;
1754     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.file = fin;
1755     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.closeit = 1;
1756     SCHEME_V->nesting_stack[SCHEME_V->file_i] = 0;
1757     SCHEME_V->loadport->object.port = SCHEME_V->load_stack + SCHEME_V->file_i;
1758    
1759     #if SHOW_ERROR_LINE
1760     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line = 0;
1761    
1762     if (fname)
1763     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.filename = store_string (SCHEME_A_ strlen (fname), fname, 0);
1764     #endif
1765     }
1766    
1767     return fin >= 0;
1768    
1769     #else
1770     return 1;
1771     #endif
1772     }
1773    
1774     static void
1775     file_pop (SCHEME_P)
1776     {
1777     if (SCHEME_V->file_i != 0)
1778     {
1779     SCHEME_V->nesting = SCHEME_V->nesting_stack[SCHEME_V->file_i];
1780     #if USE_PORTS
1781     port_close (SCHEME_A_ SCHEME_V->loadport, port_input);
1782     #endif
1783     SCHEME_V->file_i--;
1784     SCHEME_V->loadport->object.port = SCHEME_V->load_stack + SCHEME_V->file_i;
1785     }
1786     }
1787    
1788     static int
1789     file_interactive (SCHEME_P)
1790     {
1791     #if USE_PORTS
1792     return SCHEME_V->file_i == 0
1793     && SCHEME_V->load_stack[0].rep.stdio.file == STDIN_FILENO
1794     && (SCHEME_V->inport->object.port->kind & port_file);
1795     #else
1796     return 0;
1797     #endif
1798     }
1799    
1800     #if USE_PORTS
1801     static port *
1802     port_rep_from_filename (SCHEME_P_ const char *fn, int prop)
1803     {
1804     int fd;
1805     int flags;
1806     char *rw;
1807     port *pt;
1808    
1809     if (prop == (port_input | port_output))
1810     flags = O_RDWR | O_APPEND | O_CREAT;
1811     else if (prop == port_output)
1812     flags = O_WRONLY | O_TRUNC | O_CREAT;
1813     else
1814     flags = O_RDONLY;
1815    
1816     fd = open (fn, flags, 0666);
1817    
1818     if (fd < 0)
1819     return 0;
1820    
1821     pt = port_rep_from_file (SCHEME_A_ fd, prop);
1822     pt->rep.stdio.closeit = 1;
1823    
1824     # if SHOW_ERROR_LINE
1825     if (fn)
1826     pt->rep.stdio.filename = store_string (SCHEME_A_ strlen (fn), fn, 0);
1827    
1828     pt->rep.stdio.curr_line = 0;
1829     # endif
1830    
1831     return pt;
1832     }
1833    
1834     static pointer
1835     port_from_filename (SCHEME_P_ const char *fn, int prop)
1836     {
1837     port *pt = port_rep_from_filename (SCHEME_A_ fn, prop);
1838    
1839     if (!pt && USE_ERROR_CHECKING)
1840     return NIL;
1841    
1842     return mk_port (SCHEME_A_ pt);
1843     }
1844    
1845     static port *
1846     port_rep_from_file (SCHEME_P_ int f, int prop)
1847     {
1848     port *pt = malloc (sizeof *pt);
1849    
1850     if (!pt && USE_ERROR_CHECKING)
1851     return NULL;
1852    
1853     pt->unget = -1;
1854     pt->kind = port_file | prop;
1855     pt->rep.stdio.file = f;
1856     pt->rep.stdio.closeit = 0;
1857     return pt;
1858     }
1859    
1860     static pointer
1861     port_from_file (SCHEME_P_ int f, int prop)
1862     {
1863     port *pt = port_rep_from_file (SCHEME_A_ f, prop);
1864    
1865     if (!pt && USE_ERROR_CHECKING)
1866     return NIL;
1867    
1868     return mk_port (SCHEME_A_ pt);
1869     }
1870    
1871     static port *
1872     port_rep_from_string (SCHEME_P_ char *start, char *past_the_end, int prop)
1873     {
1874     port *pt = malloc (sizeof (port));
1875    
1876     if (!pt && USE_ERROR_CHECKING)
1877     return 0;
1878    
1879     pt->unget = -1;
1880     pt->kind = port_string | prop;
1881     pt->rep.string.start = start;
1882     pt->rep.string.curr = start;
1883     pt->rep.string.past_the_end = past_the_end;
1884     return pt;
1885     }
1886    
1887     static pointer
1888     port_from_string (SCHEME_P_ char *start, char *past_the_end, int prop)
1889     {
1890     port *pt = port_rep_from_string (SCHEME_A_ start, past_the_end, prop);
1891    
1892     if (!pt && USE_ERROR_CHECKING)
1893     return NIL;
1894    
1895     return mk_port (SCHEME_A_ pt);
1896     }
1897    
1898     # define BLOCK_SIZE 256
1899    
1900     static port *
1901     port_rep_from_scratch (SCHEME_P)
1902     {
1903     char *start;
1904     port *pt = malloc (sizeof (port));
1905    
1906     if (!pt && USE_ERROR_CHECKING)
1907     return 0;
1908    
1909     start = malloc (BLOCK_SIZE);
1910    
1911     if (start == 0)
1912     return 0;
1913    
1914     memset (start, ' ', BLOCK_SIZE - 1);
1915     start[BLOCK_SIZE - 1] = '\0';
1916     pt->unget = -1;
1917     pt->kind = port_string | port_output | port_srfi6;
1918     pt->rep.string.start = start;
1919     pt->rep.string.curr = start;
1920     pt->rep.string.past_the_end = start + BLOCK_SIZE - 1;
1921     return pt;
1922     }
1923    
1924     static pointer
1925     port_from_scratch (SCHEME_P)
1926     {
1927     port *pt = port_rep_from_scratch (SCHEME_A);
1928    
1929     if (!pt && USE_ERROR_CHECKING)
1930     return NIL;
1931    
1932     return mk_port (SCHEME_A_ pt);
1933     }
1934    
1935     static void
1936     port_close (SCHEME_P_ pointer p, int flag)
1937     {
1938     port *pt = p->object.port;
1939    
1940     pt->kind &= ~flag;
1941    
1942     if ((pt->kind & (port_input | port_output)) == 0)
1943     {
1944     if (pt->kind & port_file)
1945     {
1946    
1947     # if SHOW_ERROR_LINE
1948     /* Cleanup is here so (close-*-port) functions could work too */
1949     pt->rep.stdio.curr_line = 0;
1950    
1951     if (pt->rep.stdio.filename)
1952     free (pt->rep.stdio.filename);
1953    
1954     # endif
1955    
1956     close (pt->rep.stdio.file);
1957     }
1958    
1959     pt->kind = port_free;
1960     }
1961     }
1962     #endif
1963    
1964     /* get new character from input file */
1965     static int
1966     inchar (SCHEME_P)
1967     {
1968     int c;
1969     port *pt;
1970    
1971     pt = SCHEME_V->inport->object.port;
1972    
1973     if (pt->kind & port_saw_EOF)
1974     return EOF;
1975    
1976     c = basic_inchar (pt);
1977    
1978     if (c == EOF && SCHEME_V->inport == SCHEME_V->loadport)
1979     {
1980     /* Instead, set port_saw_EOF */
1981     pt->kind |= port_saw_EOF;
1982    
1983     /* file_pop(SCHEME_A); */
1984     return EOF;
1985     /* NOTREACHED */
1986     }
1987    
1988     return c;
1989     }
1990    
1991     static int ungot = -1;
1992    
1993     static int
1994     basic_inchar (port *pt)
1995     {
1996     #if USE_PORTS
1997     if (pt->unget != -1)
1998     {
1999     int r = pt->unget;
2000     pt->unget = -1;
2001     return r;
2002     }
2003    
2004     if (pt->kind & port_file)
2005     {
2006     char c;
2007    
2008     if (!read (pt->rep.stdio.file, &c, 1))
2009     return EOF;
2010    
2011     return c;
2012     }
2013     else
2014     {
2015     if (*pt->rep.string.curr == 0 || pt->rep.string.curr == pt->rep.string.past_the_end)
2016     return EOF;
2017     else
2018     return *pt->rep.string.curr++;
2019     }
2020     #else
2021     if (ungot == -1)
2022     {
2023     char c;
2024     if (!read (0, &c, 1))
2025     return EOF;
2026    
2027     ungot = c;
2028     }
2029    
2030     {
2031     int r = ungot;
2032     ungot = -1;
2033     return r;
2034     }
2035     #endif
2036     }
2037    
2038     /* back character to input buffer */
2039     static void
2040     backchar (SCHEME_P_ int c)
2041     {
2042     #if USE_PORTS
2043     port *pt;
2044    
2045     if (c == EOF)
2046     return;
2047    
2048     pt = SCHEME_V->inport->object.port;
2049     pt->unget = c;
2050     #else
2051     if (c == EOF)
2052     return;
2053    
2054     ungot = c;
2055     #endif
2056     }
2057    
2058     #if USE_PORTS
2059     static int
2060     realloc_port_string (SCHEME_P_ port *p)
2061     {
2062     char *start = p->rep.string.start;
2063     size_t new_size = p->rep.string.past_the_end - start + 1 + BLOCK_SIZE;
2064     char *str = malloc (new_size);
2065    
2066     if (str)
2067     {
2068     memset (str, ' ', new_size - 1);
2069     str[new_size - 1] = '\0';
2070     strcpy (str, start);
2071     p->rep.string.start = str;
2072     p->rep.string.past_the_end = str + new_size - 1;
2073     p->rep.string.curr -= start - str;
2074     free (start);
2075     return 1;
2076     }
2077     else
2078     return 0;
2079     }
2080     #endif
2081    
2082     INTERFACE void
2083     putstr (SCHEME_P_ const char *s)
2084     {
2085     #if USE_PORTS
2086     port *pt = SCHEME_V->outport->object.port;
2087    
2088     if (pt->kind & port_file)
2089     write (pt->rep.stdio.file, s, strlen (s));
2090     else
2091     for (; *s; s++)
2092     if (pt->rep.string.curr != pt->rep.string.past_the_end)
2093     *pt->rep.string.curr++ = *s;
2094     else if (pt->kind & port_srfi6 && realloc_port_string (SCHEME_A_ pt))
2095     *pt->rep.string.curr++ = *s;
2096    
2097     #else
2098     xwrstr (s);
2099     #endif
2100     }
2101    
2102     static void
2103     putchars (SCHEME_P_ const char *s, int len)
2104     {
2105     #if USE_PORTS
2106     port *pt = SCHEME_V->outport->object.port;
2107    
2108     if (pt->kind & port_file)
2109     write (pt->rep.stdio.file, s, len);
2110     else
2111     {
2112     for (; len; len--)
2113     {
2114     if (pt->rep.string.curr != pt->rep.string.past_the_end)
2115     *pt->rep.string.curr++ = *s++;
2116     else if (pt->kind & port_srfi6 && realloc_port_string (SCHEME_A_ pt))
2117     *pt->rep.string.curr++ = *s++;
2118     }
2119     }
2120    
2121     #else
2122     write (1, s, len);
2123     #endif
2124     }
2125    
2126     INTERFACE void
2127     putcharacter (SCHEME_P_ int c)
2128     {
2129     #if USE_PORTS
2130     port *pt = SCHEME_V->outport->object.port;
2131    
2132     if (pt->kind & port_file)
2133     {
2134     char cc = c;
2135     write (pt->rep.stdio.file, &cc, 1);
2136     }
2137     else
2138     {
2139     if (pt->rep.string.curr != pt->rep.string.past_the_end)
2140     *pt->rep.string.curr++ = c;
2141     else if (pt->kind & port_srfi6 && realloc_port_string (SCHEME_A_ pt))
2142     *pt->rep.string.curr++ = c;
2143     }
2144    
2145     #else
2146     char cc = c;
2147     write (1, &c, 1);
2148     #endif
2149     }
2150    
2151     /* read characters up to delimiter, but cater to character constants */
2152     static char *
2153     readstr_upto (SCHEME_P_ char *delim)
2154     {
2155     char *p = SCHEME_V->strbuff;
2156    
2157     while ((p - SCHEME_V->strbuff < sizeof (SCHEME_V->strbuff)) && !is_one_of (delim, (*p++ = inchar (SCHEME_A))));
2158    
2159     if (p == SCHEME_V->strbuff + 2 && p[-2] == '\\')
2160 root 1.2 *p = 0;
2161 root 1.1 else
2162     {
2163     backchar (SCHEME_A_ p[-1]);
2164     *--p = '\0';
2165     }
2166    
2167     return SCHEME_V->strbuff;
2168     }
2169    
2170     /* read string expression "xxx...xxx" */
2171     static pointer
2172     readstrexp (SCHEME_P)
2173     {
2174     char *p = SCHEME_V->strbuff;
2175     int c;
2176     int c1 = 0;
2177     enum
2178     { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state = st_ok;
2179    
2180     for (;;)
2181     {
2182     c = inchar (SCHEME_A);
2183    
2184     if (c == EOF || p - SCHEME_V->strbuff > sizeof (SCHEME_V->strbuff) - 1)
2185 root 1.2 return S_F;
2186 root 1.1
2187     switch (state)
2188     {
2189     case st_ok:
2190     switch (c)
2191     {
2192     case '\\':
2193     state = st_bsl;
2194     break;
2195    
2196     case '"':
2197     *p = 0;
2198     return mk_counted_string (SCHEME_A_ SCHEME_V->strbuff, p - SCHEME_V->strbuff);
2199    
2200     default:
2201     *p++ = c;
2202     break;
2203     }
2204    
2205     break;
2206    
2207     case st_bsl:
2208     switch (c)
2209     {
2210     case '0':
2211     case '1':
2212     case '2':
2213     case '3':
2214     case '4':
2215     case '5':
2216     case '6':
2217     case '7':
2218     state = st_oct1;
2219     c1 = c - '0';
2220     break;
2221    
2222     case 'x':
2223     case 'X':
2224     state = st_x1;
2225     c1 = 0;
2226     break;
2227    
2228     case 'n':
2229     *p++ = '\n';
2230     state = st_ok;
2231     break;
2232    
2233     case 't':
2234     *p++ = '\t';
2235     state = st_ok;
2236     break;
2237    
2238     case 'r':
2239     *p++ = '\r';
2240     state = st_ok;
2241     break;
2242    
2243     case '"':
2244     *p++ = '"';
2245     state = st_ok;
2246     break;
2247    
2248     default:
2249     *p++ = c;
2250     state = st_ok;
2251     break;
2252     }
2253    
2254     break;
2255    
2256     case st_x1:
2257     case st_x2:
2258     c = toupper (c);
2259    
2260     if (c >= '0' && c <= 'F')
2261     {
2262     if (c <= '9')
2263 root 1.2 c1 = (c1 << 4) + c - '0';
2264 root 1.1 else
2265 root 1.2 c1 = (c1 << 4) + c - 'A' + 10;
2266 root 1.1
2267     if (state == st_x1)
2268 root 1.2 state = st_x2;
2269 root 1.1 else
2270     {
2271     *p++ = c1;
2272     state = st_ok;
2273     }
2274     }
2275     else
2276 root 1.2 return S_F;
2277 root 1.1
2278     break;
2279    
2280     case st_oct1:
2281     case st_oct2:
2282     if (c < '0' || c > '7')
2283     {
2284     *p++ = c1;
2285     backchar (SCHEME_A_ c);
2286     state = st_ok;
2287     }
2288     else
2289     {
2290     if (state == st_oct2 && c1 >= 32)
2291     return S_F;
2292    
2293     c1 = (c1 << 3) + (c - '0');
2294    
2295     if (state == st_oct1)
2296     state = st_oct2;
2297     else
2298     {
2299     *p++ = c1;
2300     state = st_ok;
2301     }
2302     }
2303    
2304     break;
2305    
2306     }
2307     }
2308     }
2309    
2310     /* check c is in chars */
2311     static INLINE int
2312     is_one_of (char *s, int c)
2313     {
2314     if (c == EOF)
2315     return 1;
2316    
2317 root 1.2 return !!strchr (s, c);
2318 root 1.1 }
2319    
2320     /* skip white characters */
2321     static INLINE int
2322     skipspace (SCHEME_P)
2323     {
2324     int c, curr_line = 0;
2325    
2326     do
2327     {
2328     c = inchar (SCHEME_A);
2329     #if SHOW_ERROR_LINE
2330     if (c == '\n')
2331     curr_line++;
2332     #endif
2333     }
2334     while (c == ' ' || c == '\n' || c == '\r' || c == '\t');
2335    
2336     /* record it */
2337     #if SHOW_ERROR_LINE
2338     if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
2339     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line += curr_line;
2340     #endif
2341    
2342     if (c != EOF)
2343     {
2344     backchar (SCHEME_A_ c);
2345     return 1;
2346     }
2347     else
2348     return EOF;
2349     }
2350    
2351     /* get token */
2352     static int
2353     token (SCHEME_P)
2354     {
2355     int c = skipspace (SCHEME_A);
2356    
2357     if (c == EOF)
2358     return TOK_EOF;
2359    
2360     switch ((c = inchar (SCHEME_A)))
2361     {
2362     case EOF:
2363     return TOK_EOF;
2364    
2365     case '(':
2366     return TOK_LPAREN;
2367    
2368     case ')':
2369     return TOK_RPAREN;
2370    
2371     case '.':
2372     c = inchar (SCHEME_A);
2373    
2374     if (is_one_of (" \n\t", c))
2375     return TOK_DOT;
2376     else
2377     {
2378 root 1.2 //TODO: ungetc twice in a row is not supported in C
2379 root 1.1 backchar (SCHEME_A_ c);
2380     backchar (SCHEME_A_ '.');
2381     return TOK_ATOM;
2382     }
2383    
2384     case '\'':
2385     return TOK_QUOTE;
2386    
2387     case ';':
2388     while ((c = inchar (SCHEME_A)) != '\n' && c != EOF)
2389     ;
2390    
2391     #if SHOW_ERROR_LINE
2392    
2393     if (c == '\n' && SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
2394     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
2395    
2396     #endif
2397    
2398     if (c == EOF)
2399     return TOK_EOF;
2400     else
2401     return token (SCHEME_A);
2402    
2403     case '"':
2404     return TOK_DQUOTE;
2405    
2406     case BACKQUOTE:
2407     return TOK_BQUOTE;
2408    
2409     case ',':
2410     if ((c = inchar (SCHEME_A)) == '@')
2411     return TOK_ATMARK;
2412     else
2413     {
2414     backchar (SCHEME_A_ c);
2415     return TOK_COMMA;
2416     }
2417    
2418     case '#':
2419     c = inchar (SCHEME_A);
2420    
2421     if (c == '(')
2422     return TOK_VEC;
2423     else if (c == '!')
2424     {
2425     while ((c = inchar (SCHEME_A)) != '\n' && c != EOF)
2426     ;
2427    
2428     #if SHOW_ERROR_LINE
2429    
2430     if (c == '\n' && SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
2431     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
2432    
2433     #endif
2434    
2435     if (c == EOF)
2436     return TOK_EOF;
2437     else
2438     return token (SCHEME_A);
2439     }
2440     else
2441     {
2442     backchar (SCHEME_A_ c);
2443    
2444     if (is_one_of (" tfodxb\\", c))
2445     return TOK_SHARP_CONST;
2446     else
2447     return TOK_SHARP;
2448     }
2449    
2450     default:
2451     backchar (SCHEME_A_ c);
2452     return TOK_ATOM;
2453     }
2454     }
2455    
2456     /* ========== Routines for Printing ========== */
2457     #define ok_abbrev(x) (is_pair(x) && cdr(x) == NIL)
2458    
2459     static void
2460     printslashstring (SCHEME_P_ char *p, int len)
2461     {
2462     int i;
2463     unsigned char *s = (unsigned char *) p;
2464    
2465     putcharacter (SCHEME_A_ '"');
2466    
2467     for (i = 0; i < len; i++)
2468     {
2469     if (*s == 0xff || *s == '"' || *s < ' ' || *s == '\\')
2470     {
2471     putcharacter (SCHEME_A_ '\\');
2472    
2473     switch (*s)
2474     {
2475     case '"':
2476     putcharacter (SCHEME_A_ '"');
2477     break;
2478    
2479     case '\n':
2480     putcharacter (SCHEME_A_ 'n');
2481     break;
2482    
2483     case '\t':
2484     putcharacter (SCHEME_A_ 't');
2485     break;
2486    
2487     case '\r':
2488     putcharacter (SCHEME_A_ 'r');
2489     break;
2490    
2491     case '\\':
2492     putcharacter (SCHEME_A_ '\\');
2493     break;
2494    
2495     default:
2496     {
2497     int d = *s / 16;
2498    
2499     putcharacter (SCHEME_A_ 'x');
2500    
2501     if (d < 10)
2502 root 1.2 putcharacter (SCHEME_A_ d + '0');
2503 root 1.1 else
2504 root 1.2 putcharacter (SCHEME_A_ d - 10 + 'A');
2505 root 1.1
2506     d = *s % 16;
2507    
2508     if (d < 10)
2509 root 1.2 putcharacter (SCHEME_A_ d + '0');
2510 root 1.1 else
2511 root 1.2 putcharacter (SCHEME_A_ d - 10 + 'A');
2512 root 1.1 }
2513     }
2514     }
2515     else
2516 root 1.2 putcharacter (SCHEME_A_ * s);
2517 root 1.1
2518     s++;
2519     }
2520    
2521     putcharacter (SCHEME_A_ '"');
2522     }
2523    
2524    
2525     /* print atoms */
2526     static void
2527     printatom (SCHEME_P_ pointer l, int f)
2528     {
2529     char *p;
2530     int len;
2531    
2532     atom2str (SCHEME_A_ l, f, &p, &len);
2533     putchars (SCHEME_A_ p, len);
2534     }
2535    
2536    
2537     /* Uses internal buffer unless string pointer is already available */
2538     static void
2539     atom2str (SCHEME_P_ pointer l, int f, char **pp, int *plen)
2540     {
2541     char *p;
2542    
2543     if (l == NIL)
2544     p = "()";
2545     else if (l == S_T)
2546     p = "#t";
2547     else if (l == S_F)
2548     p = "#f";
2549     else if (l == S_EOF)
2550     p = "#<EOF>";
2551     else if (is_port (l))
2552     p = "#<PORT>";
2553     else if (is_number (l))
2554     {
2555     p = SCHEME_V->strbuff;
2556    
2557     if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */
2558     {
2559     if (num_is_integer (l))
2560     xnum (p, ivalue_unchecked (l));
2561     #if USE_FLOAT
2562     else
2563     {
2564     snprintf (p, STRBUFFSIZE, "%.10g", rvalue_unchecked (l));
2565     /* r5rs says there must be a '.' (unless 'e'?) */
2566     f = strcspn (p, ".e");
2567    
2568     if (p[f] == 0)
2569     {
2570     p[f] = '.'; /* not found, so add '.0' at the end */
2571     p[f + 1] = '0';
2572     p[f + 2] = 0;
2573     }
2574     }
2575     #endif
2576     }
2577     else
2578     {
2579     long v = ivalue (l);
2580    
2581     if (f == 16)
2582     xbase (p, v, 16);
2583     else if (f == 8)
2584     xbase (p, v, 8);
2585     else if (f == 2)
2586     {
2587     unsigned long b = (v < 0) ? -v : v;
2588    
2589     p = &p[STRBUFFSIZE - 1];
2590     *p = 0;
2591    
2592     do
2593     {
2594     *--p = (b & 1) ? '1' : '0';
2595     b >>= 1;
2596     }
2597     while (b != 0);
2598    
2599     if (v < 0)
2600     *--p = '-';
2601     }
2602     }
2603     }
2604     else if (is_string (l))
2605     {
2606     if (!f)
2607     p = strvalue (l);
2608     else /* Hack, uses the fact that printing is needed */
2609     {
2610     *pp = SCHEME_V->strbuff;
2611     *plen = 0;
2612     printslashstring (SCHEME_A_ strvalue (l), strlength (l));
2613     return;
2614     }
2615     }
2616     else if (is_character (l))
2617     {
2618     int c = charvalue (l);
2619    
2620     p = SCHEME_V->strbuff;
2621    
2622     if (!f)
2623     {
2624     p[0] = c;
2625     p[1] = 0;
2626     }
2627     else
2628     {
2629     switch (c)
2630     {
2631     case ' ':
2632     p ="#\\space";
2633     break;
2634    
2635     case '\n':
2636     p ="#\\newline";
2637     break;
2638    
2639     case '\r':
2640     p ="#\\return";
2641     break;
2642    
2643     case '\t':
2644     p ="#\\tab";
2645     break;
2646    
2647     default:
2648     #if USE_ASCII_NAMES
2649     if (c == 127)
2650     {
2651     strcpy (p, "#\\del");
2652     break;
2653     }
2654     else if (c < 32)
2655     {
2656     strcpy (p, "#\\");
2657     strcpy (p + 2, charnames[c]);
2658     break;
2659     }
2660    
2661     #else
2662    
2663     if (c < 32)
2664     {
2665     strcpy (p, "#\\x");
2666     xbase (p + 3, c, 16);
2667     break;
2668     }
2669    
2670     #endif
2671     strcpy (p, "#\\%");
2672     p[2] = c;
2673     break;
2674     }
2675     }
2676     }
2677     else if (is_symbol (l))
2678     p = symname (l);
2679     else if (is_proc (l))
2680     {
2681     #if USE_PRINTF
2682     p = SCHEME_V->strbuff;
2683     snprintf (p, STRBUFFSIZE, "#<%s PROCEDURE %ld>", procname (l), procnum (l));
2684     #else
2685     p = "#<PROCEDURE>";
2686     #endif
2687     }
2688     else if (is_macro (l))
2689     p = "#<MACRO>";
2690     else if (is_closure (l))
2691     p = "#<CLOSURE>";
2692     else if (is_promise (l))
2693     p = "#<PROMISE>";
2694     else if (is_foreign (l))
2695     {
2696     #if USE_PRINTF
2697     p = SCHEME_V->strbuff;
2698     snprintf (p, STRBUFFSIZE, "#<FOREIGN PROCEDURE %ld>", procnum (l));
2699     #else
2700     p = "#<FOREIGN PROCEDURE>";
2701     #endif
2702     }
2703     else if (is_continuation (l))
2704     p = "#<CONTINUATION>";
2705     else
2706     p = "#<ERROR>";
2707    
2708     *pp = p;
2709     *plen = strlen (p);
2710     }
2711    
2712     /* ========== Routines for Evaluation Cycle ========== */
2713    
2714     /* make closure. c is code. e is environment */
2715     static pointer
2716     mk_closure (SCHEME_P_ pointer c, pointer e)
2717     {
2718     pointer x = get_cell (SCHEME_A_ c, e);
2719    
2720     set_typeflag (x, T_CLOSURE);
2721     set_car (x, c);
2722     set_cdr (x, e);
2723     return x;
2724     }
2725    
2726     /* make continuation. */
2727     static pointer
2728     mk_continuation (SCHEME_P_ pointer d)
2729     {
2730     pointer x = get_cell (SCHEME_A_ NIL, d);
2731    
2732     set_typeflag (x, T_CONTINUATION);
2733     set_cont_dump (x, d);
2734     return x;
2735     }
2736    
2737     static pointer
2738     list_star (SCHEME_P_ pointer d)
2739     {
2740     pointer p, q;
2741    
2742     if (cdr (d) == NIL)
2743 root 1.2 return car (d);
2744 root 1.1
2745     p = cons (car (d), cdr (d));
2746     q = p;
2747    
2748     while (cdr (cdr (p)) != NIL)
2749     {
2750     d = cons (car (p), cdr (p));
2751    
2752     if (cdr (cdr (p)) != NIL)
2753 root 1.2 p = cdr (d);
2754 root 1.1 }
2755    
2756     set_cdr (p, car (cdr (p)));
2757     return q;
2758     }
2759    
2760     /* reverse list -- produce new list */
2761     static pointer
2762     reverse (SCHEME_P_ pointer a)
2763     {
2764     /* a must be checked by gc */
2765     pointer p = NIL;
2766    
2767     for (; is_pair (a); a = cdr (a))
2768     p = cons (car (a), p);
2769    
2770     return p;
2771     }
2772    
2773     /* reverse list --- in-place */
2774     static pointer
2775     reverse_in_place (SCHEME_P_ pointer term, pointer list)
2776     {
2777 root 1.2 pointer result = term;
2778     pointer p = list;
2779 root 1.1
2780     while (p != NIL)
2781     {
2782 root 1.2 pointer q = cdr (p);
2783 root 1.1 set_cdr (p, result);
2784     result = p;
2785     p = q;
2786     }
2787    
2788     return result;
2789     }
2790    
2791     /* append list -- produce new list (in reverse order) */
2792     static pointer
2793     revappend (SCHEME_P_ pointer a, pointer b)
2794     {
2795     pointer result = a;
2796     pointer p = b;
2797    
2798     while (is_pair (p))
2799     {
2800     result = cons (car (p), result);
2801     p = cdr (p);
2802     }
2803    
2804     if (p == NIL)
2805     return result;
2806    
2807     return S_F; /* signal an error */
2808     }
2809    
2810     /* equivalence of atoms */
2811     int
2812     eqv (pointer a, pointer b)
2813     {
2814     if (is_string (a))
2815     {
2816     if (is_string (b))
2817     return strvalue (a) == strvalue (b);
2818     else
2819     return 0;
2820     }
2821     else if (is_number (a))
2822     {
2823     if (is_number (b))
2824     if (num_is_integer (a) == num_is_integer (b))
2825     return num_eq (nvalue (a), nvalue (b));
2826    
2827     return 0;
2828     }
2829     else if (is_character (a))
2830     {
2831     if (is_character (b))
2832     return charvalue (a) == charvalue (b);
2833     else
2834     return 0;
2835     }
2836     else if (is_port (a))
2837     {
2838     if (is_port (b))
2839     return a == b;
2840     else
2841     return 0;
2842     }
2843     else if (is_proc (a))
2844     {
2845     if (is_proc (b))
2846     return procnum (a) == procnum (b);
2847     else
2848     return 0;
2849     }
2850     else
2851     return a == b;
2852     }
2853    
2854     /* true or false value macro */
2855    
2856     /* () is #t in R5RS */
2857     #define is_true(p) ((p) != S_F)
2858     #define is_false(p) ((p) == S_F)
2859    
2860     /* ========== Environment implementation ========== */
2861    
2862     #if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
2863    
2864     static int
2865     hash_fn (const char *key, int table_size)
2866     {
2867 root 1.3 const unsigned char *p = key;
2868     uint32_t hash = 2166136261;
2869 root 1.1
2870 root 1.3 while (*p)
2871     hash = (hash ^ *p++) * 16777619;
2872 root 1.1
2873 root 1.3 return hash % table_size;
2874 root 1.1 }
2875     #endif
2876    
2877     #ifndef USE_ALIST_ENV
2878    
2879     /*
2880     * In this implementation, each frame of the environment may be
2881     * a hash table: a vector of alists hashed by variable name.
2882     * In practice, we use a vector only for the initial frame;
2883     * subsequent frames are too small and transient for the lookup
2884     * speed to out-weigh the cost of making a new vector.
2885     */
2886    
2887     static void
2888     new_frame_in_env (SCHEME_P_ pointer old_env)
2889     {
2890     pointer new_frame;
2891    
2892     /* The interaction-environment has about 300 variables in it. */
2893     if (old_env == NIL)
2894     new_frame = mk_vector (SCHEME_A_ 461);
2895     else
2896     new_frame = NIL;
2897    
2898     SCHEME_V->envir = immutable_cons (new_frame, old_env);
2899     setenvironment (SCHEME_V->envir);
2900     }
2901    
2902     static INLINE void
2903     new_slot_spec_in_env (SCHEME_P_ pointer env, pointer variable, pointer value)
2904     {
2905     pointer slot = immutable_cons (variable, value);
2906    
2907     if (is_vector (car (env)))
2908     {
2909 root 1.3 int location = hash_fn (symname (variable), vector_length (car (env)));
2910 root 1.1
2911     set_vector_elem (car (env), location, immutable_cons (slot, vector_elem (car (env), location)));
2912     }
2913     else
2914     set_car (env, immutable_cons (slot, car (env)));
2915     }
2916    
2917     static pointer
2918     find_slot_in_env (SCHEME_P_ pointer env, pointer hdl, int all)
2919     {
2920     pointer x, y;
2921     int location;
2922    
2923     for (x = env; x != NIL; x = cdr (x))
2924     {
2925     if (is_vector (car (x)))
2926     {
2927 root 1.3 location = hash_fn (symname (hdl), vector_length (car (x)));
2928 root 1.1 y = vector_elem (car (x), location);
2929     }
2930     else
2931     y = car (x);
2932    
2933     for (; y != NIL; y = cdr (y))
2934     if (caar (y) == hdl)
2935     break;
2936    
2937     if (y != NIL)
2938     break;
2939    
2940     if (!all)
2941     return NIL;
2942     }
2943    
2944     if (x != NIL)
2945     return car (y);
2946    
2947     return NIL;
2948     }
2949    
2950     #else /* USE_ALIST_ENV */
2951    
2952     static INLINE void
2953     new_frame_in_env (SCHEME_P_ pointer old_env)
2954     {
2955     SCHEME_V->envir = immutable_cons (NIL, old_env);
2956     setenvironment (SCHEME_V->envir);
2957     }
2958    
2959     static INLINE void
2960     new_slot_spec_in_env (SCHEME_P_ pointer env, pointer variable, pointer value)
2961     {
2962     set_car (env, immutable_cons (immutable_cons (variable, value), car (env)));
2963     }
2964    
2965     static pointer
2966     find_slot_in_env (SCHEME_P_ pointer env, pointer hdl, int all)
2967     {
2968     pointer x, y;
2969    
2970     for (x = env; x != NIL; x = cdr (x))
2971     {
2972     for (y = car (x); y != NIL; y = cdr (y))
2973     if (caar (y) == hdl)
2974     break;
2975    
2976     if (y != NIL)
2977     break;
2978    
2979     if (!all)
2980     return NIL;
2981     }
2982    
2983     if (x != NIL)
2984     return car (y);
2985    
2986     return NIL;
2987     }
2988    
2989     #endif /* USE_ALIST_ENV else */
2990    
2991     static INLINE void
2992     new_slot_in_env (SCHEME_P_ pointer variable, pointer value)
2993     {
2994     new_slot_spec_in_env (SCHEME_A_ SCHEME_V->envir, variable, value);
2995     }
2996    
2997     static INLINE void
2998     set_slot_in_env (SCHEME_P_ pointer slot, pointer value)
2999     {
3000     set_cdr (slot, value);
3001     }
3002    
3003     static INLINE pointer
3004     slot_value_in_env (pointer slot)
3005     {
3006     return cdr (slot);
3007     }
3008    
3009     /* ========== Evaluation Cycle ========== */
3010    
3011     static pointer
3012     xError_1 (SCHEME_P_ const char *s, pointer a)
3013     {
3014     #if USE_ERROR_HOOK
3015     pointer x;
3016     pointer hdl = SCHEME_V->ERROR_HOOK;
3017     #endif
3018    
3019     #if USE_PRINTF
3020     #if SHOW_ERROR_LINE
3021     char sbuf[STRBUFFSIZE];
3022    
3023     /* make sure error is not in REPL */
3024     if ((SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file) && SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.file != STDIN_FILENO)
3025     {
3026     int ln = SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line;
3027     const char *fname = SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.filename;
3028    
3029     /* should never happen */
3030     if (!fname)
3031     fname = "<unknown>";
3032    
3033     /* we started from 0 */
3034     ln++;
3035     snprintf (sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s);
3036    
3037     s = sbuf;
3038     }
3039     #endif
3040     #endif
3041    
3042     #if USE_ERROR_HOOK
3043     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, hdl, 1);
3044    
3045     if (x != NIL)
3046     {
3047     if (a)
3048     SCHEME_V->code = cons (cons (SCHEME_V->QUOTE, cons (a, NIL)), NIL);
3049     else
3050     SCHEME_V->code = NIL;
3051    
3052     SCHEME_V->code = cons (mk_string (SCHEME_A_ s), SCHEME_V->code);
3053     setimmutable (car (SCHEME_V->code));
3054     SCHEME_V->code = cons (slot_value_in_env (x), SCHEME_V->code);
3055     SCHEME_V->op = OP_EVAL;
3056    
3057     return S_T;
3058     }
3059     #endif
3060    
3061     if (a)
3062     SCHEME_V->args = cons (a, NIL);
3063     else
3064     SCHEME_V->args = NIL;
3065    
3066     SCHEME_V->args = cons (mk_string (SCHEME_A_ s), SCHEME_V->args);
3067     setimmutable (car (SCHEME_V->args));
3068 root 1.2 SCHEME_V->op = OP_ERR0;
3069 root 1.1 return S_T;
3070     }
3071    
3072     #define Error_1(s, a) return xError_1(SCHEME_A_ USE_ERROR_CHECKING ? s : "", a)
3073     #define Error_0(s) Error_1 (s, 0)
3074    
3075     /* Too small to turn into function */
3076 root 1.2 #define BEGIN do {
3077     #define END } while (0)
3078     #define s_goto(a) BEGIN \
3079     SCHEME_V->op = a; \
3080 root 1.1 return S_T; END
3081    
3082 root 1.2 #define s_return(a) return xs_return (SCHEME_A_ a)
3083 root 1.1
3084     #ifndef USE_SCHEME_STACK
3085    
3086     /* this structure holds all the interpreter's registers */
3087     struct dump_stack_frame
3088     {
3089     enum scheme_opcodes op;
3090     pointer args;
3091     pointer envir;
3092     pointer code;
3093     };
3094    
3095     # define STACK_GROWTH 3
3096    
3097     static void
3098     s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3099     {
3100     int nframes = (uintptr_t)SCHEME_V->dump;
3101     struct dump_stack_frame *next_frame;
3102    
3103     /* enough room for the next frame? */
3104     if (nframes >= SCHEME_V->dump_size)
3105     {
3106     SCHEME_V->dump_size += STACK_GROWTH;
3107     SCHEME_V->dump_base = realloc (SCHEME_V->dump_base, sizeof (struct dump_stack_frame) * SCHEME_V->dump_size);
3108     }
3109    
3110     next_frame = SCHEME_V->dump_base + nframes;
3111 root 1.2
3112     next_frame->op = op;
3113     next_frame->args = args;
3114 root 1.1 next_frame->envir = SCHEME_V->envir;
3115 root 1.2 next_frame->code = code;
3116    
3117 root 1.1 SCHEME_V->dump = (pointer)(uintptr_t)(nframes + 1);
3118     }
3119    
3120     static pointer
3121     xs_return (SCHEME_P_ pointer a)
3122     {
3123     int nframes = (uintptr_t)SCHEME_V->dump;
3124     struct dump_stack_frame *frame;
3125    
3126     SCHEME_V->value = a;
3127    
3128     if (nframes <= 0)
3129     return NIL;
3130    
3131 root 1.2 frame = &SCHEME_V->dump_base[--nframes];
3132     SCHEME_V->op = frame->op;
3133     SCHEME_V->args = frame->args;
3134 root 1.1 SCHEME_V->envir = frame->envir;
3135 root 1.2 SCHEME_V->code = frame->code;
3136     SCHEME_V->dump = (pointer)(uintptr_t)nframes;
3137 root 1.1
3138     return S_T;
3139     }
3140    
3141     static INLINE void
3142     dump_stack_reset (SCHEME_P)
3143     {
3144     /* in this implementation, SCHEME_V->dump is the number of frames on the stack */
3145 root 1.2 SCHEME_V->dump = (pointer)+0;
3146 root 1.1 }
3147    
3148     static INLINE void
3149     dump_stack_initialize (SCHEME_P)
3150     {
3151     SCHEME_V->dump_size = 0;
3152 root 1.2 SCHEME_V->dump_base = 0;
3153 root 1.1 dump_stack_reset (SCHEME_A);
3154     }
3155    
3156     static void
3157     dump_stack_free (SCHEME_P)
3158     {
3159     free (SCHEME_V->dump_base);
3160 root 1.2 SCHEME_V->dump_base = 0;
3161 root 1.1 SCHEME_V->dump = (pointer)0;
3162     SCHEME_V->dump_size = 0;
3163     }
3164    
3165     static void
3166     dump_stack_mark (SCHEME_P)
3167     {
3168     int nframes = (uintptr_t)SCHEME_V->dump;
3169     int i;
3170    
3171     for (i = 0; i < nframes; i++)
3172     {
3173     struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3174    
3175     mark (frame->args);
3176     mark (frame->envir);
3177     mark (frame->code);
3178     }
3179     }
3180    
3181     static pointer
3182     ss_get_cont (SCHEME_P)
3183     {
3184     int nframes = (uintptr_t)SCHEME_V->dump;
3185     int i;
3186    
3187     pointer cont = NIL;
3188    
3189     for (i = nframes; i--; )
3190     {
3191     struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3192    
3193     cont = cons (mk_integer (SCHEME_A_ frame->op),
3194     cons (frame->args,
3195     cons (frame->envir,
3196     cons (frame->code,
3197     cont))));
3198     }
3199    
3200     return cont;
3201     }
3202    
3203     static void
3204     ss_set_cont (SCHEME_P_ pointer cont)
3205     {
3206     int i = 0;
3207     struct dump_stack_frame *frame = SCHEME_V->dump_base;
3208    
3209     while (cont != NIL)
3210     {
3211     frame->op = ivalue (car (cont)); cont = cdr (cont);
3212 root 1.2 frame->args = car (cont) ; cont = cdr (cont);
3213     frame->envir = car (cont) ; cont = cdr (cont);
3214     frame->code = car (cont) ; cont = cdr (cont);
3215 root 1.1
3216     ++frame;
3217     ++i;
3218     }
3219    
3220     SCHEME_V->dump = (pointer)(uintptr_t)i;
3221     }
3222    
3223     #else
3224    
3225     static INLINE void
3226     dump_stack_reset (SCHEME_P)
3227     {
3228     SCHEME_V->dump = NIL;
3229     }
3230    
3231     static INLINE void
3232     dump_stack_initialize (SCHEME_P)
3233     {
3234     dump_stack_reset (SCHEME_A);
3235     }
3236    
3237     static void
3238     dump_stack_free (SCHEME_P)
3239     {
3240     SCHEME_V->dump = NIL;
3241     }
3242    
3243     static pointer
3244     xs_return (SCHEME_P_ pointer a)
3245     {
3246     pointer dump = SCHEME_V->dump;
3247    
3248     SCHEME_V->value = a;
3249    
3250     if (dump == NIL)
3251     return NIL;
3252    
3253 root 1.2 SCHEME_V->op = ivalue (car (dump)); dump = cdr (dump);
3254     SCHEME_V->args = car (dump) ; dump = cdr (dump);
3255     SCHEME_V->envir = car (dump) ; dump = cdr (dump);
3256     SCHEME_V->code = car (dump) ; dump = cdr (dump);
3257 root 1.1
3258     SCHEME_V->dump = dump;
3259    
3260     return S_T;
3261     }
3262    
3263     static void
3264     s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3265     {
3266     SCHEME_V->dump = cons (mk_integer (SCHEME_A_ op),
3267     cons (args,
3268     cons (SCHEME_V->envir,
3269     cons (code,
3270     SCHEME_V->dump))));
3271     }
3272    
3273     static void
3274     dump_stack_mark (SCHEME_P)
3275     {
3276     mark (SCHEME_V->dump);
3277     }
3278    
3279     static pointer
3280     ss_get_cont (SCHEME_P)
3281     {
3282     return SCHEME_V->dump;
3283     }
3284    
3285     static void
3286     ss_set_cont (SCHEME_P_ pointer cont)
3287     {
3288     SCHEME_V->dump = cont;
3289     }
3290    
3291     #endif
3292    
3293     #define s_retbool(tf) s_return ((tf) ? S_T : S_F)
3294    
3295     static pointer
3296     opexe_0 (SCHEME_P_ enum scheme_opcodes op)
3297     {
3298     pointer x, y;
3299    
3300     switch (op)
3301     {
3302     case OP_LOAD: /* load */
3303     if (file_interactive (SCHEME_A))
3304     {
3305     xwrstr ("Loading "); xwrstr (strvalue (car (SCHEME_V->args))); xwrstr ("\n");
3306     //D fprintf (SCHEME_V->outport->object.port->rep.stdio.file, "Loading %s\n", strvalue (car (SCHEME_V->args)));
3307     }
3308    
3309     if (!file_push (SCHEME_A_ strvalue (car (SCHEME_V->args))))
3310     Error_1 ("unable to open", car (SCHEME_V->args));
3311     else
3312     {
3313     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
3314     s_goto (OP_T0LVL);
3315     }
3316    
3317     case OP_T0LVL: /* top level */
3318    
3319     /* If we reached the end of file, this loop is done. */
3320     if (SCHEME_V->loadport->object.port->kind & port_saw_EOF)
3321     {
3322     if (SCHEME_V->file_i == 0)
3323     {
3324     SCHEME_V->args = NIL;
3325     s_goto (OP_QUIT);
3326     }
3327     else
3328     {
3329     file_pop (SCHEME_A);
3330     s_return (SCHEME_V->value);
3331     }
3332    
3333     /* NOTREACHED */
3334     }
3335    
3336     /* If interactive, be nice to user. */
3337     if (file_interactive (SCHEME_A))
3338     {
3339     SCHEME_V->envir = SCHEME_V->global_env;
3340     dump_stack_reset (SCHEME_A);
3341     putstr (SCHEME_A_ "\n");
3342     putstr (SCHEME_A_ prompt);
3343     }
3344    
3345     /* Set up another iteration of REPL */
3346     SCHEME_V->nesting = 0;
3347     SCHEME_V->save_inport = SCHEME_V->inport;
3348     SCHEME_V->inport = SCHEME_V->loadport;
3349     s_save (SCHEME_A_ OP_T0LVL, NIL, NIL);
3350     s_save (SCHEME_A_ OP_VALUEPRINT, NIL, NIL);
3351     s_save (SCHEME_A_ OP_T1LVL, NIL, NIL);
3352     s_goto (OP_READ_INTERNAL);
3353    
3354     case OP_T1LVL: /* top level */
3355     SCHEME_V->code = SCHEME_V->value;
3356     SCHEME_V->inport = SCHEME_V->save_inport;
3357     s_goto (OP_EVAL);
3358    
3359     case OP_READ_INTERNAL: /* internal read */
3360     SCHEME_V->tok = token (SCHEME_A);
3361    
3362     if (SCHEME_V->tok == TOK_EOF)
3363 root 1.2 s_return (S_EOF);
3364 root 1.1
3365     s_goto (OP_RDSEXPR);
3366    
3367     case OP_GENSYM:
3368     s_return (gensym (SCHEME_A));
3369    
3370     case OP_VALUEPRINT: /* print evaluation result */
3371    
3372     /* OP_VALUEPRINT is always pushed, because when changing from
3373     non-interactive to interactive mode, it needs to be
3374     already on the stack */
3375     #if USE_TRACING
3376     if (SCHEME_V->tracing)
3377 root 1.2 putstr (SCHEME_A_ "\nGives: ");
3378 root 1.1 #endif
3379    
3380     if (file_interactive (SCHEME_A))
3381     {
3382     SCHEME_V->print_flag = 1;
3383     SCHEME_V->args = SCHEME_V->value;
3384     s_goto (OP_P0LIST);
3385     }
3386     else
3387 root 1.2 s_return (SCHEME_V->value);
3388 root 1.1
3389     case OP_EVAL: /* main part of evaluation */
3390     #if USE_TRACING
3391     if (SCHEME_V->tracing)
3392     {
3393     /*s_save(SCHEME_A_ OP_VALUEPRINT,NIL,NIL); */
3394     s_save (SCHEME_A_ OP_REAL_EVAL, SCHEME_V->args, SCHEME_V->code);
3395     SCHEME_V->args = SCHEME_V->code;
3396     putstr (SCHEME_A_ "\nEval: ");
3397     s_goto (OP_P0LIST);
3398     }
3399    
3400     /* fall through */
3401 root 1.2
3402 root 1.1 case OP_REAL_EVAL:
3403     #endif
3404     if (is_symbol (SCHEME_V->code)) /* symbol */
3405     {
3406     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3407    
3408     if (x != NIL)
3409     s_return (slot_value_in_env (x));
3410     else
3411     Error_1 ("eval: unbound variable:", SCHEME_V->code);
3412     }
3413     else if (is_pair (SCHEME_V->code))
3414     {
3415     if (is_syntax (x = car (SCHEME_V->code))) /* SYNTAX */
3416     {
3417     SCHEME_V->code = cdr (SCHEME_V->code);
3418     s_goto (syntaxnum (x));
3419     }
3420     else /* first, eval top element and eval arguments */
3421     {
3422     s_save (SCHEME_A_ OP_E0ARGS, NIL, SCHEME_V->code);
3423     /* If no macros => s_save(SCHEME_A_ OP_E1ARGS, NIL, cdr(SCHEME_V->code)); */
3424     SCHEME_V->code = car (SCHEME_V->code);
3425     s_goto (OP_EVAL);
3426     }
3427     }
3428     else
3429     s_return (SCHEME_V->code);
3430    
3431     case OP_E0ARGS: /* eval arguments */
3432     if (is_macro (SCHEME_V->value)) /* macro expansion */
3433     {
3434     s_save (SCHEME_A_ OP_DOMACRO, NIL, NIL);
3435     SCHEME_V->args = cons (SCHEME_V->code, NIL);
3436     SCHEME_V->code = SCHEME_V->value;
3437     s_goto (OP_APPLY);
3438     }
3439     else
3440     {
3441     SCHEME_V->code = cdr (SCHEME_V->code);
3442     s_goto (OP_E1ARGS);
3443     }
3444    
3445     case OP_E1ARGS: /* eval arguments */
3446     SCHEME_V->args = cons (SCHEME_V->value, SCHEME_V->args);
3447    
3448     if (is_pair (SCHEME_V->code)) /* continue */
3449     {
3450     s_save (SCHEME_A_ OP_E1ARGS, SCHEME_V->args, cdr (SCHEME_V->code));
3451     SCHEME_V->code = car (SCHEME_V->code);
3452     SCHEME_V->args = NIL;
3453     s_goto (OP_EVAL);
3454     }
3455     else /* end */
3456     {
3457     SCHEME_V->args = reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args);
3458     SCHEME_V->code = car (SCHEME_V->args);
3459     SCHEME_V->args = cdr (SCHEME_V->args);
3460     s_goto (OP_APPLY);
3461     }
3462    
3463     #if USE_TRACING
3464    
3465     case OP_TRACING:
3466     {
3467     int tr = SCHEME_V->tracing;
3468    
3469     SCHEME_V->tracing = ivalue (car (SCHEME_V->args));
3470     s_return (mk_integer (SCHEME_A_ tr));
3471     }
3472    
3473     #endif
3474    
3475     case OP_APPLY: /* apply 'code' to 'args' */
3476     #if USE_TRACING
3477     if (SCHEME_V->tracing)
3478     {
3479     s_save (SCHEME_A_ OP_REAL_APPLY, SCHEME_V->args, SCHEME_V->code);
3480     SCHEME_V->print_flag = 1;
3481     /* SCHEME_V->args=cons(SCHEME_V->code,SCHEME_V->args); */
3482     putstr (SCHEME_A_ "\nApply to: ");
3483     s_goto (OP_P0LIST);
3484     }
3485    
3486     /* fall through */
3487 root 1.2
3488 root 1.1 case OP_REAL_APPLY:
3489     #endif
3490     if (is_proc (SCHEME_V->code))
3491     {
3492     s_goto (procnum (SCHEME_V->code)); /* PROCEDURE */
3493     }
3494     else if (is_foreign (SCHEME_V->code))
3495     {
3496     /* Keep nested calls from GC'ing the arglist */
3497     push_recent_alloc (SCHEME_A_ SCHEME_V->args, NIL);
3498     x = SCHEME_V->code->object.ff (SCHEME_A_ SCHEME_V->args);
3499    
3500     s_return (x);
3501     }
3502     else if (is_closure (SCHEME_V->code) || is_macro (SCHEME_V->code) || is_promise (SCHEME_V->code)) /* CLOSURE */
3503     {
3504     /* Should not accept promise */
3505     /* make environment */
3506     new_frame_in_env (SCHEME_A_ closure_env (SCHEME_V->code));
3507    
3508     for (x = car (closure_code (SCHEME_V->code)), y = SCHEME_V->args; is_pair (x); x = cdr (x), y = cdr (y))
3509     {
3510     if (y == NIL)
3511 root 1.2 Error_0 ("not enough arguments");
3512 root 1.1 else
3513 root 1.2 new_slot_in_env (SCHEME_A_ car (x), car (y));
3514 root 1.1 }
3515    
3516     if (x == NIL)
3517     {
3518 root 1.2 /*--
3519     * if (y != NIL) {
3520     * Error_0("too many arguments");
3521     * }
3522     */
3523 root 1.1 }
3524     else if (is_symbol (x))
3525     new_slot_in_env (SCHEME_A_ x, y);
3526     else
3527 root 1.2 Error_1 ("syntax error in closure: not a symbol:", x);
3528 root 1.1
3529     SCHEME_V->code = cdr (closure_code (SCHEME_V->code));
3530     SCHEME_V->args = NIL;
3531     s_goto (OP_BEGIN);
3532     }
3533     else if (is_continuation (SCHEME_V->code)) /* CONTINUATION */
3534     {
3535     ss_set_cont (SCHEME_A_ cont_dump (SCHEME_V->code));
3536     s_return (SCHEME_V->args != NIL ? car (SCHEME_V->args) : NIL);
3537     }
3538     else
3539     Error_0 ("illegal function");
3540    
3541     case OP_DOMACRO: /* do macro */
3542     SCHEME_V->code = SCHEME_V->value;
3543     s_goto (OP_EVAL);
3544    
3545     #if 1
3546    
3547     case OP_LAMBDA: /* lambda */
3548     /* If the hook is defined, apply it to SCHEME_V->code, otherwise
3549     set SCHEME_V->value fall thru */
3550     {
3551     pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->COMPILE_HOOK, 1);
3552    
3553     if (f != NIL)
3554     {
3555     s_save (SCHEME_A_ OP_LAMBDA1, SCHEME_V->args, SCHEME_V->code);
3556     SCHEME_V->args = cons (SCHEME_V->code, NIL);
3557     SCHEME_V->code = slot_value_in_env (f);
3558     s_goto (OP_APPLY);
3559     }
3560    
3561     SCHEME_V->value = SCHEME_V->code;
3562     /* Fallthru */
3563     }
3564    
3565     case OP_LAMBDA1:
3566     s_return (mk_closure (SCHEME_A_ SCHEME_V->value, SCHEME_V->envir));
3567    
3568     #else
3569    
3570     case OP_LAMBDA: /* lambda */
3571     s_return (mk_closure (SCHEME_A_ SCHEME_V->code, SCHEME_V->envir));
3572    
3573     #endif
3574    
3575     case OP_MKCLOSURE: /* make-closure */
3576     x = car (SCHEME_V->args);
3577    
3578     if (car (x) == SCHEME_V->LAMBDA)
3579     x = cdr (x);
3580    
3581     if (cdr (SCHEME_V->args) == NIL)
3582     y = SCHEME_V->envir;
3583     else
3584     y = cadr (SCHEME_V->args);
3585    
3586     s_return (mk_closure (SCHEME_A_ x, y));
3587    
3588     case OP_QUOTE: /* quote */
3589     s_return (car (SCHEME_V->code));
3590    
3591     case OP_DEF0: /* define */
3592     if (is_immutable (car (SCHEME_V->code)))
3593     Error_1 ("define: unable to alter immutable", car (SCHEME_V->code));
3594    
3595     if (is_pair (car (SCHEME_V->code)))
3596     {
3597     x = caar (SCHEME_V->code);
3598     SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3599     }
3600     else
3601     {
3602     x = car (SCHEME_V->code);
3603     SCHEME_V->code = cadr (SCHEME_V->code);
3604     }
3605    
3606     if (!is_symbol (x))
3607 root 1.2 Error_0 ("variable is not a symbol");
3608 root 1.1
3609     s_save (SCHEME_A_ OP_DEF1, NIL, x);
3610     s_goto (OP_EVAL);
3611    
3612     case OP_DEF1: /* define */
3613     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3614    
3615     if (x != NIL)
3616 root 1.2 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3617 root 1.1 else
3618 root 1.2 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3619 root 1.1
3620     s_return (SCHEME_V->code);
3621    
3622    
3623     case OP_DEFP: /* defined? */
3624     x = SCHEME_V->envir;
3625    
3626     if (cdr (SCHEME_V->args) != NIL)
3627 root 1.2 x = cadr (SCHEME_V->args);
3628 root 1.1
3629     s_retbool (find_slot_in_env (SCHEME_A_ x, car (SCHEME_V->args), 1) != NIL);
3630    
3631     case OP_SET0: /* set! */
3632     if (is_immutable (car (SCHEME_V->code)))
3633     Error_1 ("set!: unable to alter immutable variable", car (SCHEME_V->code));
3634    
3635     s_save (SCHEME_A_ OP_SET1, NIL, car (SCHEME_V->code));
3636     SCHEME_V->code = cadr (SCHEME_V->code);
3637     s_goto (OP_EVAL);
3638    
3639     case OP_SET1: /* set! */
3640     y = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3641    
3642     if (y != NIL)
3643     {
3644     set_slot_in_env (SCHEME_A_ y, SCHEME_V->value);
3645     s_return (SCHEME_V->value);
3646     }
3647     else
3648 root 1.2 Error_1 ("set!: unbound variable:", SCHEME_V->code);
3649 root 1.1
3650    
3651     case OP_BEGIN: /* begin */
3652     if (!is_pair (SCHEME_V->code))
3653 root 1.2 s_return (SCHEME_V->code);
3654 root 1.1
3655     if (cdr (SCHEME_V->code) != NIL)
3656 root 1.2 s_save (SCHEME_A_ OP_BEGIN, NIL, cdr (SCHEME_V->code));
3657 root 1.1
3658     SCHEME_V->code = car (SCHEME_V->code);
3659     s_goto (OP_EVAL);
3660    
3661     case OP_IF0: /* if */
3662     s_save (SCHEME_A_ OP_IF1, NIL, cdr (SCHEME_V->code));
3663     SCHEME_V->code = car (SCHEME_V->code);
3664     s_goto (OP_EVAL);
3665    
3666     case OP_IF1: /* if */
3667     if (is_true (SCHEME_V->value))
3668     SCHEME_V->code = car (SCHEME_V->code);
3669     else
3670     SCHEME_V->code = cadr (SCHEME_V->code); /* (if #f 1) ==> () because
3671    
3672     * car(NIL) = NIL */
3673     s_goto (OP_EVAL);
3674    
3675     case OP_LET0: /* let */
3676     SCHEME_V->args = NIL;
3677     SCHEME_V->value = SCHEME_V->code;
3678     SCHEME_V->code = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code);
3679     s_goto (OP_LET1);
3680    
3681     case OP_LET1: /* let (calculate parameters) */
3682     SCHEME_V->args = cons (SCHEME_V->value, SCHEME_V->args);
3683    
3684     if (is_pair (SCHEME_V->code)) /* continue */
3685     {
3686     if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3687 root 1.2 Error_1 ("Bad syntax of binding spec in let :", car (SCHEME_V->code));
3688 root 1.1
3689     s_save (SCHEME_A_ OP_LET1, SCHEME_V->args, cdr (SCHEME_V->code));
3690     SCHEME_V->code = cadar (SCHEME_V->code);
3691     SCHEME_V->args = NIL;
3692     s_goto (OP_EVAL);
3693     }
3694     else /* end */
3695     {
3696     SCHEME_V->args = reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args);
3697     SCHEME_V->code = car (SCHEME_V->args);
3698     SCHEME_V->args = cdr (SCHEME_V->args);
3699     s_goto (OP_LET2);
3700     }
3701    
3702     case OP_LET2: /* let */
3703     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3704    
3705     for (x = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code), y = SCHEME_V->args;
3706     y != NIL; x = cdr (x), y = cdr (y))
3707 root 1.2 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3708 root 1.1
3709     if (is_symbol (car (SCHEME_V->code))) /* named let */
3710     {
3711     for (x = cadr (SCHEME_V->code), SCHEME_V->args = NIL; x != NIL; x = cdr (x))
3712     {
3713     if (!is_pair (x))
3714     Error_1 ("Bad syntax of binding in let :", x);
3715    
3716     if (!is_list (SCHEME_A_ car (x)))
3717     Error_1 ("Bad syntax of binding in let :", car (x));
3718    
3719     SCHEME_V->args = cons (caar (x), SCHEME_V->args);
3720     }
3721    
3722     x =
3723     mk_closure (SCHEME_A_ cons (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args), cddr (SCHEME_V->code)),
3724     SCHEME_V->envir);
3725     new_slot_in_env (SCHEME_A_ car (SCHEME_V->code), x);
3726     SCHEME_V->code = cddr (SCHEME_V->code);
3727     SCHEME_V->args = NIL;
3728     }
3729     else
3730     {
3731     SCHEME_V->code = cdr (SCHEME_V->code);
3732     SCHEME_V->args = NIL;
3733     }
3734    
3735     s_goto (OP_BEGIN);
3736    
3737     case OP_LET0AST: /* let* */
3738     if (car (SCHEME_V->code) == NIL)
3739     {
3740     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3741     SCHEME_V->code = cdr (SCHEME_V->code);
3742     s_goto (OP_BEGIN);
3743     }
3744    
3745     if (!is_pair (car (SCHEME_V->code)) || !is_pair (caar (SCHEME_V->code)) || !is_pair (cdaar (SCHEME_V->code)))
3746     Error_1 ("Bad syntax of binding spec in let* :", car (SCHEME_V->code));
3747    
3748     s_save (SCHEME_A_ OP_LET1AST, cdr (SCHEME_V->code), car (SCHEME_V->code));
3749     SCHEME_V->code = car (cdaar (SCHEME_V->code));
3750     s_goto (OP_EVAL);
3751    
3752     case OP_LET1AST: /* let* (make new frame) */
3753     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3754     s_goto (OP_LET2AST);
3755    
3756     case OP_LET2AST: /* let* (calculate parameters) */
3757     new_slot_in_env (SCHEME_A_ caar (SCHEME_V->code), SCHEME_V->value);
3758     SCHEME_V->code = cdr (SCHEME_V->code);
3759    
3760     if (is_pair (SCHEME_V->code)) /* continue */
3761     {
3762     s_save (SCHEME_A_ OP_LET2AST, SCHEME_V->args, SCHEME_V->code);
3763     SCHEME_V->code = cadar (SCHEME_V->code);
3764     SCHEME_V->args = NIL;
3765     s_goto (OP_EVAL);
3766     }
3767     else /* end */
3768     {
3769     SCHEME_V->code = SCHEME_V->args;
3770     SCHEME_V->args = NIL;
3771     s_goto (OP_BEGIN);
3772     }
3773    
3774     case OP_LET0REC: /* letrec */
3775     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3776     SCHEME_V->args = NIL;
3777     SCHEME_V->value = SCHEME_V->code;
3778     SCHEME_V->code = car (SCHEME_V->code);
3779     s_goto (OP_LET1REC);
3780    
3781     case OP_LET1REC: /* letrec (calculate parameters) */
3782     SCHEME_V->args = cons (SCHEME_V->value, SCHEME_V->args);
3783    
3784     if (is_pair (SCHEME_V->code)) /* continue */
3785     {
3786     if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3787 root 1.2 Error_1 ("Bad syntax of binding spec in letrec :", car (SCHEME_V->code));
3788 root 1.1
3789     s_save (SCHEME_A_ OP_LET1REC, SCHEME_V->args, cdr (SCHEME_V->code));
3790     SCHEME_V->code = cadar (SCHEME_V->code);
3791     SCHEME_V->args = NIL;
3792     s_goto (OP_EVAL);
3793     }
3794     else /* end */
3795     {
3796     SCHEME_V->args = reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args);
3797     SCHEME_V->code = car (SCHEME_V->args);
3798     SCHEME_V->args = cdr (SCHEME_V->args);
3799     s_goto (OP_LET2REC);
3800     }
3801    
3802     case OP_LET2REC: /* letrec */
3803     for (x = car (SCHEME_V->code), y = SCHEME_V->args; y != NIL; x = cdr (x), y = cdr (y))
3804 root 1.2 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3805 root 1.1
3806     SCHEME_V->code = cdr (SCHEME_V->code);
3807     SCHEME_V->args = NIL;
3808     s_goto (OP_BEGIN);
3809    
3810     case OP_COND0: /* cond */
3811     if (!is_pair (SCHEME_V->code))
3812 root 1.2 Error_0 ("syntax error in cond");
3813 root 1.1
3814     s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3815     SCHEME_V->code = caar (SCHEME_V->code);
3816     s_goto (OP_EVAL);
3817    
3818     case OP_COND1: /* cond */
3819     if (is_true (SCHEME_V->value))
3820     {
3821     if ((SCHEME_V->code = cdar (SCHEME_V->code)) == NIL)
3822 root 1.2 s_return (SCHEME_V->value);
3823 root 1.1
3824     if (car (SCHEME_V->code) == SCHEME_V->FEED_TO)
3825     {
3826     if (!is_pair (cdr (SCHEME_V->code)))
3827 root 1.2 Error_0 ("syntax error in cond");
3828 root 1.1
3829     x = cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL));
3830     SCHEME_V->code = cons (cadr (SCHEME_V->code), cons (x, NIL));
3831     s_goto (OP_EVAL);
3832     }
3833    
3834     s_goto (OP_BEGIN);
3835     }
3836     else
3837     {
3838     if ((SCHEME_V->code = cdr (SCHEME_V->code)) == NIL)
3839 root 1.2 s_return (NIL);
3840 root 1.1 else
3841     {
3842     s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3843     SCHEME_V->code = caar (SCHEME_V->code);
3844     s_goto (OP_EVAL);
3845     }
3846     }
3847    
3848     case OP_DELAY: /* delay */
3849     x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3850     set_typeflag (x, T_PROMISE);
3851     s_return (x);
3852    
3853     case OP_AND0: /* and */
3854     if (SCHEME_V->code == NIL)
3855 root 1.2 s_return (S_T);
3856 root 1.1
3857     s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3858     SCHEME_V->code = car (SCHEME_V->code);
3859     s_goto (OP_EVAL);
3860    
3861     case OP_AND1: /* and */
3862     if (is_false (SCHEME_V->value))
3863 root 1.2 s_return (SCHEME_V->value);
3864 root 1.1 else if (SCHEME_V->code == NIL)
3865 root 1.2 s_return (SCHEME_V->value);
3866 root 1.1 else
3867     {
3868     s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3869     SCHEME_V->code = car (SCHEME_V->code);
3870     s_goto (OP_EVAL);
3871     }
3872    
3873     case OP_OR0: /* or */
3874     if (SCHEME_V->code == NIL)
3875 root 1.2 s_return (S_F);
3876 root 1.1
3877     s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3878     SCHEME_V->code = car (SCHEME_V->code);
3879     s_goto (OP_EVAL);
3880    
3881     case OP_OR1: /* or */
3882     if (is_true (SCHEME_V->value))
3883 root 1.2 s_return (SCHEME_V->value);
3884 root 1.1 else if (SCHEME_V->code == NIL)
3885 root 1.2 s_return (SCHEME_V->value);
3886 root 1.1 else
3887     {
3888     s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3889     SCHEME_V->code = car (SCHEME_V->code);
3890     s_goto (OP_EVAL);
3891     }
3892    
3893     case OP_C0STREAM: /* cons-stream */
3894     s_save (SCHEME_A_ OP_C1STREAM, NIL, cdr (SCHEME_V->code));
3895     SCHEME_V->code = car (SCHEME_V->code);
3896     s_goto (OP_EVAL);
3897    
3898     case OP_C1STREAM: /* cons-stream */
3899     SCHEME_V->args = SCHEME_V->value; /* save SCHEME_V->value to register SCHEME_V->args for gc */
3900     x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3901     set_typeflag (x, T_PROMISE);
3902     s_return (cons (SCHEME_V->args, x));
3903    
3904     case OP_MACRO0: /* macro */
3905     if (is_pair (car (SCHEME_V->code)))
3906     {
3907     x = caar (SCHEME_V->code);
3908     SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3909     }
3910     else
3911     {
3912     x = car (SCHEME_V->code);
3913     SCHEME_V->code = cadr (SCHEME_V->code);
3914     }
3915    
3916     if (!is_symbol (x))
3917 root 1.2 Error_0 ("variable is not a symbol");
3918 root 1.1
3919     s_save (SCHEME_A_ OP_MACRO1, NIL, x);
3920     s_goto (OP_EVAL);
3921    
3922     case OP_MACRO1: /* macro */
3923     set_typeflag (SCHEME_V->value, T_MACRO);
3924     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3925    
3926     if (x != NIL)
3927 root 1.2 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3928 root 1.1 else
3929 root 1.2 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3930 root 1.1
3931     s_return (SCHEME_V->code);
3932    
3933     case OP_CASE0: /* case */
3934     s_save (SCHEME_A_ OP_CASE1, NIL, cdr (SCHEME_V->code));
3935     SCHEME_V->code = car (SCHEME_V->code);
3936     s_goto (OP_EVAL);
3937    
3938     case OP_CASE1: /* case */
3939     for (x = SCHEME_V->code; x != NIL; x = cdr (x))
3940     {
3941     if (!is_pair (y = caar (x)))
3942 root 1.2 break;
3943 root 1.1
3944     for (; y != NIL; y = cdr (y))
3945     {
3946     if (eqv (car (y), SCHEME_V->value))
3947 root 1.2 break;
3948 root 1.1 }
3949    
3950     if (y != NIL)
3951 root 1.2 break;
3952 root 1.1 }
3953    
3954     if (x != NIL)
3955     {
3956     if (is_pair (caar (x)))
3957     {
3958     SCHEME_V->code = cdar (x);
3959     s_goto (OP_BEGIN);
3960     }
3961     else /* else */
3962     {
3963     s_save (SCHEME_A_ OP_CASE2, NIL, cdar (x));
3964     SCHEME_V->code = caar (x);
3965     s_goto (OP_EVAL);
3966     }
3967     }
3968     else
3969 root 1.2 s_return (NIL);
3970 root 1.1
3971     case OP_CASE2: /* case */
3972     if (is_true (SCHEME_V->value))
3973 root 1.2 s_goto (OP_BEGIN);
3974 root 1.1 else
3975 root 1.2 s_return (NIL);
3976 root 1.1
3977     case OP_PAPPLY: /* apply */
3978     SCHEME_V->code = car (SCHEME_V->args);
3979     SCHEME_V->args = list_star (SCHEME_A_ cdr (SCHEME_V->args));
3980     /*SCHEME_V->args = cadr(SCHEME_V->args); */
3981     s_goto (OP_APPLY);
3982    
3983     case OP_PEVAL: /* eval */
3984     if (cdr (SCHEME_V->args) != NIL)
3985 root 1.2 SCHEME_V->envir = cadr (SCHEME_V->args);
3986 root 1.1
3987     SCHEME_V->code = car (SCHEME_V->args);
3988     s_goto (OP_EVAL);
3989    
3990     case OP_CONTINUATION: /* call-with-current-continuation */
3991     SCHEME_V->code = car (SCHEME_V->args);
3992     SCHEME_V->args = cons (mk_continuation (SCHEME_A_ ss_get_cont (SCHEME_V)), NIL);
3993     s_goto (OP_APPLY);
3994     }
3995    
3996     return S_T;
3997     }
3998    
3999     static pointer
4000     opexe_2 (SCHEME_P_ enum scheme_opcodes op)
4001     {
4002     pointer x;
4003     num v;
4004    
4005     #if USE_MATH
4006     RVALUE dd;
4007     #endif
4008    
4009     switch (op)
4010     {
4011     #if USE_MATH
4012    
4013     case OP_INEX2EX: /* inexact->exact */
4014     x = car (SCHEME_V->args);
4015    
4016     if (num_is_integer (x))
4017 root 1.2 s_return (x);
4018 root 1.1 else if (modf (rvalue_unchecked (x), &dd) == 0.0)
4019 root 1.2 s_return (mk_integer (SCHEME_A_ ivalue (x)));
4020 root 1.1 else
4021 root 1.2 Error_1 ("inexact->exact: not integral:", x);
4022 root 1.1
4023     case OP_EXP:
4024     x = car (SCHEME_V->args);
4025     s_return (mk_real (SCHEME_A_ exp (rvalue (x))));
4026    
4027     case OP_LOG:
4028     x = car (SCHEME_V->args);
4029     s_return (mk_real (SCHEME_A_ log (rvalue (x))));
4030    
4031     case OP_SIN:
4032     x = car (SCHEME_V->args);
4033     s_return (mk_real (SCHEME_A_ sin (rvalue (x))));
4034    
4035     case OP_COS:
4036     x = car (SCHEME_V->args);
4037     s_return (mk_real (SCHEME_A_ cos (rvalue (x))));
4038    
4039     case OP_TAN:
4040     x = car (SCHEME_V->args);
4041     s_return (mk_real (SCHEME_A_ tan (rvalue (x))));
4042    
4043     case OP_ASIN:
4044     x = car (SCHEME_V->args);
4045     s_return (mk_real (SCHEME_A_ asin (rvalue (x))));
4046    
4047     case OP_ACOS:
4048     x = car (SCHEME_V->args);
4049     s_return (mk_real (SCHEME_A_ acos (rvalue (x))));
4050    
4051     case OP_ATAN:
4052     x = car (SCHEME_V->args);
4053    
4054     if (cdr (SCHEME_V->args) == NIL)
4055 root 1.2 s_return (mk_real (SCHEME_A_ atan (rvalue (x))));
4056 root 1.1 else
4057     {
4058     pointer y = cadr (SCHEME_V->args);
4059    
4060     s_return (mk_real (SCHEME_A_ atan2 (rvalue (x), rvalue (y))));
4061     }
4062    
4063     case OP_SQRT:
4064     x = car (SCHEME_V->args);
4065     s_return (mk_real (SCHEME_A_ sqrt (rvalue (x))));
4066    
4067     case OP_EXPT:
4068     {
4069     RVALUE result;
4070     int real_result = 1;
4071     pointer y = cadr (SCHEME_V->args);
4072    
4073     x = car (SCHEME_V->args);
4074    
4075     if (num_is_integer (x) && num_is_integer (y))
4076     real_result = 0;
4077    
4078     /* This 'if' is an R5RS compatibility fix. */
4079     /* NOTE: Remove this 'if' fix for R6RS. */
4080     if (rvalue (x) == 0 && rvalue (y) < 0)
4081 root 1.2 result = 0.0;
4082 root 1.1 else
4083 root 1.2 result = pow (rvalue (x), rvalue (y));
4084 root 1.1
4085     /* Before returning integer result make sure we can. */
4086     /* If the test fails, result is too big for integer. */
4087     if (!real_result)
4088     {
4089     long result_as_long = (long) result;
4090    
4091     if (result != (RVALUE) result_as_long)
4092     real_result = 1;
4093     }
4094    
4095     if (real_result)
4096 root 1.2 s_return (mk_real (SCHEME_A_ result));
4097 root 1.1 else
4098 root 1.2 s_return (mk_integer (SCHEME_A_ result));
4099 root 1.1 }
4100    
4101     case OP_FLOOR:
4102     x = car (SCHEME_V->args);
4103     s_return (mk_real (SCHEME_A_ floor (rvalue (x))));
4104    
4105     case OP_CEILING:
4106     x = car (SCHEME_V->args);
4107     s_return (mk_real (SCHEME_A_ ceil (rvalue (x))));
4108    
4109     case OP_TRUNCATE:
4110     {
4111     RVALUE rvalue_of_x;
4112    
4113     x = car (SCHEME_V->args);
4114     rvalue_of_x = rvalue (x);
4115    
4116     if (rvalue_of_x > 0)
4117 root 1.2 s_return (mk_real (SCHEME_A_ floor (rvalue_of_x)));
4118 root 1.1 else
4119 root 1.2 s_return (mk_real (SCHEME_A_ ceil (rvalue_of_x)));
4120 root 1.1 }
4121    
4122     case OP_ROUND:
4123     x = car (SCHEME_V->args);
4124    
4125     if (num_is_integer (x))
4126     s_return (x);
4127    
4128     s_return (mk_real (SCHEME_A_ round_per_R5RS (rvalue (x))));
4129     #endif
4130    
4131     case OP_ADD: /* + */
4132     v = num_zero;
4133    
4134     for (x = SCHEME_V->args; x != NIL; x = cdr (x))
4135     v = num_add (v, nvalue (car (x)));
4136    
4137     s_return (mk_number (SCHEME_A_ v));
4138    
4139     case OP_MUL: /* * */
4140     v = num_one;
4141    
4142     for (x = SCHEME_V->args; x != NIL; x = cdr (x))
4143     v = num_mul (v, nvalue (car (x)));
4144    
4145     s_return (mk_number (SCHEME_A_ v));
4146    
4147     case OP_SUB: /* - */
4148     if (cdr (SCHEME_V->args) == NIL)
4149     {
4150     x = SCHEME_V->args;
4151     v = num_zero;
4152     }
4153     else
4154     {
4155     x = cdr (SCHEME_V->args);
4156     v = nvalue (car (SCHEME_V->args));
4157     }
4158    
4159     for (; x != NIL; x = cdr (x))
4160     v = num_sub (v, nvalue (car (x)));
4161    
4162     s_return (mk_number (SCHEME_A_ v));
4163    
4164     case OP_DIV: /* / */
4165     if (cdr (SCHEME_V->args) == NIL)
4166     {
4167     x = SCHEME_V->args;
4168     v = num_one;
4169     }
4170     else
4171     {
4172     x = cdr (SCHEME_V->args);
4173     v = nvalue (car (SCHEME_V->args));
4174     }
4175    
4176     for (; x != NIL; x = cdr (x))
4177     {
4178     if (!is_zero_rvalue (rvalue (car (x))))
4179     v = num_div (v, nvalue (car (x)));
4180     else
4181     Error_0 ("/: division by zero");
4182     }
4183    
4184     s_return (mk_number (SCHEME_A_ v));
4185    
4186     case OP_INTDIV: /* quotient */
4187     if (cdr (SCHEME_V->args) == NIL)
4188     {
4189     x = SCHEME_V->args;
4190     v = num_one;
4191     }
4192     else
4193     {
4194     x = cdr (SCHEME_V->args);
4195     v = nvalue (car (SCHEME_V->args));
4196     }
4197    
4198     for (; x != NIL; x = cdr (x))
4199     {
4200     if (ivalue (car (x)) != 0)
4201     v = num_intdiv (v, nvalue (car (x)));
4202     else
4203     Error_0 ("quotient: division by zero");
4204     }
4205    
4206     s_return (mk_number (SCHEME_A_ v));
4207    
4208     case OP_REM: /* remainder */
4209     v = nvalue (car (SCHEME_V->args));
4210    
4211     if (ivalue (cadr (SCHEME_V->args)) != 0)
4212     v = num_rem (v, nvalue (cadr (SCHEME_V->args)));
4213     else
4214     Error_0 ("remainder: division by zero");
4215    
4216     s_return (mk_number (SCHEME_A_ v));
4217    
4218     case OP_MOD: /* modulo */
4219     v = nvalue (car (SCHEME_V->args));
4220    
4221     if (ivalue (cadr (SCHEME_V->args)) != 0)
4222     v = num_mod (v, nvalue (cadr (SCHEME_V->args)));
4223     else
4224     Error_0 ("modulo: division by zero");
4225    
4226     s_return (mk_number (SCHEME_A_ v));
4227    
4228     case OP_CAR: /* car */
4229     s_return (caar (SCHEME_V->args));
4230    
4231     case OP_CDR: /* cdr */
4232     s_return (cdar (SCHEME_V->args));
4233    
4234     case OP_CONS: /* cons */
4235     set_cdr (SCHEME_V->args, cadr (SCHEME_V->args));
4236     s_return (SCHEME_V->args);
4237    
4238     case OP_SETCAR: /* set-car! */
4239     if (!is_immutable (car (SCHEME_V->args)))
4240     {
4241     set_car (car (SCHEME_V->args), cadr (SCHEME_V->args));
4242     s_return (car (SCHEME_V->args));
4243     }
4244     else
4245     Error_0 ("set-car!: unable to alter immutable pair");
4246    
4247     case OP_SETCDR: /* set-cdr! */
4248     if (!is_immutable (car (SCHEME_V->args)))
4249     {
4250     set_cdr (car (SCHEME_V->args), cadr (SCHEME_V->args));
4251     s_return (car (SCHEME_V->args));
4252     }
4253     else
4254     Error_0 ("set-cdr!: unable to alter immutable pair");
4255    
4256     case OP_CHAR2INT: /* char->integer */
4257 root 1.2 s_return (mk_integer (SCHEME_A_ ivalue (car (SCHEME_V->args))));
4258 root 1.1
4259     case OP_INT2CHAR: /* integer->char */
4260 root 1.2 s_return (mk_character (SCHEME_A_ ivalue (car (SCHEME_V->args))));
4261 root 1.1
4262     case OP_CHARUPCASE:
4263     {
4264 root 1.2 unsigned char c = ivalue (car (SCHEME_V->args));
4265 root 1.1 c = toupper (c);
4266 root 1.2 s_return (mk_character (SCHEME_A_ c));
4267 root 1.1 }
4268    
4269     case OP_CHARDNCASE:
4270     {
4271 root 1.2 unsigned char c = ivalue (car (SCHEME_V->args));
4272 root 1.1 c = tolower (c);
4273 root 1.2 s_return (mk_character (SCHEME_A_ c));
4274 root 1.1 }
4275    
4276     case OP_STR2SYM: /* string->symbol */
4277     s_return (mk_symbol (SCHEME_A_ strvalue (car (SCHEME_V->args))));
4278    
4279     case OP_STR2ATOM: /* string->atom */
4280     {
4281     char *s = strvalue (car (SCHEME_V->args));
4282     long pf = 0;
4283    
4284     if (cdr (SCHEME_V->args) != NIL)
4285     {
4286     /* we know cadr(SCHEME_V->args) is a natural number */
4287     /* see if it is 2, 8, 10, or 16, or error */
4288     pf = ivalue_unchecked (cadr (SCHEME_V->args));
4289    
4290     if (pf == 16 || pf == 10 || pf == 8 || pf == 2)
4291     {
4292     /* base is OK */
4293     }
4294     else
4295 root 1.2 pf = -1;
4296 root 1.1 }
4297    
4298     if (pf < 0)
4299 root 1.2 Error_1 ("string->atom: bad base:", cadr (SCHEME_V->args));
4300 root 1.1 else if (*s == '#') /* no use of base! */
4301 root 1.2 s_return (mk_sharp_const (SCHEME_A_ s + 1));
4302 root 1.1 else
4303     {
4304     if (pf == 0 || pf == 10)
4305 root 1.2 s_return (mk_atom (SCHEME_A_ s));
4306 root 1.1 else
4307     {
4308     char *ep;
4309     long iv = strtol (s, &ep, (int) pf);
4310    
4311     if (*ep == 0)
4312 root 1.2 s_return (mk_integer (SCHEME_A_ iv));
4313 root 1.1 else
4314 root 1.2 s_return (S_F);
4315 root 1.1 }
4316     }
4317     }
4318    
4319     case OP_SYM2STR: /* symbol->string */
4320     x = mk_string (SCHEME_A_ symname (car (SCHEME_V->args)));
4321     setimmutable (x);
4322     s_return (x);
4323    
4324     case OP_ATOM2STR: /* atom->string */
4325     {
4326     long pf = 0;
4327    
4328     x = car (SCHEME_V->args);
4329    
4330     if (cdr (SCHEME_V->args) != NIL)
4331     {
4332     /* we know cadr(SCHEME_V->args) is a natural number */
4333     /* see if it is 2, 8, 10, or 16, or error */
4334     pf = ivalue_unchecked (cadr (SCHEME_V->args));
4335    
4336     if (is_number (x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2))
4337     {
4338     /* base is OK */
4339     }
4340     else
4341 root 1.2 pf = -1;
4342 root 1.1 }
4343    
4344     if (pf < 0)
4345 root 1.2 Error_1 ("atom->string: bad base:", cadr (SCHEME_V->args));
4346 root 1.1 else if (is_number (x) || is_character (x) || is_string (x) || is_symbol (x))
4347     {
4348     char *p;
4349     int len;
4350    
4351 root 1.2 atom2str (SCHEME_A_ x, pf, &p, &len);
4352 root 1.1 s_return (mk_counted_string (SCHEME_A_ p, len));
4353     }
4354     else
4355 root 1.2 Error_1 ("atom->string: not an atom:", x);
4356 root 1.1 }
4357    
4358     case OP_MKSTRING: /* make-string */
4359     {
4360     int fill = ' ';
4361     int len;
4362    
4363     len = ivalue (car (SCHEME_V->args));
4364    
4365     if (cdr (SCHEME_V->args) != NIL)
4366 root 1.2 fill = charvalue (cadr (SCHEME_V->args));
4367 root 1.1
4368     s_return (mk_empty_string (SCHEME_A_ len, (char) fill));
4369     }
4370    
4371     case OP_STRLEN: /* string-length */
4372     s_return (mk_integer (SCHEME_A_ strlength (car (SCHEME_V->args))));
4373    
4374     case OP_STRREF: /* string-ref */
4375     {
4376     char *str;
4377     int index;
4378    
4379     str = strvalue (car (SCHEME_V->args));
4380    
4381     index = ivalue (cadr (SCHEME_V->args));
4382    
4383     if (index >= strlength (car (SCHEME_V->args)))
4384 root 1.2 Error_1 ("string-ref: out of bounds:", cadr (SCHEME_V->args));
4385 root 1.1
4386     s_return (mk_character (SCHEME_A_ ((unsigned char *) str)[index]));
4387     }
4388    
4389     case OP_STRSET: /* string-set! */
4390     {
4391     char *str;
4392     int index;
4393     int c;
4394    
4395     if (is_immutable (car (SCHEME_V->args)))
4396 root 1.2 Error_1 ("string-set!: unable to alter immutable string:", car (SCHEME_V->args));
4397 root 1.1
4398     str = strvalue (car (SCHEME_V->args));
4399    
4400     index = ivalue (cadr (SCHEME_V->args));
4401    
4402     if (index >= strlength (car (SCHEME_V->args)))
4403 root 1.2 Error_1 ("string-set!: out of bounds:", cadr (SCHEME_V->args));
4404 root 1.1
4405     c = charvalue (caddr (SCHEME_V->args));
4406    
4407     str[index] = (char) c;
4408     s_return (car (SCHEME_V->args));
4409     }
4410    
4411     case OP_STRAPPEND: /* string-append */
4412     {
4413     /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4414     int len = 0;
4415     pointer newstr;
4416     char *pos;
4417    
4418     /* compute needed length for new string */
4419     for (x = SCHEME_V->args; x != NIL; x = cdr (x))
4420 root 1.2 len += strlength (car (x));
4421 root 1.1
4422     newstr = mk_empty_string (SCHEME_A_ len, ' ');
4423    
4424     /* store the contents of the argument strings into the new string */
4425     for (pos = strvalue (newstr), x = SCHEME_V->args; x != NIL; pos += strlength (car (x)), x = cdr (x))
4426 root 1.2 memcpy (pos, strvalue (car (x)), strlength (car (x)));
4427 root 1.1
4428     s_return (newstr);
4429     }
4430    
4431     case OP_SUBSTR: /* substring */
4432     {
4433     char *str;
4434     int index0;
4435     int index1;
4436     int len;
4437    
4438     str = strvalue (car (SCHEME_V->args));
4439    
4440     index0 = ivalue (cadr (SCHEME_V->args));
4441    
4442     if (index0 > strlength (car (SCHEME_V->args)))
4443 root 1.2 Error_1 ("substring: start out of bounds:", cadr (SCHEME_V->args));
4444 root 1.1
4445     if (cddr (SCHEME_V->args) != NIL)
4446     {
4447     index1 = ivalue (caddr (SCHEME_V->args));
4448    
4449     if (index1 > strlength (car (SCHEME_V->args)) || index1 < index0)
4450 root 1.2 Error_1 ("substring: end out of bounds:", caddr (SCHEME_V->args));
4451 root 1.1 }
4452     else
4453 root 1.2 index1 = strlength (car (SCHEME_V->args));
4454 root 1.1
4455     len = index1 - index0;
4456     x = mk_empty_string (SCHEME_A_ len, ' ');
4457     memcpy (strvalue (x), str + index0, len);
4458     strvalue (x)[len] = 0;
4459    
4460     s_return (x);
4461     }
4462    
4463     case OP_VECTOR: /* vector */
4464     {
4465     int i;
4466     pointer vec;
4467     int len = list_length (SCHEME_A_ SCHEME_V->args);
4468    
4469     if (len < 0)
4470 root 1.2 Error_1 ("vector: not a proper list:", SCHEME_V->args);
4471 root 1.1
4472     vec = mk_vector (SCHEME_A_ len);
4473    
4474     #if USE_ERROR_CHECKING
4475     if (SCHEME_V->no_memory)
4476     s_return (S_SINK);
4477     #endif
4478    
4479     for (x = SCHEME_V->args, i = 0; is_pair (x); x = cdr (x), i++)
4480     set_vector_elem (vec, i, car (x));
4481    
4482     s_return (vec);
4483     }
4484    
4485     case OP_MKVECTOR: /* make-vector */
4486     {
4487     pointer fill = NIL;
4488     int len;
4489     pointer vec;
4490    
4491     len = ivalue (car (SCHEME_V->args));
4492    
4493     if (cdr (SCHEME_V->args) != NIL)
4494     fill = cadr (SCHEME_V->args);
4495    
4496     vec = mk_vector (SCHEME_A_ len);
4497    
4498     #if USE_ERROR_CHECKING
4499     if (SCHEME_V->no_memory)
4500     s_return (S_SINK);
4501     #endif
4502    
4503     if (fill != NIL)
4504     fill_vector (vec, fill);
4505    
4506     s_return (vec);
4507     }
4508    
4509     case OP_VECLEN: /* vector-length */
4510 root 1.3 s_return (mk_integer (SCHEME_A_ vector_length (car (SCHEME_V->args))));
4511 root 1.1
4512     case OP_VECREF: /* vector-ref */
4513     {
4514     int index;
4515    
4516     index = ivalue (cadr (SCHEME_V->args));
4517    
4518 root 1.3 if (index >= vector_length (car (SCHEME_V->args)) && USE_ERROR_CHECKING)
4519 root 1.2 Error_1 ("vector-ref: out of bounds:", cadr (SCHEME_V->args));
4520 root 1.1
4521     s_return (vector_elem (car (SCHEME_V->args), index));
4522     }
4523    
4524     case OP_VECSET: /* vector-set! */
4525     {
4526     int index;
4527    
4528     if (is_immutable (car (SCHEME_V->args)))
4529 root 1.2 Error_1 ("vector-set!: unable to alter immutable vector:", car (SCHEME_V->args));
4530 root 1.1
4531     index = ivalue (cadr (SCHEME_V->args));
4532    
4533 root 1.3 if (index >= vector_length (car (SCHEME_V->args)) && USE_ERROR_CHECKING)
4534 root 1.2 Error_1 ("vector-set!: out of bounds:", cadr (SCHEME_V->args));
4535 root 1.1
4536     set_vector_elem (car (SCHEME_V->args), index, caddr (SCHEME_V->args));
4537     s_return (car (SCHEME_V->args));
4538     }
4539     }
4540    
4541     return S_T;
4542     }
4543    
4544     INTERFACE int
4545     is_list (SCHEME_P_ pointer a)
4546     {
4547     return list_length (SCHEME_A_ a) >= 0;
4548     }
4549    
4550     /* Result is:
4551     proper list: length
4552     circular list: -1
4553     not even a pair: -2
4554     dotted list: -2 minus length before dot
4555     */
4556     INTERFACE int
4557     list_length (SCHEME_P_ pointer a)
4558     {
4559     int i = 0;
4560     pointer slow, fast;
4561    
4562     slow = fast = a;
4563    
4564     while (1)
4565     {
4566     if (fast == NIL)
4567     return i;
4568    
4569     if (!is_pair (fast))
4570     return -2 - i;
4571    
4572     fast = cdr (fast);
4573     ++i;
4574    
4575     if (fast == NIL)
4576     return i;
4577    
4578     if (!is_pair (fast))
4579     return -2 - i;
4580    
4581     ++i;
4582     fast = cdr (fast);
4583    
4584     /* Safe because we would have already returned if `fast'
4585     encountered a non-pair. */
4586     slow = cdr (slow);
4587    
4588     if (fast == slow)
4589     {
4590     /* the fast pointer has looped back around and caught up
4591     with the slow pointer, hence the structure is circular,
4592     not of finite length, and therefore not a list */
4593     return -1;
4594     }
4595     }
4596     }
4597    
4598     static pointer
4599     opexe_3 (SCHEME_P_ enum scheme_opcodes op)
4600     {
4601     pointer x;
4602     num v;
4603     int (*comp_func) (num, num);
4604    
4605     switch (op)
4606     {
4607     case OP_NOT: /* not */
4608     s_retbool (is_false (car (SCHEME_V->args)));
4609    
4610     case OP_BOOLP: /* boolean? */
4611     s_retbool (car (SCHEME_V->args) == S_F || car (SCHEME_V->args) == S_T);
4612    
4613     case OP_EOFOBJP: /* boolean? */
4614     s_retbool (car (SCHEME_V->args) == S_EOF);
4615    
4616     case OP_NULLP: /* null? */
4617     s_retbool (car (SCHEME_V->args) == NIL);
4618    
4619     case OP_NUMEQ: /* = */
4620     case OP_LESS: /* < */
4621     case OP_GRE: /* > */
4622     case OP_LEQ: /* <= */
4623     case OP_GEQ: /* >= */
4624     switch (op)
4625     {
4626     case OP_NUMEQ:
4627     comp_func = num_eq;
4628     break;
4629    
4630     case OP_LESS:
4631     comp_func = num_lt;
4632     break;
4633    
4634     case OP_GRE:
4635     comp_func = num_gt;
4636     break;
4637    
4638     case OP_LEQ:
4639     comp_func = num_le;
4640     break;
4641    
4642     case OP_GEQ:
4643     comp_func = num_ge;
4644     break;
4645     }
4646    
4647     x = SCHEME_V->args;
4648     v = nvalue (car (x));
4649     x = cdr (x);
4650    
4651     for (; x != NIL; x = cdr (x))
4652     {
4653     if (!comp_func (v, nvalue (car (x))))
4654 root 1.2 s_retbool (0);
4655 root 1.1
4656     v = nvalue (car (x));
4657     }
4658    
4659     s_retbool (1);
4660    
4661     case OP_SYMBOLP: /* symbol? */
4662     s_retbool (is_symbol (car (SCHEME_V->args)));
4663    
4664     case OP_NUMBERP: /* number? */
4665     s_retbool (is_number (car (SCHEME_V->args)));
4666    
4667     case OP_STRINGP: /* string? */
4668     s_retbool (is_string (car (SCHEME_V->args)));
4669    
4670     case OP_INTEGERP: /* integer? */
4671     s_retbool (is_integer (car (SCHEME_V->args)));
4672    
4673     case OP_REALP: /* real? */
4674     s_retbool (is_number (car (SCHEME_V->args))); /* All numbers are real */
4675    
4676     case OP_CHARP: /* char? */
4677     s_retbool (is_character (car (SCHEME_V->args)));
4678     #if USE_CHAR_CLASSIFIERS
4679    
4680     case OP_CHARAP: /* char-alphabetic? */
4681     s_retbool (Cisalpha (ivalue (car (SCHEME_V->args))));
4682    
4683     case OP_CHARNP: /* char-numeric? */
4684     s_retbool (Cisdigit (ivalue (car (SCHEME_V->args))));
4685    
4686     case OP_CHARWP: /* char-whitespace? */
4687     s_retbool (Cisspace (ivalue (car (SCHEME_V->args))));
4688    
4689     case OP_CHARUP: /* char-upper-case? */
4690     s_retbool (Cisupper (ivalue (car (SCHEME_V->args))));
4691    
4692     case OP_CHARLP: /* char-lower-case? */
4693     s_retbool (Cislower (ivalue (car (SCHEME_V->args))));
4694     #endif
4695     #if USE_PORTS
4696    
4697     case OP_PORTP: /* port? */
4698     s_retbool (is_port (car (SCHEME_V->args)));
4699    
4700     case OP_INPORTP: /* input-port? */
4701     s_retbool (is_inport (car (SCHEME_V->args)));
4702    
4703     case OP_OUTPORTP: /* output-port? */
4704     s_retbool (is_outport (car (SCHEME_V->args)));
4705     #endif
4706    
4707     case OP_PROCP: /* procedure? */
4708    
4709     /*--
4710     * continuation should be procedure by the example
4711     * (call-with-current-continuation procedure?) ==> #t
4712     * in R^3 report sec. 6.9
4713     */
4714     s_retbool (is_proc (car (SCHEME_V->args)) || is_closure (car (SCHEME_V->args))
4715     || is_continuation (car (SCHEME_V->args)) || is_foreign (car (SCHEME_V->args)));
4716    
4717     case OP_PAIRP: /* pair? */
4718     s_retbool (is_pair (car (SCHEME_V->args)));
4719    
4720     case OP_LISTP: /* list? */
4721     s_retbool (list_length (SCHEME_A_ car (SCHEME_V->args)) >= 0);
4722    
4723     case OP_ENVP: /* environment? */
4724     s_retbool (is_environment (car (SCHEME_V->args)));
4725    
4726     case OP_VECTORP: /* vector? */
4727     s_retbool (is_vector (car (SCHEME_V->args)));
4728    
4729     case OP_EQ: /* eq? */
4730     s_retbool (car (SCHEME_V->args) == cadr (SCHEME_V->args));
4731    
4732     case OP_EQV: /* eqv? */
4733     s_retbool (eqv (car (SCHEME_V->args), cadr (SCHEME_V->args)));
4734     }
4735    
4736     return S_T;
4737     }
4738    
4739     static pointer
4740     opexe_4 (SCHEME_P_ enum scheme_opcodes op)
4741     {
4742     pointer x, y;
4743    
4744     switch (op)
4745     {
4746     case OP_FORCE: /* force */
4747     SCHEME_V->code = car (SCHEME_V->args);
4748    
4749     if (is_promise (SCHEME_V->code))
4750     {
4751     /* Should change type to closure here */
4752     s_save (SCHEME_A_ OP_SAVE_FORCED, NIL, SCHEME_V->code);
4753     SCHEME_V->args = NIL;
4754     s_goto (OP_APPLY);
4755     }
4756     else
4757 root 1.2 s_return (SCHEME_V->code);
4758 root 1.1
4759     case OP_SAVE_FORCED: /* Save forced value replacing promise */
4760     memcpy (SCHEME_V->code, SCHEME_V->value, sizeof (struct cell));
4761     s_return (SCHEME_V->value);
4762    
4763     #if USE_PORTS
4764    
4765     case OP_WRITE: /* write */
4766     case OP_DISPLAY: /* display */
4767     case OP_WRITE_CHAR: /* write-char */
4768     if (is_pair (cdr (SCHEME_V->args)))
4769     {
4770     if (cadr (SCHEME_V->args) != SCHEME_V->outport)
4771     {
4772     x = cons (SCHEME_V->outport, NIL);
4773     s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4774     SCHEME_V->outport = cadr (SCHEME_V->args);
4775     }
4776     }
4777    
4778     SCHEME_V->args = car (SCHEME_V->args);
4779    
4780     if (op == OP_WRITE)
4781     SCHEME_V->print_flag = 1;
4782     else
4783     SCHEME_V->print_flag = 0;
4784    
4785     s_goto (OP_P0LIST);
4786    
4787     case OP_NEWLINE: /* newline */
4788     if (is_pair (SCHEME_V->args))
4789     {
4790     if (car (SCHEME_V->args) != SCHEME_V->outport)
4791     {
4792     x = cons (SCHEME_V->outport, NIL);
4793     s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4794     SCHEME_V->outport = car (SCHEME_V->args);
4795     }
4796     }
4797    
4798     putstr (SCHEME_A_ "\n");
4799     s_return (S_T);
4800     #endif
4801    
4802     case OP_ERR0: /* error */
4803     SCHEME_V->retcode = -1;
4804    
4805     if (!is_string (car (SCHEME_V->args)))
4806     {
4807     SCHEME_V->args = cons (mk_string (SCHEME_A_ " -- "), SCHEME_V->args);
4808     setimmutable (car (SCHEME_V->args));
4809     }
4810    
4811     putstr (SCHEME_A_ "Error: ");
4812     putstr (SCHEME_A_ strvalue (car (SCHEME_V->args)));
4813     SCHEME_V->args = cdr (SCHEME_V->args);
4814     s_goto (OP_ERR1);
4815    
4816     case OP_ERR1: /* error */
4817     putstr (SCHEME_A_ " ");
4818    
4819     if (SCHEME_V->args != NIL)
4820     {
4821     s_save (SCHEME_A_ OP_ERR1, cdr (SCHEME_V->args), NIL);
4822     SCHEME_V->args = car (SCHEME_V->args);
4823     SCHEME_V->print_flag = 1;
4824     s_goto (OP_P0LIST);
4825     }
4826     else
4827     {
4828     putstr (SCHEME_A_ "\n");
4829    
4830     if (SCHEME_V->interactive_repl)
4831 root 1.2 s_goto (OP_T0LVL);
4832 root 1.1 else
4833 root 1.2 return NIL;
4834 root 1.1 }
4835    
4836     case OP_REVERSE: /* reverse */
4837     s_return (reverse (SCHEME_A_ car (SCHEME_V->args)));
4838    
4839     case OP_LIST_STAR: /* list* */
4840     s_return (list_star (SCHEME_A_ SCHEME_V->args));
4841    
4842     case OP_APPEND: /* append */
4843     x = NIL;
4844     y = SCHEME_V->args;
4845    
4846     if (y == x)
4847     s_return (x);
4848    
4849     /* cdr() in the while condition is not a typo. If car() */
4850     /* is used (append '() 'a) will return the wrong result. */
4851     while (cdr (y) != NIL)
4852     {
4853     x = revappend (SCHEME_A_ x, car (y));
4854     y = cdr (y);
4855    
4856     if (x == S_F)
4857     Error_0 ("non-list argument to append");
4858     }
4859    
4860     s_return (reverse_in_place (SCHEME_A_ car (y), x));
4861    
4862     #if USE_PLIST
4863    
4864     case OP_PUT: /* put */
4865     if (!hasprop (car (SCHEME_V->args)) || !hasprop (cadr (SCHEME_V->args)))
4866 root 1.2 Error_0 ("illegal use of put");
4867 root 1.1
4868     for (x = symprop (car (SCHEME_V->args)), y = cadr (SCHEME_V->args); x != NIL; x = cdr (x))
4869     {
4870     if (caar (x) == y)
4871 root 1.2 break;
4872 root 1.1 }
4873    
4874     if (x != NIL)
4875     cdar (x) = caddr (SCHEME_V->args);
4876     else
4877     symprop (car (SCHEME_V->args)) = cons (cons (y, caddr (SCHEME_V->args)), symprop (car (SCHEME_V->args)));
4878    
4879     s_return (S_T);
4880    
4881     case OP_GET: /* get */
4882     if (!hasprop (car (SCHEME_V->args)) || !hasprop (cadr (SCHEME_V->args)))
4883     Error_0 ("illegal use of get");
4884    
4885     for (x = symprop (car (SCHEME_V->args)), y = cadr (SCHEME_V->args); x != NIL; x = cdr (x))
4886     if (caar (x) == y)
4887     break;
4888    
4889     if (x != NIL)
4890     s_return (cdar (x));
4891     else
4892     s_return (NIL);
4893    
4894     #endif /* USE_PLIST */
4895    
4896     case OP_QUIT: /* quit */
4897     if (is_pair (SCHEME_V->args))
4898     SCHEME_V->retcode = ivalue (car (SCHEME_V->args));
4899    
4900     return NIL;
4901    
4902     case OP_GC: /* gc */
4903     gc (SCHEME_A_ NIL, NIL);
4904     s_return (S_T);
4905    
4906     case OP_GCVERB: /* gc-verbose */
4907     {
4908     int was = SCHEME_V->gc_verbose;
4909    
4910     SCHEME_V->gc_verbose = (car (SCHEME_V->args) != S_F);
4911     s_retbool (was);
4912     }
4913    
4914     case OP_NEWSEGMENT: /* new-segment */
4915     if (!is_pair (SCHEME_V->args) || !is_number (car (SCHEME_V->args)))
4916     Error_0 ("new-segment: argument must be a number");
4917    
4918     alloc_cellseg (SCHEME_A_ (int)ivalue (car (SCHEME_V->args)));
4919    
4920     s_return (S_T);
4921    
4922     case OP_OBLIST: /* oblist */
4923     s_return (oblist_all_symbols (SCHEME_A));
4924    
4925     #if USE_PORTS
4926    
4927     case OP_CURR_INPORT: /* current-input-port */
4928     s_return (SCHEME_V->inport);
4929    
4930     case OP_CURR_OUTPORT: /* current-output-port */
4931     s_return (SCHEME_V->outport);
4932    
4933     case OP_OPEN_INFILE: /* open-input-file */
4934     case OP_OPEN_OUTFILE: /* open-output-file */
4935     case OP_OPEN_INOUTFILE: /* open-input-output-file */
4936     {
4937     int prop = 0;
4938     pointer p;
4939    
4940     switch (op)
4941     {
4942     case OP_OPEN_INFILE:
4943     prop = port_input;
4944     break;
4945    
4946     case OP_OPEN_OUTFILE:
4947     prop = port_output;
4948     break;
4949    
4950     case OP_OPEN_INOUTFILE:
4951     prop = port_input | port_output;
4952     break;
4953     }
4954    
4955     p = port_from_filename (SCHEME_A_ strvalue (car (SCHEME_V->args)), prop);
4956    
4957     if (p == NIL)
4958 root 1.2 s_return (S_F);
4959 root 1.1
4960     s_return (p);
4961     }
4962    
4963     # if USE_STRING_PORTS
4964    
4965     case OP_OPEN_INSTRING: /* open-input-string */
4966     case OP_OPEN_INOUTSTRING: /* open-input-output-string */
4967     {
4968     int prop = 0;
4969     pointer p;
4970    
4971     switch (op)
4972     {
4973     case OP_OPEN_INSTRING:
4974     prop = port_input;
4975     break;
4976    
4977     case OP_OPEN_INOUTSTRING:
4978     prop = port_input | port_output;
4979     break;
4980     }
4981    
4982     p = port_from_string (SCHEME_A_ strvalue (car (SCHEME_V->args)),
4983     strvalue (car (SCHEME_V->args)) + strlength (car (SCHEME_V->args)), prop);
4984    
4985     if (p == NIL)
4986 root 1.2 s_return (S_F);
4987 root 1.1
4988     s_return (p);
4989     }
4990    
4991     case OP_OPEN_OUTSTRING: /* open-output-string */
4992     {
4993     pointer p;
4994    
4995     if (car (SCHEME_V->args) == NIL)
4996     {
4997     p = port_from_scratch (SCHEME_A);
4998    
4999     if (p == NIL)
5000 root 1.2 s_return (S_F);
5001 root 1.1 }
5002     else
5003     {
5004     p = port_from_string (SCHEME_A_ strvalue (car (SCHEME_V->args)),
5005     strvalue (car (SCHEME_V->args)) + strlength (car (SCHEME_V->args)), port_output);
5006    
5007     if (p == NIL)
5008 root 1.2 s_return (S_F);
5009 root 1.1 }
5010    
5011     s_return (p);
5012     }
5013    
5014     case OP_GET_OUTSTRING: /* get-output-string */
5015     {
5016     port *p;
5017    
5018     if ((p = car (SCHEME_V->args)->object.port)->kind & port_string)
5019     {
5020     off_t size;
5021     char *str;
5022    
5023     size = p->rep.string.curr - p->rep.string.start + 1;
5024     str = malloc (size);
5025    
5026     if (str != NULL)
5027     {
5028     pointer s;
5029    
5030     memcpy (str, p->rep.string.start, size - 1);
5031     str[size - 1] = '\0';
5032     s = mk_string (SCHEME_A_ str);
5033     free (str);
5034     s_return (s);
5035     }
5036     }
5037    
5038     s_return (S_F);
5039     }
5040    
5041     # endif
5042    
5043     case OP_CLOSE_INPORT: /* close-input-port */
5044     port_close (SCHEME_A_ car (SCHEME_V->args), port_input);
5045     s_return (S_T);
5046    
5047     case OP_CLOSE_OUTPORT: /* close-output-port */
5048     port_close (SCHEME_A_ car (SCHEME_V->args), port_output);
5049     s_return (S_T);
5050     #endif
5051    
5052     case OP_INT_ENV: /* interaction-environment */
5053     s_return (SCHEME_V->global_env);
5054    
5055     case OP_CURR_ENV: /* current-environment */
5056     s_return (SCHEME_V->envir);
5057    
5058     }
5059    
5060     return S_T;
5061     }
5062    
5063     static pointer
5064     opexe_5 (SCHEME_P_ enum scheme_opcodes op)
5065     {
5066     pointer x;
5067    
5068     if (SCHEME_V->nesting != 0)
5069     {
5070     int n = SCHEME_V->nesting;
5071    
5072     SCHEME_V->nesting = 0;
5073     SCHEME_V->retcode = -1;
5074     Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
5075     }
5076    
5077     switch (op)
5078     {
5079     /* ========== reading part ========== */
5080     #if USE_PORTS
5081     case OP_READ:
5082     if (!is_pair (SCHEME_V->args))
5083 root 1.2 s_goto (OP_READ_INTERNAL);
5084 root 1.1
5085     if (!is_inport (car (SCHEME_V->args)))
5086 root 1.2 Error_1 ("read: not an input port:", car (SCHEME_V->args));
5087 root 1.1
5088     if (car (SCHEME_V->args) == SCHEME_V->inport)
5089 root 1.2 s_goto (OP_READ_INTERNAL);
5090 root 1.1
5091     x = SCHEME_V->inport;
5092     SCHEME_V->inport = car (SCHEME_V->args);
5093     x = cons (x, NIL);
5094     s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
5095     s_goto (OP_READ_INTERNAL);
5096    
5097     case OP_READ_CHAR: /* read-char */
5098     case OP_PEEK_CHAR: /* peek-char */
5099     {
5100     int c;
5101    
5102     if (is_pair (SCHEME_V->args))
5103     {
5104     if (car (SCHEME_V->args) != SCHEME_V->inport)
5105     {
5106     x = SCHEME_V->inport;
5107     x = cons (x, NIL);
5108     s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
5109     SCHEME_V->inport = car (SCHEME_V->args);
5110     }
5111     }
5112    
5113     c = inchar (SCHEME_A);
5114    
5115     if (c == EOF)
5116     s_return (S_EOF);
5117    
5118     if (SCHEME_V->op == OP_PEEK_CHAR)
5119     backchar (SCHEME_A_ c);
5120    
5121     s_return (mk_character (SCHEME_A_ c));
5122     }
5123    
5124     case OP_CHAR_READY: /* char-ready? */
5125     {
5126     pointer p = SCHEME_V->inport;
5127     int res;
5128    
5129     if (is_pair (SCHEME_V->args))
5130 root 1.2 p = car (SCHEME_V->args);
5131 root 1.1
5132     res = p->object.port->kind & port_string;
5133    
5134     s_retbool (res);
5135     }
5136    
5137     case OP_SET_INPORT: /* set-input-port */
5138     SCHEME_V->inport = car (SCHEME_V->args);
5139     s_return (SCHEME_V->value);
5140    
5141     case OP_SET_OUTPORT: /* set-output-port */
5142     SCHEME_V->outport = car (SCHEME_V->args);
5143     s_return (SCHEME_V->value);
5144     #endif
5145    
5146     case OP_RDSEXPR:
5147     switch (SCHEME_V->tok)
5148     {
5149     case TOK_EOF:
5150     s_return (S_EOF);
5151     /* NOTREACHED */
5152    
5153     case TOK_VEC:
5154     s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
5155 root 1.2 /* fall through */
5156 root 1.1
5157     case TOK_LPAREN:
5158     SCHEME_V->tok = token (SCHEME_A);
5159    
5160     if (SCHEME_V->tok == TOK_RPAREN)
5161     s_return (NIL);
5162     else if (SCHEME_V->tok == TOK_DOT)
5163     Error_0 ("syntax error: illegal dot expression");
5164     else
5165     {
5166     SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
5167     s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
5168     s_goto (OP_RDSEXPR);
5169     }
5170    
5171     case TOK_QUOTE:
5172     s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
5173     SCHEME_V->tok = token (SCHEME_A);
5174     s_goto (OP_RDSEXPR);
5175    
5176     case TOK_BQUOTE:
5177     SCHEME_V->tok = token (SCHEME_A);
5178    
5179     if (SCHEME_V->tok == TOK_VEC)
5180     {
5181     s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
5182     SCHEME_V->tok = TOK_LPAREN;
5183     s_goto (OP_RDSEXPR);
5184     }
5185     else
5186 root 1.2 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
5187 root 1.1
5188     s_goto (OP_RDSEXPR);
5189    
5190     case TOK_COMMA:
5191     s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
5192     SCHEME_V->tok = token (SCHEME_A);
5193     s_goto (OP_RDSEXPR);
5194    
5195     case TOK_ATMARK:
5196     s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
5197     SCHEME_V->tok = token (SCHEME_A);
5198     s_goto (OP_RDSEXPR);
5199    
5200     case TOK_ATOM:
5201     s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS)));
5202    
5203     case TOK_DQUOTE:
5204     x = readstrexp (SCHEME_A);
5205    
5206     if (x == S_F)
5207     Error_0 ("Error reading string");
5208    
5209     setimmutable (x);
5210     s_return (x);
5211    
5212     case TOK_SHARP:
5213     {
5214     pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
5215    
5216     if (f == NIL)
5217     Error_0 ("undefined sharp expression");
5218     else
5219     {
5220     SCHEME_V->code = cons (slot_value_in_env (f), NIL);
5221     s_goto (OP_EVAL);
5222     }
5223     }
5224    
5225     case TOK_SHARP_CONST:
5226     if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS))) == NIL)
5227     Error_0 ("undefined sharp expression");
5228     else
5229     s_return (x);
5230    
5231     default:
5232     Error_0 ("syntax error: illegal token");
5233     }
5234    
5235     break;
5236    
5237     case OP_RDLIST:
5238 root 1.2 SCHEME_V->args = cons (SCHEME_V->value, SCHEME_V->args);
5239     SCHEME_V->tok = token (SCHEME_A);
5240 root 1.1
5241 root 1.2 switch (SCHEME_V->tok)
5242     {
5243     case TOK_EOF:
5244     s_return (S_EOF);
5245 root 1.1
5246 root 1.2 case TOK_RPAREN:
5247     {
5248     int c = inchar (SCHEME_A);
5249 root 1.1
5250 root 1.2 if (c != '\n')
5251     backchar (SCHEME_A_ c);
5252 root 1.1 #if SHOW_ERROR_LINE
5253 root 1.2 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5254     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5255     #endif
5256 root 1.1
5257 root 1.2 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5258     s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5259     }
5260    
5261     case TOK_DOT:
5262 root 1.1 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5263     SCHEME_V->tok = token (SCHEME_A);
5264     s_goto (OP_RDSEXPR);
5265 root 1.2
5266     default:
5267     s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5268 root 1.1 s_goto (OP_RDSEXPR);
5269 root 1.2 }
5270 root 1.1
5271     case OP_RDDOT:
5272     if (token (SCHEME_A) != TOK_RPAREN)
5273     Error_0 ("syntax error: illegal dot expression");
5274 root 1.2
5275     SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5276     s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, SCHEME_V->args));
5277 root 1.1
5278     case OP_RDQUOTE:
5279     s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5280    
5281     case OP_RDQQUOTE:
5282     s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5283    
5284     case OP_RDQQUOTEVEC:
5285     s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5286     cons (mk_symbol (SCHEME_A_ "vector"),
5287     cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5288    
5289     case OP_RDUNQUOTE:
5290     s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5291    
5292     case OP_RDUQTSP:
5293     s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5294    
5295     case OP_RDVEC:
5296     /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5297     s_goto(OP_EVAL); Cannot be quoted */
5298     /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5299     s_return(x); Cannot be part of pairs */
5300     /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5301     SCHEME_V->args=SCHEME_V->value;
5302     s_goto(OP_APPLY); */
5303     SCHEME_V->args = SCHEME_V->value;
5304     s_goto (OP_VECTOR);
5305    
5306     /* ========== printing part ========== */
5307     case OP_P0LIST:
5308     if (is_vector (SCHEME_V->args))
5309     {
5310     putstr (SCHEME_A_ "#(");
5311     SCHEME_V->args = cons (SCHEME_V->args, mk_integer (SCHEME_A_ 0));
5312     s_goto (OP_PVECFROM);
5313     }
5314     else if (is_environment (SCHEME_V->args))
5315     {
5316     putstr (SCHEME_A_ "#<ENVIRONMENT>");
5317     s_return (S_T);
5318     }
5319     else if (!is_pair (SCHEME_V->args))
5320     {
5321     printatom (SCHEME_A_ SCHEME_V->args, SCHEME_V->print_flag);
5322     s_return (S_T);
5323     }
5324     else if (car (SCHEME_V->args) == SCHEME_V->QUOTE && ok_abbrev (cdr (SCHEME_V->args)))
5325     {
5326     putstr (SCHEME_A_ "'");
5327     SCHEME_V->args = cadr (SCHEME_V->args);
5328     s_goto (OP_P0LIST);
5329     }
5330     else if (car (SCHEME_V->args) == SCHEME_V->QQUOTE && ok_abbrev (cdr (SCHEME_V->args)))
5331     {
5332     putstr (SCHEME_A_ "`");
5333     SCHEME_V->args = cadr (SCHEME_V->args);
5334     s_goto (OP_P0LIST);
5335     }
5336     else if (car (SCHEME_V->args) == SCHEME_V->UNQUOTE && ok_abbrev (cdr (SCHEME_V->args)))
5337     {
5338     putstr (SCHEME_A_ ",");
5339     SCHEME_V->args = cadr (SCHEME_V->args);
5340     s_goto (OP_P0LIST);
5341     }
5342     else if (car (SCHEME_V->args) == SCHEME_V->UNQUOTESP && ok_abbrev (cdr (SCHEME_V->args)))
5343     {
5344     putstr (SCHEME_A_ ",@");
5345     SCHEME_V->args = cadr (SCHEME_V->args);
5346     s_goto (OP_P0LIST);
5347     }
5348     else
5349     {
5350     putstr (SCHEME_A_ "(");
5351     s_save (SCHEME_A_ OP_P1LIST, cdr (SCHEME_V->args), NIL);
5352     SCHEME_V->args = car (SCHEME_V->args);
5353     s_goto (OP_P0LIST);
5354     }
5355    
5356     case OP_P1LIST:
5357     if (is_pair (SCHEME_V->args))
5358     {
5359     s_save (SCHEME_A_ OP_P1LIST, cdr (SCHEME_V->args), NIL);
5360     putstr (SCHEME_A_ " ");
5361     SCHEME_V->args = car (SCHEME_V->args);
5362     s_goto (OP_P0LIST);
5363     }
5364     else if (is_vector (SCHEME_V->args))
5365     {
5366     s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5367     putstr (SCHEME_A_ " . ");
5368     s_goto (OP_P0LIST);
5369     }
5370     else
5371     {
5372     if (SCHEME_V->args != NIL)
5373     {
5374     putstr (SCHEME_A_ " . ");
5375     printatom (SCHEME_A_ SCHEME_V->args, SCHEME_V->print_flag);
5376     }
5377    
5378     putstr (SCHEME_A_ ")");
5379     s_return (S_T);
5380     }
5381    
5382     case OP_PVECFROM:
5383     {
5384     int i = ivalue_unchecked (cdr (SCHEME_V->args));
5385     pointer vec = car (SCHEME_V->args);
5386 root 1.3 int len = vector_length (vec);
5387 root 1.1
5388     if (i == len)
5389     {
5390     putstr (SCHEME_A_ ")");
5391     s_return (S_T);
5392     }
5393     else
5394     {
5395     pointer elem = vector_elem (vec, i);
5396    
5397     ivalue_unchecked (cdr (SCHEME_V->args)) = i + 1;
5398     s_save (SCHEME_A_ OP_PVECFROM, SCHEME_V->args, NIL);
5399     SCHEME_V->args = elem;
5400    
5401     if (i > 0)
5402     putstr (SCHEME_A_ " ");
5403    
5404     s_goto (OP_P0LIST);
5405     }
5406     }
5407     }
5408    
5409     return S_T;
5410     }
5411    
5412     static pointer
5413     opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5414     {
5415     pointer x, y;
5416    
5417     switch (op)
5418     {
5419     case OP_LIST_LENGTH: /* length *//* a.k */
5420     {
5421     long v = list_length (SCHEME_A_ car (SCHEME_V->args));
5422    
5423     if (v < 0)
5424     Error_1 ("length: not a list:", car (SCHEME_V->args));
5425    
5426     s_return (mk_integer (SCHEME_A_ v));
5427     }
5428    
5429     case OP_ASSQ: /* assq *//* a.k */
5430     x = car (SCHEME_V->args);
5431    
5432     for (y = cadr (SCHEME_V->args); is_pair (y); y = cdr (y))
5433     {
5434     if (!is_pair (car (y)))
5435     Error_0 ("unable to handle non pair element");
5436    
5437     if (x == caar (y))
5438     break;
5439     }
5440    
5441     if (is_pair (y))
5442     s_return (car (y));
5443     else
5444     s_return (S_F);
5445    
5446    
5447     case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5448     SCHEME_V->args = car (SCHEME_V->args);
5449    
5450     if (SCHEME_V->args == NIL)
5451     s_return (S_F);
5452     else if (is_closure (SCHEME_V->args))
5453     s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5454     else if (is_macro (SCHEME_V->args))
5455     s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5456     else
5457     s_return (S_F);
5458    
5459     case OP_CLOSUREP: /* closure? */
5460     /*
5461     * Note, macro object is also a closure.
5462     * Therefore, (closure? <#MACRO>) ==> #t
5463     */
5464     s_retbool (is_closure (car (SCHEME_V->args)));
5465    
5466     case OP_MACROP: /* macro? */
5467     s_retbool (is_macro (car (SCHEME_V->args)));
5468     }
5469    
5470     return S_T; /* NOTREACHED */
5471     }
5472    
5473     typedef pointer (*dispatch_func) (SCHEME_P_ enum scheme_opcodes);
5474    
5475     typedef int (*test_predicate) (pointer);
5476     static int
5477     is_any (pointer p)
5478     {
5479     return 1;
5480     }
5481    
5482     static int
5483     is_nonneg (pointer p)
5484     {
5485     return ivalue (p) >= 0 && is_integer (p);
5486     }
5487    
5488     /* Correspond carefully with following defines! */
5489     static struct
5490     {
5491     test_predicate fct;
5492     const char *kind;
5493     } tests[] =
5494     {
5495     { 0, 0}, /* unused */
5496     { is_any, 0},
5497     { is_string, "string" },
5498     { is_symbol, "symbol" },
5499     { is_port, "port" },
5500     { is_inport, "input port" },
5501     { is_outport, "output port" },
5502     { is_environment, "environment" },
5503     { is_pair, "pair" },
5504     { 0, "pair or '()" },
5505     { is_character, "character" },
5506     { is_vector, "vector" },
5507     { is_number, "number" },
5508     { is_integer, "integer" },
5509     { is_nonneg, "non-negative integer" }
5510     };
5511    
5512     #define TST_NONE 0
5513     #define TST_ANY "\001"
5514     #define TST_STRING "\002"
5515     #define TST_SYMBOL "\003"
5516     #define TST_PORT "\004"
5517     #define TST_INPORT "\005"
5518     #define TST_OUTPORT "\006"
5519     #define TST_ENVIRONMENT "\007"
5520     #define TST_PAIR "\010"
5521     #define TST_LIST "\011"
5522     #define TST_CHAR "\012"
5523     #define TST_VECTOR "\013"
5524     #define TST_NUMBER "\014"
5525     #define TST_INTEGER "\015"
5526     #define TST_NATURAL "\016"
5527    
5528     typedef struct
5529     {
5530     dispatch_func func;
5531     char *name;
5532     int min_arity;
5533     int max_arity;
5534     char *arg_tests_encoding;
5535     } op_code_info;
5536    
5537     #define INF_ARG 0xffff
5538    
5539     static op_code_info dispatch_table[] = {
5540     #define OP_DEF(A,B,C,D,E,OP) {A,B,C,D,E},
5541     #include "opdefines.h"
5542     {0}
5543     };
5544    
5545     static const char *
5546     procname (pointer x)
5547     {
5548     int n = procnum (x);
5549     const char *name = dispatch_table[n].name;
5550    
5551     if (name == 0)
5552 root 1.2 name = "ILLEGAL!";
5553 root 1.1
5554     return name;
5555     }
5556    
5557     /* kernel of this interpreter */
5558     static void
5559     Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5560     {
5561     SCHEME_V->op = op;
5562    
5563     for (;;)
5564     {
5565     op_code_info *pcd = dispatch_table + SCHEME_V->op;
5566    
5567 root 1.4 #if USE_ERROR_CHECKING
5568 root 1.2 if (pcd->name) /* if built-in function, check arguments */
5569 root 1.1 {
5570 root 1.4 int ok = 1;
5571 root 1.1 char msg[STRBUFFSIZE];
5572     int n = list_length (SCHEME_A_ SCHEME_V->args);
5573    
5574     /* Check number of arguments */
5575     if (n < pcd->min_arity)
5576     {
5577     ok = 0;
5578     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5579     pcd->name, pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5580     }
5581    
5582     if (ok && n > pcd->max_arity)
5583     {
5584     ok = 0;
5585     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5586     pcd->name, pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5587     }
5588    
5589     if (ok)
5590     {
5591 root 1.4 if (pcd->arg_tests_encoding)
5592 root 1.1 {
5593     int i = 0;
5594     int j;
5595     const char *t = pcd->arg_tests_encoding;
5596     pointer arglist = SCHEME_V->args;
5597    
5598     do
5599     {
5600     pointer arg = car (arglist);
5601    
5602     j = (int) t[0];
5603    
5604     if (j == TST_LIST[0])
5605     {
5606     if (arg != NIL && !is_pair (arg))
5607     break;
5608     }
5609     else
5610     {
5611     if (!tests[j].fct (arg))
5612     break;
5613     }
5614    
5615     if (t[1] != 0) /* last test is replicated as necessary */
5616 root 1.2 t++;
5617 root 1.1
5618     arglist = cdr (arglist);
5619     i++;
5620     }
5621     while (i < n);
5622    
5623     if (i < n)
5624     {
5625     ok = 0;
5626     snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", pcd->name, i + 1, tests[j].kind);
5627     }
5628     }
5629     }
5630    
5631     if (!ok)
5632     {
5633     if (xError_1 (SCHEME_A_ msg, 0) == NIL)
5634     return;
5635    
5636     pcd = dispatch_table + SCHEME_V->op;
5637     }
5638     }
5639 root 1.4 #endif
5640 root 1.1
5641     ok_to_freely_gc (SCHEME_A);
5642    
5643 root 1.2 if (pcd->func (SCHEME_A_ SCHEME_V->op) == NIL)
5644 root 1.1 return;
5645    
5646 root 1.5 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5647 root 1.1 {
5648     xwrstr ("No memory!\n");
5649     return;
5650     }
5651     }
5652     }
5653    
5654     /* ========== Initialization of internal keywords ========== */
5655    
5656     static void
5657 root 1.2 assign_syntax (SCHEME_P_ const char *name)
5658 root 1.1 {
5659     pointer x = oblist_add_by_name (SCHEME_A_ name);
5660     set_typeflag (x, typeflag (x) | T_SYNTAX);
5661     }
5662    
5663     static void
5664 root 1.2 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5665 root 1.1 {
5666     pointer x = mk_symbol (SCHEME_A_ name);
5667     pointer y = mk_proc (SCHEME_A_ op);
5668     new_slot_in_env (SCHEME_A_ x, y);
5669     }
5670    
5671     static pointer
5672     mk_proc (SCHEME_P_ enum scheme_opcodes op)
5673     {
5674     pointer y = get_cell (SCHEME_A_ NIL, NIL);
5675     set_typeflag (y, (T_PROC | T_ATOM));
5676 root 1.2 ivalue_unchecked (y) = op;
5677 root 1.1 set_num_integer (y);
5678     return y;
5679     }
5680    
5681     /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5682     static int
5683     syntaxnum (pointer p)
5684     {
5685     const char *s = strvalue (car (p));
5686    
5687     switch (strlength (car (p)))
5688     {
5689     case 2:
5690     if (s[0] == 'i')
5691     return OP_IF0; /* if */
5692     else
5693     return OP_OR0; /* or */
5694    
5695     case 3:
5696     if (s[0] == 'a')
5697     return OP_AND0; /* and */
5698     else
5699     return OP_LET0; /* let */
5700    
5701     case 4:
5702     switch (s[3])
5703     {
5704     case 'e':
5705     return OP_CASE0; /* case */
5706    
5707     case 'd':
5708     return OP_COND0; /* cond */
5709    
5710     case '*':
5711     return OP_LET0AST; /* let* */
5712    
5713     default:
5714     return OP_SET0; /* set! */
5715     }
5716    
5717     case 5:
5718     switch (s[2])
5719     {
5720     case 'g':
5721     return OP_BEGIN; /* begin */
5722    
5723     case 'l':
5724     return OP_DELAY; /* delay */
5725    
5726     case 'c':
5727     return OP_MACRO0; /* macro */
5728    
5729     default:
5730     return OP_QUOTE; /* quote */
5731     }
5732    
5733     case 6:
5734     switch (s[2])
5735     {
5736     case 'm':
5737     return OP_LAMBDA; /* lambda */
5738    
5739     case 'f':
5740     return OP_DEF0; /* define */
5741    
5742     default:
5743     return OP_LET0REC; /* letrec */
5744     }
5745    
5746     default:
5747     return OP_C0STREAM; /* cons-stream */
5748     }
5749     }
5750    
5751     #if USE_MULTIPLICITY
5752     scheme *
5753     scheme_init_new ()
5754     {
5755     scheme *sc = malloc (sizeof (scheme));
5756    
5757     if (!scheme_init (SCHEME_A))
5758     {
5759     free (SCHEME_A);
5760     return 0;
5761     }
5762     else
5763     return sc;
5764     }
5765     #endif
5766    
5767     int
5768     scheme_init (SCHEME_P)
5769     {
5770     int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5771     pointer x;
5772    
5773     num_set_fixnum (num_zero, 1);
5774     num_set_ivalue (num_zero, 0);
5775     num_set_fixnum (num_one, 1);
5776     num_set_ivalue (num_one, 1);
5777    
5778     #if USE_INTERFACE
5779     SCHEME_V->vptr = &vtbl;
5780     #endif
5781     SCHEME_V->gensym_cnt = 0;
5782     SCHEME_V->last_cell_seg = -1;
5783     SCHEME_V->free_cell = NIL;
5784     SCHEME_V->fcells = 0;
5785     SCHEME_V->no_memory = 0;
5786     SCHEME_V->inport = NIL;
5787     SCHEME_V->outport = NIL;
5788     SCHEME_V->save_inport = NIL;
5789     SCHEME_V->loadport = NIL;
5790     SCHEME_V->nesting = 0;
5791     SCHEME_V->interactive_repl = 0;
5792    
5793     if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5794     {
5795     #if USE_ERROR_CHECKING
5796     SCHEME_V->no_memory = 1;
5797     return 0;
5798     #endif
5799     }
5800    
5801     SCHEME_V->gc_verbose = 0;
5802     dump_stack_initialize (SCHEME_A);
5803     SCHEME_V->code = NIL;
5804 root 1.2 SCHEME_V->args = NIL;
5805     SCHEME_V->envir = NIL;
5806 root 1.1 SCHEME_V->tracing = 0;
5807    
5808     /* init NIL */
5809 root 1.2 set_typeflag (NIL, T_ATOM | T_MARK);
5810 root 1.1 set_car (NIL, NIL);
5811     set_cdr (NIL, NIL);
5812     /* init T */
5813 root 1.2 set_typeflag (S_T, T_ATOM | T_MARK);
5814 root 1.1 set_car (S_T, S_T);
5815     set_cdr (S_T, S_T);
5816     /* init F */
5817 root 1.2 set_typeflag (S_F, T_ATOM | T_MARK);
5818 root 1.1 set_car (S_F, S_F);
5819     set_cdr (S_F, S_F);
5820     /* init sink */
5821 root 1.2 set_typeflag (S_SINK, T_PAIR | T_MARK);
5822 root 1.1 set_car (S_SINK, NIL);
5823     /* init c_nest */
5824     SCHEME_V->c_nest = NIL;
5825    
5826     SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5827     /* init global_env */
5828     new_frame_in_env (SCHEME_A_ NIL);
5829     SCHEME_V->global_env = SCHEME_V->envir;
5830     /* init else */
5831     x = mk_symbol (SCHEME_A_ "else");
5832     new_slot_in_env (SCHEME_A_ x, S_T);
5833    
5834 root 1.2 {
5835     static const char *syntax_names[] = {
5836     "lambda", "quote", "define", "if", "begin", "set!",
5837     "let", "let*", "letrec", "cond", "delay", "and",
5838     "or", "cons-stream", "macro", "case"
5839     };
5840    
5841     for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5842     assign_syntax (SCHEME_A_ syntax_names[i]);
5843     }
5844 root 1.1
5845     for (i = 0; i < n; i++)
5846 root 1.2 if (dispatch_table[i].name != 0)
5847     assign_proc (SCHEME_A_ i, dispatch_table[i].name);
5848 root 1.1
5849     /* initialization of global pointers to special symbols */
5850     SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5851     SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5852     SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5853     SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5854     SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5855     SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5856     SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5857     SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5858     SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5859     SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5860    
5861     return !SCHEME_V->no_memory;
5862     }
5863    
5864     #if USE_PORTS
5865     void
5866     scheme_set_input_port_file (SCHEME_P_ int fin)
5867     {
5868     SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5869     }
5870    
5871     void
5872     scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5873     {
5874     SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5875     }
5876    
5877     void
5878     scheme_set_output_port_file (SCHEME_P_ int fout)
5879     {
5880     SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5881     }
5882    
5883     void
5884     scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5885     {
5886     SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5887     }
5888     #endif
5889    
5890     void
5891     scheme_set_external_data (SCHEME_P_ void *p)
5892     {
5893     SCHEME_V->ext_data = p;
5894     }
5895    
5896     void
5897     scheme_deinit (SCHEME_P)
5898     {
5899     int i;
5900    
5901     #if SHOW_ERROR_LINE
5902     char *fname;
5903     #endif
5904    
5905     SCHEME_V->oblist = NIL;
5906     SCHEME_V->global_env = NIL;
5907     dump_stack_free (SCHEME_A);
5908     SCHEME_V->envir = NIL;
5909     SCHEME_V->code = NIL;
5910     SCHEME_V->args = NIL;
5911     SCHEME_V->value = NIL;
5912    
5913     if (is_port (SCHEME_V->inport))
5914     set_typeflag (SCHEME_V->inport, T_ATOM);
5915    
5916     SCHEME_V->inport = NIL;
5917     SCHEME_V->outport = NIL;
5918    
5919     if (is_port (SCHEME_V->save_inport))
5920     set_typeflag (SCHEME_V->save_inport, T_ATOM);
5921    
5922     SCHEME_V->save_inport = NIL;
5923    
5924     if (is_port (SCHEME_V->loadport))
5925     set_typeflag (SCHEME_V->loadport, T_ATOM);
5926    
5927     SCHEME_V->loadport = NIL;
5928     SCHEME_V->gc_verbose = 0;
5929     gc (SCHEME_A_ NIL, NIL);
5930    
5931     for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5932     free (SCHEME_V->alloc_seg[i]);
5933    
5934     #if SHOW_ERROR_LINE
5935     for (i = 0; i <= SCHEME_V->file_i; i++)
5936     {
5937     if (SCHEME_V->load_stack[i].kind & port_file)
5938     {
5939     fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5940    
5941     if (fname)
5942     free (fname);
5943     }
5944     }
5945     #endif
5946     }
5947    
5948     void
5949     scheme_load_file (SCHEME_P_ int fin)
5950     {
5951     scheme_load_named_file (SCHEME_A_ fin, 0);
5952     }
5953    
5954     void
5955     scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5956     {
5957     dump_stack_reset (SCHEME_A);
5958     SCHEME_V->envir = SCHEME_V->global_env;
5959     SCHEME_V->file_i = 0;
5960     SCHEME_V->load_stack[0].unget = -1;
5961     SCHEME_V->load_stack[0].kind = port_input | port_file;
5962     SCHEME_V->load_stack[0].rep.stdio.file = fin;
5963     #if USE_PORTS
5964     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5965     #endif
5966     SCHEME_V->retcode = 0;
5967    
5968     #if USE_PORTS
5969     if (fin == STDIN_FILENO)
5970     SCHEME_V->interactive_repl = 1;
5971     #endif
5972    
5973     #if USE_PORTS
5974     #if SHOW_ERROR_LINE
5975     SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5976    
5977     if (fin != STDIN_FILENO && filename)
5978     SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5979     #endif
5980     #endif
5981    
5982     SCHEME_V->inport = SCHEME_V->loadport;
5983     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5984     Eval_Cycle (SCHEME_A_ OP_T0LVL);
5985     set_typeflag (SCHEME_V->loadport, T_ATOM);
5986    
5987     if (SCHEME_V->retcode == 0)
5988     SCHEME_V->retcode = SCHEME_V->nesting != 0;
5989     }
5990    
5991     void
5992     scheme_load_string (SCHEME_P_ const char *cmd)
5993     {
5994     dump_stack_reset (SCHEME_A);
5995     SCHEME_V->envir = SCHEME_V->global_env;
5996     SCHEME_V->file_i = 0;
5997     SCHEME_V->load_stack[0].kind = port_input | port_string;
5998     SCHEME_V->load_stack[0].rep.string.start = (char *) cmd; /* This func respects const */
5999     SCHEME_V->load_stack[0].rep.string.past_the_end = (char *) cmd + strlen (cmd);
6000     SCHEME_V->load_stack[0].rep.string.curr = (char *) cmd;
6001     #if USE_PORTS
6002     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
6003     #endif
6004     SCHEME_V->retcode = 0;
6005     SCHEME_V->interactive_repl = 0;
6006     SCHEME_V->inport = SCHEME_V->loadport;
6007     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
6008     Eval_Cycle (SCHEME_A_ OP_T0LVL);
6009     set_typeflag (SCHEME_V->loadport, T_ATOM);
6010    
6011     if (SCHEME_V->retcode == 0)
6012     SCHEME_V->retcode = SCHEME_V->nesting != 0;
6013     }
6014    
6015     void
6016     scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
6017     {
6018     pointer x;
6019    
6020     x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
6021    
6022     if (x != NIL)
6023 root 1.2 set_slot_in_env (SCHEME_A_ x, value);
6024 root 1.1 else
6025 root 1.2 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
6026 root 1.1 }
6027    
6028     #if !STANDALONE
6029 root 1.2
6030 root 1.1 void
6031     scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
6032     {
6033     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
6034     }
6035    
6036     void
6037     scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
6038     {
6039     int i;
6040    
6041     for (i = 0; i < count; i++)
6042 root 1.2 scheme_register_foreign_func (SCHEME_A_ list + i);
6043 root 1.1 }
6044    
6045     pointer
6046     scheme_apply0 (SCHEME_P_ const char *procname)
6047     {
6048     return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
6049     }
6050    
6051     void
6052     save_from_C_call (SCHEME_P)
6053     {
6054     pointer saved_data = cons (car (S_SINK),
6055     cons (SCHEME_V->envir,
6056     SCHEME_V->dump));
6057    
6058     /* Push */
6059     SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
6060     /* Truncate the dump stack so TS will return here when done, not
6061     directly resume pre-C-call operations. */
6062     dump_stack_reset (SCHEME_A);
6063     }
6064    
6065     void
6066     restore_from_C_call (SCHEME_P)
6067     {
6068     set_car (S_SINK, caar (SCHEME_V->c_nest));
6069     SCHEME_V->envir = cadar (SCHEME_V->c_nest);
6070     SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
6071     /* Pop */
6072     SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
6073     }
6074    
6075     /* "func" and "args" are assumed to be already eval'ed. */
6076     pointer
6077     scheme_call (SCHEME_P_ pointer func, pointer args)
6078     {
6079     int old_repl = SCHEME_V->interactive_repl;
6080    
6081     SCHEME_V->interactive_repl = 0;
6082     save_from_C_call (SCHEME_A);
6083     SCHEME_V->envir = SCHEME_V->global_env;
6084     SCHEME_V->args = args;
6085     SCHEME_V->code = func;
6086     SCHEME_V->retcode = 0;
6087     Eval_Cycle (SCHEME_A_ OP_APPLY);
6088     SCHEME_V->interactive_repl = old_repl;
6089     restore_from_C_call (SCHEME_A);
6090     return SCHEME_V->value;
6091     }
6092    
6093     pointer
6094     scheme_eval (SCHEME_P_ pointer obj)
6095     {
6096     int old_repl = SCHEME_V->interactive_repl;
6097    
6098     SCHEME_V->interactive_repl = 0;
6099     save_from_C_call (SCHEME_A);
6100     SCHEME_V->args = NIL;
6101     SCHEME_V->code = obj;
6102     SCHEME_V->retcode = 0;
6103     Eval_Cycle (SCHEME_A_ OP_EVAL);
6104     SCHEME_V->interactive_repl = old_repl;
6105     restore_from_C_call (SCHEME_A);
6106     return SCHEME_V->value;
6107     }
6108    
6109     #endif
6110    
6111     /* ========== Main ========== */
6112    
6113     #if STANDALONE
6114    
6115     # if defined(__APPLE__) && !defined (OSX)
6116     int
6117     main ()
6118     {
6119     extern MacTS_main (int argc, char **argv);
6120     char **argv;
6121     int argc = ccommand (&argv);
6122    
6123     MacTS_main (argc, argv);
6124     return 0;
6125     }
6126    
6127     int
6128     MacTS_main (int argc, char **argv)
6129     {
6130     # else
6131     int
6132     main (int argc, char **argv)
6133     {
6134     # endif
6135     # if USE_MULTIPLICITY
6136     scheme ssc;
6137 root 1.2 scheme *const SCHEME_V = &ssc;
6138 root 1.1 # else
6139     # endif
6140     int fin;
6141     char *file_name = InitFile;
6142     int retcode;
6143     int isfile = 1;
6144    
6145     if (argc == 2 && strcmp (argv[1], "-?") == 0)
6146     {
6147     xwrstr ("Usage: tinyscheme -?\n");
6148     xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
6149     xwrstr ("followed by\n");
6150     xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
6151     xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
6152     xwrstr ("assuming that the executable is named tinyscheme.\n");
6153     xwrstr ("Use - as filename for stdin.\n");
6154     return 1;
6155     }
6156    
6157     if (!scheme_init (SCHEME_A))
6158     {
6159     xwrstr ("Could not initialize!\n");
6160     return 2;
6161     }
6162    
6163     # if USE_PORTS
6164     scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
6165     scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
6166     # endif
6167    
6168     argv++;
6169    
6170     #if 0
6171     if (access (file_name, 0) != 0)
6172     {
6173     char *p = getenv ("TINYSCHEMEINIT");
6174    
6175     if (p != 0)
6176 root 1.2 file_name = p;
6177 root 1.1 }
6178     #endif
6179    
6180     do
6181     {
6182     #if USE_PORTS
6183     if (strcmp (file_name, "-") == 0)
6184     fin = STDIN_FILENO;
6185     else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
6186     {
6187     pointer args = NIL;
6188    
6189     isfile = file_name[1] == '1';
6190     file_name = *argv++;
6191    
6192     if (strcmp (file_name, "-") == 0)
6193     fin = STDIN_FILENO;
6194     else if (isfile)
6195     fin = open (file_name, O_RDONLY);
6196    
6197     for (; *argv; argv++)
6198     {
6199     pointer value = mk_string (SCHEME_A_ * argv);
6200    
6201     args = cons (value, args);
6202     }
6203    
6204     args = reverse_in_place (SCHEME_A_ NIL, args);
6205     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
6206    
6207     }
6208     else
6209     fin = open (file_name, O_RDONLY);
6210     #endif
6211    
6212     if (isfile && fin < 0)
6213     {
6214     xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
6215     }
6216     else
6217     {
6218     if (isfile)
6219     scheme_load_named_file (SCHEME_A_ fin, file_name);
6220     else
6221     scheme_load_string (SCHEME_A_ file_name);
6222    
6223     #if USE_PORTS
6224     if (!isfile || fin != STDIN_FILENO)
6225     {
6226     if (SCHEME_V->retcode != 0)
6227     {
6228     xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
6229     }
6230    
6231     if (isfile)
6232     close (fin);
6233     }
6234     #endif
6235     }
6236    
6237     file_name = *argv++;
6238     }
6239     while (file_name != 0);
6240    
6241     if (argc == 1)
6242     scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6243    
6244     retcode = SCHEME_V->retcode;
6245     scheme_deinit (SCHEME_A);
6246    
6247     return retcode;
6248     }
6249    
6250     #endif
6251    
6252     /*
6253     Local variables:
6254     c-file-style: "k&r"
6255     End:
6256     */