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