ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.8
Committed: Wed Nov 25 22:36:25 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.7: +21 -54 lines
Log Message:
*** empty log message ***

File Contents

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