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