ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.19
Committed: Thu Nov 26 21:36:11 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.18: +24 -26 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     static pointer opexe_0 (SCHEME_P_ enum scheme_opcodes op);
673     static pointer opexe_2 (SCHEME_P_ enum scheme_opcodes op);
674 root 1.14 static pointer opexe_r (SCHEME_P_ enum scheme_opcodes op);
675 root 1.1 static pointer opexe_3 (SCHEME_P_ enum scheme_opcodes op);
676     static pointer opexe_4 (SCHEME_P_ enum scheme_opcodes op);
677     static pointer opexe_5 (SCHEME_P_ enum scheme_opcodes op);
678     static pointer opexe_6 (SCHEME_P_ enum scheme_opcodes op);
679     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     static pointer
2938     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     return S_T;
2983     }
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.1 return S_T;
2995     }
2996    
2997     #define Error_1(s, a) return xError_1(SCHEME_A_ USE_ERROR_CHECKING ? s : "", a)
2998     #define Error_0(s) Error_1 (s, 0)
2999    
3000     /* Too small to turn into function */
3001 root 1.2 #define BEGIN do {
3002     #define END } while (0)
3003     #define s_goto(a) BEGIN \
3004     SCHEME_V->op = a; \
3005 root 1.1 return S_T; END
3006    
3007 root 1.2 #define s_return(a) return xs_return (SCHEME_A_ a)
3008 root 1.1
3009     #ifndef USE_SCHEME_STACK
3010    
3011     /* this structure holds all the interpreter's registers */
3012     struct dump_stack_frame
3013     {
3014     enum scheme_opcodes op;
3015     pointer args;
3016     pointer envir;
3017     pointer code;
3018     };
3019    
3020     # define STACK_GROWTH 3
3021    
3022     static void
3023     s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3024     {
3025     int nframes = (uintptr_t)SCHEME_V->dump;
3026     struct dump_stack_frame *next_frame;
3027    
3028     /* enough room for the next frame? */
3029     if (nframes >= SCHEME_V->dump_size)
3030     {
3031     SCHEME_V->dump_size += STACK_GROWTH;
3032     SCHEME_V->dump_base = realloc (SCHEME_V->dump_base, sizeof (struct dump_stack_frame) * SCHEME_V->dump_size);
3033     }
3034    
3035     next_frame = SCHEME_V->dump_base + nframes;
3036 root 1.2
3037     next_frame->op = op;
3038     next_frame->args = args;
3039 root 1.1 next_frame->envir = SCHEME_V->envir;
3040 root 1.16 next_frame->code = code;
3041 root 1.2
3042 root 1.1 SCHEME_V->dump = (pointer)(uintptr_t)(nframes + 1);
3043     }
3044    
3045     static pointer
3046     xs_return (SCHEME_P_ pointer a)
3047     {
3048     int nframes = (uintptr_t)SCHEME_V->dump;
3049     struct dump_stack_frame *frame;
3050    
3051     SCHEME_V->value = a;
3052    
3053     if (nframes <= 0)
3054     return NIL;
3055    
3056 root 1.2 frame = &SCHEME_V->dump_base[--nframes];
3057     SCHEME_V->op = frame->op;
3058     SCHEME_V->args = frame->args;
3059 root 1.1 SCHEME_V->envir = frame->envir;
3060 root 1.2 SCHEME_V->code = frame->code;
3061     SCHEME_V->dump = (pointer)(uintptr_t)nframes;
3062 root 1.1
3063     return S_T;
3064     }
3065    
3066     static INLINE void
3067     dump_stack_reset (SCHEME_P)
3068     {
3069     /* in this implementation, SCHEME_V->dump is the number of frames on the stack */
3070 root 1.2 SCHEME_V->dump = (pointer)+0;
3071 root 1.1 }
3072    
3073     static INLINE void
3074     dump_stack_initialize (SCHEME_P)
3075     {
3076     SCHEME_V->dump_size = 0;
3077 root 1.2 SCHEME_V->dump_base = 0;
3078 root 1.1 dump_stack_reset (SCHEME_A);
3079     }
3080    
3081     static void
3082     dump_stack_free (SCHEME_P)
3083     {
3084     free (SCHEME_V->dump_base);
3085 root 1.2 SCHEME_V->dump_base = 0;
3086 root 1.1 SCHEME_V->dump = (pointer)0;
3087     SCHEME_V->dump_size = 0;
3088     }
3089    
3090     static void
3091     dump_stack_mark (SCHEME_P)
3092     {
3093     int nframes = (uintptr_t)SCHEME_V->dump;
3094     int i;
3095    
3096     for (i = 0; i < nframes; i++)
3097     {
3098     struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3099    
3100     mark (frame->args);
3101     mark (frame->envir);
3102     mark (frame->code);
3103     }
3104     }
3105    
3106     static pointer
3107     ss_get_cont (SCHEME_P)
3108     {
3109     int nframes = (uintptr_t)SCHEME_V->dump;
3110     int i;
3111    
3112     pointer cont = NIL;
3113    
3114     for (i = nframes; i--; )
3115     {
3116     struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3117    
3118     cont = cons (mk_integer (SCHEME_A_ frame->op),
3119     cons (frame->args,
3120     cons (frame->envir,
3121     cons (frame->code,
3122     cont))));
3123     }
3124    
3125     return cont;
3126     }
3127    
3128     static void
3129     ss_set_cont (SCHEME_P_ pointer cont)
3130     {
3131     int i = 0;
3132     struct dump_stack_frame *frame = SCHEME_V->dump_base;
3133    
3134     while (cont != NIL)
3135     {
3136     frame->op = ivalue (car (cont)); cont = cdr (cont);
3137 root 1.2 frame->args = car (cont) ; cont = cdr (cont);
3138     frame->envir = car (cont) ; cont = cdr (cont);
3139     frame->code = car (cont) ; cont = cdr (cont);
3140 root 1.1
3141     ++frame;
3142     ++i;
3143     }
3144    
3145     SCHEME_V->dump = (pointer)(uintptr_t)i;
3146     }
3147    
3148     #else
3149    
3150     static INLINE void
3151     dump_stack_reset (SCHEME_P)
3152     {
3153     SCHEME_V->dump = NIL;
3154     }
3155    
3156     static INLINE void
3157     dump_stack_initialize (SCHEME_P)
3158     {
3159     dump_stack_reset (SCHEME_A);
3160     }
3161    
3162     static void
3163     dump_stack_free (SCHEME_P)
3164     {
3165     SCHEME_V->dump = NIL;
3166     }
3167    
3168     static pointer
3169     xs_return (SCHEME_P_ pointer a)
3170     {
3171     pointer dump = SCHEME_V->dump;
3172    
3173     SCHEME_V->value = a;
3174    
3175     if (dump == NIL)
3176     return NIL;
3177    
3178 root 1.2 SCHEME_V->op = ivalue (car (dump)); dump = cdr (dump);
3179     SCHEME_V->args = car (dump) ; dump = cdr (dump);
3180     SCHEME_V->envir = car (dump) ; dump = cdr (dump);
3181     SCHEME_V->code = car (dump) ; dump = cdr (dump);
3182 root 1.1
3183     SCHEME_V->dump = dump;
3184    
3185     return S_T;
3186     }
3187    
3188     static void
3189     s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3190     {
3191     SCHEME_V->dump = cons (mk_integer (SCHEME_A_ op),
3192     cons (args,
3193     cons (SCHEME_V->envir,
3194     cons (code,
3195     SCHEME_V->dump))));
3196     }
3197    
3198     static void
3199     dump_stack_mark (SCHEME_P)
3200     {
3201     mark (SCHEME_V->dump);
3202     }
3203    
3204     static pointer
3205     ss_get_cont (SCHEME_P)
3206     {
3207     return SCHEME_V->dump;
3208     }
3209    
3210     static void
3211     ss_set_cont (SCHEME_P_ pointer cont)
3212     {
3213     SCHEME_V->dump = cont;
3214     }
3215    
3216     #endif
3217    
3218     #define s_retbool(tf) s_return ((tf) ? S_T : S_F)
3219    
3220     static pointer
3221     opexe_0 (SCHEME_P_ enum scheme_opcodes op)
3222     {
3223 root 1.16 pointer args = SCHEME_V->args;
3224 root 1.1 pointer x, y;
3225    
3226     switch (op)
3227     {
3228     case OP_LOAD: /* load */
3229     if (file_interactive (SCHEME_A))
3230     {
3231 root 1.16 xwrstr ("Loading "); xwrstr (strvalue (car (args))); xwrstr ("\n");
3232     //D fprintf (SCHEME_V->outport->object.port->rep.stdio.file, "Loading %s\n", strvalue (car (args)));
3233 root 1.1 }
3234    
3235 root 1.16 if (!file_push (SCHEME_A_ strvalue (car (args))))
3236     Error_1 ("unable to open", car (args));
3237 root 1.1 else
3238     {
3239     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
3240     s_goto (OP_T0LVL);
3241     }
3242    
3243     case OP_T0LVL: /* top level */
3244    
3245     /* If we reached the end of file, this loop is done. */
3246     if (SCHEME_V->loadport->object.port->kind & port_saw_EOF)
3247     {
3248     if (SCHEME_V->file_i == 0)
3249     {
3250     SCHEME_V->args = NIL;
3251     s_goto (OP_QUIT);
3252     }
3253     else
3254     {
3255     file_pop (SCHEME_A);
3256     s_return (SCHEME_V->value);
3257     }
3258    
3259     /* NOTREACHED */
3260     }
3261    
3262     /* If interactive, be nice to user. */
3263     if (file_interactive (SCHEME_A))
3264     {
3265     SCHEME_V->envir = SCHEME_V->global_env;
3266     dump_stack_reset (SCHEME_A);
3267     putstr (SCHEME_A_ "\n");
3268     putstr (SCHEME_A_ prompt);
3269     }
3270    
3271     /* Set up another iteration of REPL */
3272     SCHEME_V->nesting = 0;
3273     SCHEME_V->save_inport = SCHEME_V->inport;
3274     SCHEME_V->inport = SCHEME_V->loadport;
3275     s_save (SCHEME_A_ OP_T0LVL, NIL, NIL);
3276     s_save (SCHEME_A_ OP_VALUEPRINT, NIL, NIL);
3277     s_save (SCHEME_A_ OP_T1LVL, NIL, NIL);
3278     s_goto (OP_READ_INTERNAL);
3279    
3280     case OP_T1LVL: /* top level */
3281 root 1.7 SCHEME_V->code = SCHEME_V->value;
3282 root 1.1 SCHEME_V->inport = SCHEME_V->save_inport;
3283     s_goto (OP_EVAL);
3284    
3285     case OP_READ_INTERNAL: /* internal read */
3286     SCHEME_V->tok = token (SCHEME_A);
3287    
3288     if (SCHEME_V->tok == TOK_EOF)
3289 root 1.2 s_return (S_EOF);
3290 root 1.1
3291     s_goto (OP_RDSEXPR);
3292    
3293     case OP_GENSYM:
3294     s_return (gensym (SCHEME_A));
3295    
3296     case OP_VALUEPRINT: /* print evaluation result */
3297    
3298     /* OP_VALUEPRINT is always pushed, because when changing from
3299     non-interactive to interactive mode, it needs to be
3300     already on the stack */
3301     #if USE_TRACING
3302     if (SCHEME_V->tracing)
3303 root 1.2 putstr (SCHEME_A_ "\nGives: ");
3304 root 1.1 #endif
3305    
3306     if (file_interactive (SCHEME_A))
3307     {
3308     SCHEME_V->print_flag = 1;
3309     SCHEME_V->args = SCHEME_V->value;
3310     s_goto (OP_P0LIST);
3311     }
3312     else
3313 root 1.2 s_return (SCHEME_V->value);
3314 root 1.1
3315     case OP_EVAL: /* main part of evaluation */
3316     #if USE_TRACING
3317     if (SCHEME_V->tracing)
3318     {
3319     /*s_save(SCHEME_A_ OP_VALUEPRINT,NIL,NIL); */
3320 root 1.16 s_save (SCHEME_A_ OP_REAL_EVAL, args, SCHEME_V->code);
3321 root 1.1 SCHEME_V->args = SCHEME_V->code;
3322     putstr (SCHEME_A_ "\nEval: ");
3323     s_goto (OP_P0LIST);
3324     }
3325    
3326     /* fall through */
3327 root 1.2
3328 root 1.1 case OP_REAL_EVAL:
3329     #endif
3330     if (is_symbol (SCHEME_V->code)) /* symbol */
3331     {
3332     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3333    
3334     if (x != NIL)
3335     s_return (slot_value_in_env (x));
3336     else
3337     Error_1 ("eval: unbound variable:", SCHEME_V->code);
3338     }
3339     else if (is_pair (SCHEME_V->code))
3340     {
3341 root 1.7 x = car (SCHEME_V->code);
3342    
3343     if (is_syntax (x)) /* SYNTAX */
3344 root 1.1 {
3345     SCHEME_V->code = cdr (SCHEME_V->code);
3346     s_goto (syntaxnum (x));
3347     }
3348     else /* first, eval top element and eval arguments */
3349     {
3350     s_save (SCHEME_A_ OP_E0ARGS, NIL, SCHEME_V->code);
3351     /* If no macros => s_save(SCHEME_A_ OP_E1ARGS, NIL, cdr(SCHEME_V->code)); */
3352 root 1.7 SCHEME_V->code = x;
3353 root 1.1 s_goto (OP_EVAL);
3354     }
3355     }
3356     else
3357     s_return (SCHEME_V->code);
3358    
3359     case OP_E0ARGS: /* eval arguments */
3360     if (is_macro (SCHEME_V->value)) /* macro expansion */
3361     {
3362     s_save (SCHEME_A_ OP_DOMACRO, NIL, NIL);
3363     SCHEME_V->args = cons (SCHEME_V->code, NIL);
3364     SCHEME_V->code = SCHEME_V->value;
3365     s_goto (OP_APPLY);
3366     }
3367     else
3368     {
3369     SCHEME_V->code = cdr (SCHEME_V->code);
3370     s_goto (OP_E1ARGS);
3371     }
3372    
3373     case OP_E1ARGS: /* eval arguments */
3374 root 1.16 args = cons (SCHEME_V->value, args);
3375 root 1.1
3376     if (is_pair (SCHEME_V->code)) /* continue */
3377     {
3378 root 1.16 s_save (SCHEME_A_ OP_E1ARGS, args, cdr (SCHEME_V->code));
3379 root 1.1 SCHEME_V->code = car (SCHEME_V->code);
3380     SCHEME_V->args = NIL;
3381     s_goto (OP_EVAL);
3382     }
3383     else /* end */
3384     {
3385 root 1.16 args = reverse_in_place (SCHEME_A_ NIL, args);
3386     SCHEME_V->code = car (args);
3387     SCHEME_V->args = cdr (args);
3388 root 1.1 s_goto (OP_APPLY);
3389     }
3390    
3391     #if USE_TRACING
3392    
3393     case OP_TRACING:
3394     {
3395     int tr = SCHEME_V->tracing;
3396    
3397 root 1.16 SCHEME_V->tracing = ivalue (car (args));
3398 root 1.1 s_return (mk_integer (SCHEME_A_ tr));
3399     }
3400    
3401     #endif
3402    
3403     case OP_APPLY: /* apply 'code' to 'args' */
3404     #if USE_TRACING
3405     if (SCHEME_V->tracing)
3406     {
3407 root 1.16 s_save (SCHEME_A_ OP_REAL_APPLY, args, SCHEME_V->code);
3408 root 1.1 SCHEME_V->print_flag = 1;
3409 root 1.16 /* args=cons(SCHEME_V->code,args); */
3410 root 1.1 putstr (SCHEME_A_ "\nApply to: ");
3411     s_goto (OP_P0LIST);
3412     }
3413    
3414     /* fall through */
3415 root 1.2
3416 root 1.1 case OP_REAL_APPLY:
3417     #endif
3418     if (is_proc (SCHEME_V->code))
3419 root 1.18 s_goto (procnum (SCHEME_V->code)); /* PROCEDURE */
3420 root 1.1 else if (is_foreign (SCHEME_V->code))
3421     {
3422     /* Keep nested calls from GC'ing the arglist */
3423 root 1.16 push_recent_alloc (SCHEME_A_ args, NIL);
3424     x = SCHEME_V->code->object.ff (SCHEME_A_ args);
3425 root 1.1
3426     s_return (x);
3427     }
3428     else if (is_closure (SCHEME_V->code) || is_macro (SCHEME_V->code) || is_promise (SCHEME_V->code)) /* CLOSURE */
3429     {
3430     /* Should not accept promise */
3431     /* make environment */
3432     new_frame_in_env (SCHEME_A_ closure_env (SCHEME_V->code));
3433    
3434 root 1.16 for (x = car (closure_code (SCHEME_V->code)), y = args; is_pair (x); x = cdr (x), y = cdr (y))
3435 root 1.1 {
3436     if (y == NIL)
3437 root 1.2 Error_0 ("not enough arguments");
3438 root 1.1 else
3439 root 1.2 new_slot_in_env (SCHEME_A_ car (x), car (y));
3440 root 1.1 }
3441    
3442     if (x == NIL)
3443     {
3444 root 1.2 /*--
3445     * if (y != NIL) {
3446     * Error_0("too many arguments");
3447     * }
3448     */
3449 root 1.1 }
3450     else if (is_symbol (x))
3451     new_slot_in_env (SCHEME_A_ x, y);
3452     else
3453 root 1.2 Error_1 ("syntax error in closure: not a symbol:", x);
3454 root 1.1
3455     SCHEME_V->code = cdr (closure_code (SCHEME_V->code));
3456     SCHEME_V->args = NIL;
3457     s_goto (OP_BEGIN);
3458     }
3459     else if (is_continuation (SCHEME_V->code)) /* CONTINUATION */
3460     {
3461     ss_set_cont (SCHEME_A_ cont_dump (SCHEME_V->code));
3462 root 1.16 s_return (args != NIL ? car (args) : NIL);
3463 root 1.1 }
3464     else
3465     Error_0 ("illegal function");
3466    
3467     case OP_DOMACRO: /* do macro */
3468     SCHEME_V->code = SCHEME_V->value;
3469     s_goto (OP_EVAL);
3470    
3471     #if 1
3472    
3473     case OP_LAMBDA: /* lambda */
3474     /* If the hook is defined, apply it to SCHEME_V->code, otherwise
3475     set SCHEME_V->value fall thru */
3476     {
3477     pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->COMPILE_HOOK, 1);
3478    
3479     if (f != NIL)
3480     {
3481 root 1.16 s_save (SCHEME_A_ OP_LAMBDA1, args, SCHEME_V->code);
3482 root 1.1 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3483     SCHEME_V->code = slot_value_in_env (f);
3484     s_goto (OP_APPLY);
3485     }
3486    
3487     SCHEME_V->value = SCHEME_V->code;
3488     /* Fallthru */
3489     }
3490    
3491     case OP_LAMBDA1:
3492     s_return (mk_closure (SCHEME_A_ SCHEME_V->value, SCHEME_V->envir));
3493    
3494     #else
3495    
3496     case OP_LAMBDA: /* lambda */
3497     s_return (mk_closure (SCHEME_A_ SCHEME_V->code, SCHEME_V->envir));
3498    
3499     #endif
3500    
3501     case OP_MKCLOSURE: /* make-closure */
3502 root 1.16 x = car (args);
3503 root 1.1
3504     if (car (x) == SCHEME_V->LAMBDA)
3505     x = cdr (x);
3506    
3507 root 1.16 if (cdr (args) == NIL)
3508 root 1.1 y = SCHEME_V->envir;
3509     else
3510 root 1.16 y = cadr (args);
3511 root 1.1
3512     s_return (mk_closure (SCHEME_A_ x, y));
3513    
3514     case OP_QUOTE: /* quote */
3515     s_return (car (SCHEME_V->code));
3516    
3517     case OP_DEF0: /* define */
3518     if (is_immutable (car (SCHEME_V->code)))
3519     Error_1 ("define: unable to alter immutable", car (SCHEME_V->code));
3520    
3521     if (is_pair (car (SCHEME_V->code)))
3522     {
3523     x = caar (SCHEME_V->code);
3524     SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3525     }
3526     else
3527     {
3528     x = car (SCHEME_V->code);
3529     SCHEME_V->code = cadr (SCHEME_V->code);
3530     }
3531    
3532     if (!is_symbol (x))
3533 root 1.2 Error_0 ("variable is not a symbol");
3534 root 1.1
3535     s_save (SCHEME_A_ OP_DEF1, NIL, x);
3536     s_goto (OP_EVAL);
3537    
3538     case OP_DEF1: /* define */
3539     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3540    
3541     if (x != NIL)
3542 root 1.2 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3543 root 1.1 else
3544 root 1.2 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3545 root 1.1
3546     s_return (SCHEME_V->code);
3547    
3548    
3549     case OP_DEFP: /* defined? */
3550     x = SCHEME_V->envir;
3551    
3552 root 1.16 if (cdr (args) != NIL)
3553     x = cadr (args);
3554 root 1.1
3555 root 1.16 s_retbool (find_slot_in_env (SCHEME_A_ x, car (args), 1) != NIL);
3556 root 1.1
3557     case OP_SET0: /* set! */
3558     if (is_immutable (car (SCHEME_V->code)))
3559     Error_1 ("set!: unable to alter immutable variable", car (SCHEME_V->code));
3560    
3561     s_save (SCHEME_A_ OP_SET1, NIL, car (SCHEME_V->code));
3562     SCHEME_V->code = cadr (SCHEME_V->code);
3563     s_goto (OP_EVAL);
3564    
3565     case OP_SET1: /* set! */
3566     y = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3567    
3568     if (y != NIL)
3569     {
3570     set_slot_in_env (SCHEME_A_ y, SCHEME_V->value);
3571     s_return (SCHEME_V->value);
3572     }
3573     else
3574 root 1.2 Error_1 ("set!: unbound variable:", SCHEME_V->code);
3575 root 1.1
3576    
3577     case OP_BEGIN: /* begin */
3578     if (!is_pair (SCHEME_V->code))
3579 root 1.2 s_return (SCHEME_V->code);
3580 root 1.1
3581     if (cdr (SCHEME_V->code) != NIL)
3582 root 1.2 s_save (SCHEME_A_ OP_BEGIN, NIL, cdr (SCHEME_V->code));
3583 root 1.1
3584     SCHEME_V->code = car (SCHEME_V->code);
3585     s_goto (OP_EVAL);
3586    
3587     case OP_IF0: /* if */
3588     s_save (SCHEME_A_ OP_IF1, NIL, cdr (SCHEME_V->code));
3589     SCHEME_V->code = car (SCHEME_V->code);
3590     s_goto (OP_EVAL);
3591    
3592     case OP_IF1: /* if */
3593     if (is_true (SCHEME_V->value))
3594     SCHEME_V->code = car (SCHEME_V->code);
3595     else
3596 root 1.18 SCHEME_V->code = cadr (SCHEME_V->code); /* (if #f 1) ==> () because * car(NIL) = NIL */
3597 root 1.1 s_goto (OP_EVAL);
3598    
3599     case OP_LET0: /* let */
3600     SCHEME_V->args = NIL;
3601     SCHEME_V->value = SCHEME_V->code;
3602     SCHEME_V->code = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code);
3603     s_goto (OP_LET1);
3604    
3605     case OP_LET1: /* let (calculate parameters) */
3606 root 1.16 args = cons (SCHEME_V->value, args);
3607 root 1.1
3608     if (is_pair (SCHEME_V->code)) /* continue */
3609     {
3610     if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3611 root 1.2 Error_1 ("Bad syntax of binding spec in let :", car (SCHEME_V->code));
3612 root 1.1
3613 root 1.16 s_save (SCHEME_A_ OP_LET1, args, cdr (SCHEME_V->code));
3614 root 1.1 SCHEME_V->code = cadar (SCHEME_V->code);
3615     SCHEME_V->args = NIL;
3616     s_goto (OP_EVAL);
3617     }
3618     else /* end */
3619     {
3620 root 1.16 args = reverse_in_place (SCHEME_A_ NIL, args);
3621     SCHEME_V->code = car (args);
3622     SCHEME_V->args = cdr (args);
3623 root 1.1 s_goto (OP_LET2);
3624     }
3625    
3626     case OP_LET2: /* let */
3627     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3628    
3629 root 1.16 for (x = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code), y = args;
3630 root 1.1 y != NIL; x = cdr (x), y = cdr (y))
3631 root 1.2 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3632 root 1.1
3633     if (is_symbol (car (SCHEME_V->code))) /* named let */
3634     {
3635 root 1.16 for (x = cadr (SCHEME_V->code), args = NIL; x != NIL; x = cdr (x))
3636 root 1.1 {
3637     if (!is_pair (x))
3638     Error_1 ("Bad syntax of binding in let :", x);
3639    
3640     if (!is_list (SCHEME_A_ car (x)))
3641     Error_1 ("Bad syntax of binding in let :", car (x));
3642    
3643 root 1.16 args = cons (caar (x), args);
3644 root 1.1 }
3645    
3646 root 1.16 x = mk_closure (SCHEME_A_ cons (reverse_in_place (SCHEME_A_ NIL, args), cddr (SCHEME_V->code)),
3647     SCHEME_V->envir);
3648 root 1.1 new_slot_in_env (SCHEME_A_ car (SCHEME_V->code), x);
3649     SCHEME_V->code = cddr (SCHEME_V->code);
3650     }
3651     else
3652     {
3653     SCHEME_V->code = cdr (SCHEME_V->code);
3654     }
3655    
3656 root 1.16 SCHEME_V->args = NIL;
3657 root 1.1 s_goto (OP_BEGIN);
3658    
3659     case OP_LET0AST: /* let* */
3660     if (car (SCHEME_V->code) == NIL)
3661     {
3662     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3663     SCHEME_V->code = cdr (SCHEME_V->code);
3664     s_goto (OP_BEGIN);
3665     }
3666    
3667     if (!is_pair (car (SCHEME_V->code)) || !is_pair (caar (SCHEME_V->code)) || !is_pair (cdaar (SCHEME_V->code)))
3668     Error_1 ("Bad syntax of binding spec in let* :", car (SCHEME_V->code));
3669    
3670     s_save (SCHEME_A_ OP_LET1AST, cdr (SCHEME_V->code), car (SCHEME_V->code));
3671     SCHEME_V->code = car (cdaar (SCHEME_V->code));
3672     s_goto (OP_EVAL);
3673    
3674     case OP_LET1AST: /* let* (make new frame) */
3675     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3676     s_goto (OP_LET2AST);
3677    
3678     case OP_LET2AST: /* let* (calculate parameters) */
3679     new_slot_in_env (SCHEME_A_ caar (SCHEME_V->code), SCHEME_V->value);
3680     SCHEME_V->code = cdr (SCHEME_V->code);
3681    
3682     if (is_pair (SCHEME_V->code)) /* continue */
3683     {
3684 root 1.16 s_save (SCHEME_A_ OP_LET2AST, args, SCHEME_V->code);
3685 root 1.1 SCHEME_V->code = cadar (SCHEME_V->code);
3686     SCHEME_V->args = NIL;
3687     s_goto (OP_EVAL);
3688     }
3689     else /* end */
3690     {
3691 root 1.16 SCHEME_V->code = args;
3692 root 1.1 SCHEME_V->args = NIL;
3693     s_goto (OP_BEGIN);
3694     }
3695    
3696     case OP_LET0REC: /* letrec */
3697     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3698     SCHEME_V->args = NIL;
3699     SCHEME_V->value = SCHEME_V->code;
3700     SCHEME_V->code = car (SCHEME_V->code);
3701     s_goto (OP_LET1REC);
3702    
3703     case OP_LET1REC: /* letrec (calculate parameters) */
3704 root 1.16 args = cons (SCHEME_V->value, args);
3705 root 1.1
3706     if (is_pair (SCHEME_V->code)) /* continue */
3707     {
3708     if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3709 root 1.2 Error_1 ("Bad syntax of binding spec in letrec :", car (SCHEME_V->code));
3710 root 1.1
3711 root 1.16 s_save (SCHEME_A_ OP_LET1REC, args, cdr (SCHEME_V->code));
3712 root 1.1 SCHEME_V->code = cadar (SCHEME_V->code);
3713     SCHEME_V->args = NIL;
3714     s_goto (OP_EVAL);
3715     }
3716     else /* end */
3717     {
3718 root 1.16 args = reverse_in_place (SCHEME_A_ NIL, args);
3719     SCHEME_V->code = car (args);
3720     SCHEME_V->args = cdr (args);
3721 root 1.1 s_goto (OP_LET2REC);
3722     }
3723    
3724     case OP_LET2REC: /* letrec */
3725 root 1.16 for (x = car (SCHEME_V->code), y = args; y != NIL; x = cdr (x), y = cdr (y))
3726 root 1.2 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3727 root 1.1
3728     SCHEME_V->code = cdr (SCHEME_V->code);
3729     SCHEME_V->args = NIL;
3730     s_goto (OP_BEGIN);
3731    
3732     case OP_COND0: /* cond */
3733     if (!is_pair (SCHEME_V->code))
3734 root 1.2 Error_0 ("syntax error in cond");
3735 root 1.1
3736     s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3737     SCHEME_V->code = caar (SCHEME_V->code);
3738     s_goto (OP_EVAL);
3739    
3740     case OP_COND1: /* cond */
3741     if (is_true (SCHEME_V->value))
3742     {
3743     if ((SCHEME_V->code = cdar (SCHEME_V->code)) == NIL)
3744 root 1.2 s_return (SCHEME_V->value);
3745 root 1.1
3746     if (car (SCHEME_V->code) == SCHEME_V->FEED_TO)
3747     {
3748     if (!is_pair (cdr (SCHEME_V->code)))
3749 root 1.2 Error_0 ("syntax error in cond");
3750 root 1.1
3751     x = cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL));
3752     SCHEME_V->code = cons (cadr (SCHEME_V->code), cons (x, NIL));
3753     s_goto (OP_EVAL);
3754     }
3755    
3756     s_goto (OP_BEGIN);
3757     }
3758     else
3759     {
3760     if ((SCHEME_V->code = cdr (SCHEME_V->code)) == NIL)
3761 root 1.2 s_return (NIL);
3762 root 1.1 else
3763     {
3764     s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3765     SCHEME_V->code = caar (SCHEME_V->code);
3766     s_goto (OP_EVAL);
3767     }
3768     }
3769    
3770     case OP_DELAY: /* delay */
3771     x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3772     set_typeflag (x, T_PROMISE);
3773     s_return (x);
3774    
3775     case OP_AND0: /* and */
3776     if (SCHEME_V->code == NIL)
3777 root 1.2 s_return (S_T);
3778 root 1.1
3779     s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3780     SCHEME_V->code = car (SCHEME_V->code);
3781     s_goto (OP_EVAL);
3782    
3783     case OP_AND1: /* and */
3784     if (is_false (SCHEME_V->value))
3785 root 1.2 s_return (SCHEME_V->value);
3786 root 1.1 else if (SCHEME_V->code == NIL)
3787 root 1.2 s_return (SCHEME_V->value);
3788 root 1.1 else
3789     {
3790     s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3791     SCHEME_V->code = car (SCHEME_V->code);
3792     s_goto (OP_EVAL);
3793     }
3794    
3795     case OP_OR0: /* or */
3796     if (SCHEME_V->code == NIL)
3797 root 1.2 s_return (S_F);
3798 root 1.1
3799     s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3800     SCHEME_V->code = car (SCHEME_V->code);
3801     s_goto (OP_EVAL);
3802    
3803     case OP_OR1: /* or */
3804     if (is_true (SCHEME_V->value))
3805 root 1.2 s_return (SCHEME_V->value);
3806 root 1.1 else if (SCHEME_V->code == NIL)
3807 root 1.2 s_return (SCHEME_V->value);
3808 root 1.1 else
3809     {
3810     s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3811     SCHEME_V->code = car (SCHEME_V->code);
3812     s_goto (OP_EVAL);
3813     }
3814    
3815     case OP_C0STREAM: /* cons-stream */
3816     s_save (SCHEME_A_ OP_C1STREAM, NIL, cdr (SCHEME_V->code));
3817     SCHEME_V->code = car (SCHEME_V->code);
3818     s_goto (OP_EVAL);
3819    
3820     case OP_C1STREAM: /* cons-stream */
3821 root 1.16 SCHEME_V->args = SCHEME_V->value; /* save SCHEME_V->value to register args for gc */
3822 root 1.1 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3823     set_typeflag (x, T_PROMISE);
3824 root 1.16 s_return (cons (args, x));
3825 root 1.1
3826     case OP_MACRO0: /* macro */
3827     if (is_pair (car (SCHEME_V->code)))
3828     {
3829     x = caar (SCHEME_V->code);
3830     SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3831     }
3832     else
3833     {
3834     x = car (SCHEME_V->code);
3835     SCHEME_V->code = cadr (SCHEME_V->code);
3836     }
3837    
3838     if (!is_symbol (x))
3839 root 1.2 Error_0 ("variable is not a symbol");
3840 root 1.1
3841     s_save (SCHEME_A_ OP_MACRO1, NIL, x);
3842     s_goto (OP_EVAL);
3843    
3844     case OP_MACRO1: /* macro */
3845     set_typeflag (SCHEME_V->value, T_MACRO);
3846     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3847    
3848     if (x != NIL)
3849 root 1.2 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3850 root 1.1 else
3851 root 1.2 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3852 root 1.1
3853     s_return (SCHEME_V->code);
3854    
3855     case OP_CASE0: /* case */
3856     s_save (SCHEME_A_ OP_CASE1, NIL, cdr (SCHEME_V->code));
3857     SCHEME_V->code = car (SCHEME_V->code);
3858     s_goto (OP_EVAL);
3859    
3860     case OP_CASE1: /* case */
3861     for (x = SCHEME_V->code; x != NIL; x = cdr (x))
3862     {
3863     if (!is_pair (y = caar (x)))
3864 root 1.2 break;
3865 root 1.1
3866     for (; y != NIL; y = cdr (y))
3867 root 1.16 if (eqv (car (y), SCHEME_V->value))
3868 root 1.2 break;
3869 root 1.1
3870     if (y != NIL)
3871 root 1.2 break;
3872 root 1.1 }
3873    
3874     if (x != NIL)
3875     {
3876     if (is_pair (caar (x)))
3877     {
3878     SCHEME_V->code = cdar (x);
3879     s_goto (OP_BEGIN);
3880     }
3881     else /* else */
3882     {
3883     s_save (SCHEME_A_ OP_CASE2, NIL, cdar (x));
3884     SCHEME_V->code = caar (x);
3885     s_goto (OP_EVAL);
3886     }
3887     }
3888     else
3889 root 1.2 s_return (NIL);
3890 root 1.1
3891     case OP_CASE2: /* case */
3892     if (is_true (SCHEME_V->value))
3893 root 1.2 s_goto (OP_BEGIN);
3894 root 1.1 else
3895 root 1.2 s_return (NIL);
3896 root 1.1
3897     case OP_PAPPLY: /* apply */
3898 root 1.16 SCHEME_V->code = car (args);
3899     SCHEME_V->args = list_star (SCHEME_A_ cdr (args));
3900     /*SCHEME_V->args = cadr(args); */
3901 root 1.1 s_goto (OP_APPLY);
3902    
3903     case OP_PEVAL: /* eval */
3904 root 1.16 if (cdr (args) != NIL)
3905     SCHEME_V->envir = cadr (args);
3906 root 1.1
3907 root 1.16 SCHEME_V->code = car (args);
3908 root 1.1 s_goto (OP_EVAL);
3909    
3910     case OP_CONTINUATION: /* call-with-current-continuation */
3911 root 1.16 SCHEME_V->code = car (args);
3912 root 1.7 SCHEME_V->args = cons (mk_continuation (SCHEME_A_ ss_get_cont (SCHEME_A)), NIL);
3913 root 1.1 s_goto (OP_APPLY);
3914     }
3915    
3916 root 1.14 abort ();
3917 root 1.1 }
3918    
3919     static pointer
3920     opexe_2 (SCHEME_P_ enum scheme_opcodes op)
3921     {
3922 root 1.16 pointer args = SCHEME_V->args;
3923     pointer x = car (args);
3924 root 1.1 num v;
3925    
3926     #if USE_MATH
3927     RVALUE dd;
3928     #endif
3929    
3930     switch (op)
3931     {
3932     #if USE_MATH
3933     case OP_INEX2EX: /* inexact->exact */
3934     if (num_is_integer (x))
3935 root 1.2 s_return (x);
3936 root 1.16 else if (modf (rvalue_unchecked (x), &dd) == 0)
3937 root 1.2 s_return (mk_integer (SCHEME_A_ ivalue (x)));
3938 root 1.1 else
3939 root 1.2 Error_1 ("inexact->exact: not integral:", x);
3940 root 1.1
3941 root 1.16 case OP_EXP: s_return (mk_real (SCHEME_A_ exp (rvalue (x))));
3942     case OP_LOG: s_return (mk_real (SCHEME_A_ log (rvalue (x))));
3943     case OP_SIN: s_return (mk_real (SCHEME_A_ sin (rvalue (x))));
3944     case OP_COS: s_return (mk_real (SCHEME_A_ cos (rvalue (x))));
3945     case OP_TAN: s_return (mk_real (SCHEME_A_ tan (rvalue (x))));
3946     case OP_ASIN: s_return (mk_real (SCHEME_A_ asin (rvalue (x))));
3947     case OP_ACOS: s_return (mk_real (SCHEME_A_ acos (rvalue (x))));
3948 root 1.1
3949     case OP_ATAN:
3950 root 1.16 if (cdr (args) == NIL)
3951 root 1.2 s_return (mk_real (SCHEME_A_ atan (rvalue (x))));
3952 root 1.1 else
3953     {
3954 root 1.16 pointer y = cadr (args);
3955 root 1.1 s_return (mk_real (SCHEME_A_ atan2 (rvalue (x), rvalue (y))));
3956     }
3957    
3958     case OP_SQRT:
3959     s_return (mk_real (SCHEME_A_ sqrt (rvalue (x))));
3960    
3961     case OP_EXPT:
3962     {
3963     RVALUE result;
3964     int real_result = 1;
3965 root 1.16 pointer y = cadr (args);
3966 root 1.1
3967     if (num_is_integer (x) && num_is_integer (y))
3968     real_result = 0;
3969    
3970     /* This 'if' is an R5RS compatibility fix. */
3971     /* NOTE: Remove this 'if' fix for R6RS. */
3972     if (rvalue (x) == 0 && rvalue (y) < 0)
3973 root 1.16 result = 0;
3974 root 1.1 else
3975 root 1.2 result = pow (rvalue (x), rvalue (y));
3976 root 1.1
3977     /* Before returning integer result make sure we can. */
3978     /* If the test fails, result is too big for integer. */
3979     if (!real_result)
3980     {
3981 root 1.16 long result_as_long = result;
3982 root 1.1
3983     if (result != (RVALUE) result_as_long)
3984     real_result = 1;
3985     }
3986    
3987     if (real_result)
3988 root 1.2 s_return (mk_real (SCHEME_A_ result));
3989 root 1.1 else
3990 root 1.2 s_return (mk_integer (SCHEME_A_ result));
3991 root 1.1 }
3992    
3993 root 1.16 case OP_FLOOR: s_return (mk_real (SCHEME_A_ floor (rvalue (x))));
3994     case OP_CEILING: s_return (mk_real (SCHEME_A_ ceil (rvalue (x))));
3995 root 1.1
3996     case OP_TRUNCATE:
3997     {
3998     RVALUE rvalue_of_x;
3999    
4000     rvalue_of_x = rvalue (x);
4001    
4002     if (rvalue_of_x > 0)
4003 root 1.2 s_return (mk_real (SCHEME_A_ floor (rvalue_of_x)));
4004 root 1.1 else
4005 root 1.2 s_return (mk_real (SCHEME_A_ ceil (rvalue_of_x)));
4006 root 1.1 }
4007    
4008     case OP_ROUND:
4009     if (num_is_integer (x))
4010     s_return (x);
4011    
4012     s_return (mk_real (SCHEME_A_ round_per_R5RS (rvalue (x))));
4013     #endif
4014    
4015     case OP_ADD: /* + */
4016     v = num_zero;
4017    
4018 root 1.16 for (x = args; x != NIL; x = cdr (x))
4019 root 1.13 v = num_op ('+', v, nvalue (car (x)));
4020 root 1.1
4021     s_return (mk_number (SCHEME_A_ v));
4022    
4023     case OP_MUL: /* * */
4024     v = num_one;
4025    
4026 root 1.16 for (x = args; x != NIL; x = cdr (x))
4027 root 1.13 v = num_op ('+', v, nvalue (car (x)));
4028 root 1.1
4029     s_return (mk_number (SCHEME_A_ v));
4030    
4031     case OP_SUB: /* - */
4032 root 1.16 if (cdr (args) == NIL)
4033 root 1.1 {
4034 root 1.16 x = args;
4035 root 1.1 v = num_zero;
4036     }
4037     else
4038     {
4039 root 1.16 x = cdr (args);
4040     v = nvalue (car (args));
4041 root 1.1 }
4042    
4043     for (; x != NIL; x = cdr (x))
4044 root 1.13 v = num_op ('+', v, nvalue (car (x)));
4045 root 1.1
4046     s_return (mk_number (SCHEME_A_ v));
4047    
4048     case OP_DIV: /* / */
4049 root 1.16 if (cdr (args) == NIL)
4050 root 1.1 {
4051 root 1.16 x = args;
4052 root 1.1 v = num_one;
4053     }
4054     else
4055     {
4056 root 1.16 x = cdr (args);
4057     v = nvalue (car (args));
4058 root 1.1 }
4059    
4060     for (; x != NIL; x = cdr (x))
4061     {
4062     if (!is_zero_rvalue (rvalue (car (x))))
4063     v = num_div (v, nvalue (car (x)));
4064     else
4065     Error_0 ("/: division by zero");
4066     }
4067    
4068     s_return (mk_number (SCHEME_A_ v));
4069    
4070     case OP_INTDIV: /* quotient */
4071 root 1.16 if (cdr (args) == NIL)
4072 root 1.1 {
4073 root 1.16 x = args;
4074 root 1.1 v = num_one;
4075     }
4076     else
4077     {
4078 root 1.16 x = cdr (args);
4079     v = nvalue (car (args));
4080 root 1.1 }
4081    
4082     for (; x != NIL; x = cdr (x))
4083     {
4084     if (ivalue (car (x)) != 0)
4085 root 1.13 v = num_op ('/', v, nvalue (car (x)));
4086 root 1.1 else
4087     Error_0 ("quotient: division by zero");
4088     }
4089    
4090     s_return (mk_number (SCHEME_A_ v));
4091    
4092     case OP_REM: /* remainder */
4093 root 1.16 v = nvalue (x);
4094 root 1.1
4095 root 1.16 if (ivalue (cadr (args)) != 0)
4096     v = num_rem (v, nvalue (cadr (args)));
4097 root 1.1 else
4098     Error_0 ("remainder: division by zero");
4099    
4100     s_return (mk_number (SCHEME_A_ v));
4101    
4102     case OP_MOD: /* modulo */
4103 root 1.16 v = nvalue (x);
4104 root 1.1
4105 root 1.16 if (ivalue (cadr (args)) != 0)
4106     v = num_mod (v, nvalue (cadr (args)));
4107 root 1.1 else
4108     Error_0 ("modulo: division by zero");
4109    
4110     s_return (mk_number (SCHEME_A_ v));
4111    
4112     case OP_CAR: /* car */
4113 root 1.16 s_return (caar (args));
4114 root 1.1
4115     case OP_CDR: /* cdr */
4116 root 1.16 s_return (cdar (args));
4117 root 1.1
4118     case OP_CONS: /* cons */
4119 root 1.16 set_cdr (args, cadr (args));
4120     s_return (args);
4121 root 1.1
4122     case OP_SETCAR: /* set-car! */
4123 root 1.16 if (!is_immutable (x))
4124 root 1.1 {
4125 root 1.16 set_car (x, cadr (args));
4126     s_return (car (args));
4127 root 1.1 }
4128     else
4129     Error_0 ("set-car!: unable to alter immutable pair");
4130    
4131     case OP_SETCDR: /* set-cdr! */
4132 root 1.16 if (!is_immutable (x))
4133 root 1.1 {
4134 root 1.16 set_cdr (x, cadr (args));
4135     s_return (car (args));
4136 root 1.1 }
4137     else
4138     Error_0 ("set-cdr!: unable to alter immutable pair");
4139    
4140     case OP_CHAR2INT: /* char->integer */
4141 root 1.16 s_return (mk_integer (SCHEME_A_ ivalue (x)));
4142 root 1.1
4143     case OP_INT2CHAR: /* integer->char */
4144 root 1.16 s_return (mk_character (SCHEME_A_ ivalue (x)));
4145 root 1.1
4146     case OP_CHARUPCASE:
4147     {
4148 root 1.16 unsigned char c = ivalue (x);
4149 root 1.1 c = toupper (c);
4150 root 1.2 s_return (mk_character (SCHEME_A_ c));
4151 root 1.1 }
4152    
4153     case OP_CHARDNCASE:
4154     {
4155 root 1.16 unsigned char c = ivalue (x);
4156 root 1.1 c = tolower (c);
4157 root 1.2 s_return (mk_character (SCHEME_A_ c));
4158 root 1.1 }
4159    
4160     case OP_STR2SYM: /* string->symbol */
4161 root 1.16 s_return (mk_symbol (SCHEME_A_ strvalue (x)));
4162 root 1.1
4163     case OP_STR2ATOM: /* string->atom */
4164     {
4165 root 1.16 char *s = strvalue (x);
4166 root 1.1 long pf = 0;
4167    
4168 root 1.16 if (cdr (args) != NIL)
4169 root 1.1 {
4170 root 1.16 /* we know cadr(args) is a natural number */
4171 root 1.1 /* see if it is 2, 8, 10, or 16, or error */
4172 root 1.16 pf = ivalue_unchecked (cadr (args));
4173 root 1.1
4174     if (pf == 16 || pf == 10 || pf == 8 || pf == 2)
4175     {
4176     /* base is OK */
4177     }
4178     else
4179 root 1.2 pf = -1;
4180 root 1.1 }
4181    
4182     if (pf < 0)
4183 root 1.16 Error_1 ("string->atom: bad base:", cadr (args));
4184 root 1.1 else if (*s == '#') /* no use of base! */
4185 root 1.2 s_return (mk_sharp_const (SCHEME_A_ s + 1));
4186 root 1.1 else
4187     {
4188     if (pf == 0 || pf == 10)
4189 root 1.2 s_return (mk_atom (SCHEME_A_ s));
4190 root 1.1 else
4191     {
4192     char *ep;
4193     long iv = strtol (s, &ep, (int) pf);
4194    
4195     if (*ep == 0)
4196 root 1.2 s_return (mk_integer (SCHEME_A_ iv));
4197 root 1.1 else
4198 root 1.2 s_return (S_F);
4199 root 1.1 }
4200     }
4201     }
4202    
4203     case OP_SYM2STR: /* symbol->string */
4204 root 1.16 x = mk_string (SCHEME_A_ symname (x));
4205 root 1.1 setimmutable (x);
4206     s_return (x);
4207    
4208     case OP_ATOM2STR: /* atom->string */
4209     {
4210     long pf = 0;
4211    
4212 root 1.16 if (cdr (args) != NIL)
4213 root 1.1 {
4214 root 1.16 /* we know cadr(args) is a natural number */
4215 root 1.1 /* see if it is 2, 8, 10, or 16, or error */
4216 root 1.16 pf = ivalue_unchecked (cadr (args));
4217 root 1.1
4218     if (is_number (x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2))
4219     {
4220     /* base is OK */
4221     }
4222     else
4223 root 1.2 pf = -1;
4224 root 1.1 }
4225    
4226     if (pf < 0)
4227 root 1.16 Error_1 ("atom->string: bad base:", cadr (args));
4228 root 1.1 else if (is_number (x) || is_character (x) || is_string (x) || is_symbol (x))
4229     {
4230     char *p;
4231     int len;
4232    
4233 root 1.2 atom2str (SCHEME_A_ x, pf, &p, &len);
4234 root 1.1 s_return (mk_counted_string (SCHEME_A_ p, len));
4235     }
4236     else
4237 root 1.2 Error_1 ("atom->string: not an atom:", x);
4238 root 1.1 }
4239    
4240     case OP_MKSTRING: /* make-string */
4241     {
4242     int fill = ' ';
4243     int len;
4244    
4245 root 1.16 len = ivalue (x);
4246 root 1.1
4247 root 1.16 if (cdr (args) != NIL)
4248     fill = charvalue (cadr (args));
4249 root 1.1
4250 root 1.17 s_return (mk_empty_string (SCHEME_A_ len, fill));
4251 root 1.1 }
4252    
4253     case OP_STRLEN: /* string-length */
4254 root 1.16 s_return (mk_integer (SCHEME_A_ strlength (x)));
4255 root 1.1
4256     case OP_STRREF: /* string-ref */
4257     {
4258     char *str;
4259     int index;
4260    
4261 root 1.16 str = strvalue (x);
4262 root 1.1
4263 root 1.16 index = ivalue (cadr (args));
4264 root 1.1
4265 root 1.16 if (index >= strlength (x))
4266     Error_1 ("string-ref: out of bounds:", cadr (args));
4267 root 1.1
4268 root 1.17 s_return (mk_character (SCHEME_A_ ((unsigned char *)str)[index]));
4269 root 1.1 }
4270    
4271     case OP_STRSET: /* string-set! */
4272     {
4273     char *str;
4274     int index;
4275     int c;
4276    
4277 root 1.16 if (is_immutable (x))
4278     Error_1 ("string-set!: unable to alter immutable string:", x);
4279 root 1.1
4280 root 1.16 str = strvalue (x);
4281 root 1.1
4282 root 1.16 index = ivalue (cadr (args));
4283 root 1.1
4284 root 1.16 if (index >= strlength (x))
4285     Error_1 ("string-set!: out of bounds:", cadr (args));
4286 root 1.1
4287 root 1.16 c = charvalue (caddr (args));
4288 root 1.1
4289 root 1.17 str[index] = c;
4290 root 1.16 s_return (car (args));
4291 root 1.1 }
4292    
4293     case OP_STRAPPEND: /* string-append */
4294     {
4295     /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4296     int len = 0;
4297     pointer newstr;
4298     char *pos;
4299    
4300     /* compute needed length for new string */
4301 root 1.16 for (x = args; x != NIL; x = cdr (x))
4302 root 1.2 len += strlength (car (x));
4303 root 1.1
4304     newstr = mk_empty_string (SCHEME_A_ len, ' ');
4305    
4306     /* store the contents of the argument strings into the new string */
4307 root 1.16 for (pos = strvalue (newstr), x = args; x != NIL; pos += strlength (car (x)), x = cdr (x))
4308 root 1.2 memcpy (pos, strvalue (car (x)), strlength (car (x)));
4309 root 1.1
4310     s_return (newstr);
4311     }
4312    
4313     case OP_SUBSTR: /* substring */
4314     {
4315     char *str;
4316     int index0;
4317     int index1;
4318     int len;
4319    
4320 root 1.16 str = strvalue (x);
4321 root 1.1
4322 root 1.16 index0 = ivalue (cadr (args));
4323 root 1.1
4324 root 1.16 if (index0 > strlength (x))
4325     Error_1 ("substring: start out of bounds:", cadr (args));
4326 root 1.1
4327 root 1.16 if (cddr (args) != NIL)
4328 root 1.1 {
4329 root 1.16 index1 = ivalue (caddr (args));
4330 root 1.1
4331 root 1.16 if (index1 > strlength (x) || index1 < index0)
4332     Error_1 ("substring: end out of bounds:", caddr (args));
4333 root 1.1 }
4334     else
4335 root 1.16 index1 = strlength (x);
4336 root 1.1
4337     len = index1 - index0;
4338     x = mk_empty_string (SCHEME_A_ len, ' ');
4339     memcpy (strvalue (x), str + index0, len);
4340     strvalue (x)[len] = 0;
4341    
4342     s_return (x);
4343     }
4344    
4345     case OP_VECTOR: /* vector */
4346     {
4347     int i;
4348     pointer vec;
4349 root 1.16 int len = list_length (SCHEME_A_ args);
4350 root 1.1
4351     if (len < 0)
4352 root 1.16 Error_1 ("vector: not a proper list:", args);
4353 root 1.1
4354     vec = mk_vector (SCHEME_A_ len);
4355    
4356     #if USE_ERROR_CHECKING
4357     if (SCHEME_V->no_memory)
4358     s_return (S_SINK);
4359     #endif
4360    
4361 root 1.16 for (x = args, i = 0; is_pair (x); x = cdr (x), i++)
4362 root 1.1 set_vector_elem (vec, i, car (x));
4363    
4364     s_return (vec);
4365     }
4366    
4367     case OP_MKVECTOR: /* make-vector */
4368     {
4369     pointer fill = NIL;
4370     int len;
4371     pointer vec;
4372    
4373 root 1.16 len = ivalue (x);
4374 root 1.1
4375 root 1.16 if (cdr (args) != NIL)
4376     fill = cadr (args);
4377 root 1.1
4378     vec = mk_vector (SCHEME_A_ len);
4379    
4380     #if USE_ERROR_CHECKING
4381     if (SCHEME_V->no_memory)
4382     s_return (S_SINK);
4383     #endif
4384    
4385     if (fill != NIL)
4386     fill_vector (vec, fill);
4387    
4388     s_return (vec);
4389     }
4390    
4391     case OP_VECLEN: /* vector-length */
4392 root 1.16 s_return (mk_integer (SCHEME_A_ veclength (x)));
4393 root 1.1
4394     case OP_VECREF: /* vector-ref */
4395     {
4396     int index;
4397    
4398 root 1.16 index = ivalue (cadr (args));
4399 root 1.1
4400 root 1.16 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4401     Error_1 ("vector-ref: out of bounds:", cadr (args));
4402 root 1.1
4403 root 1.16 s_return (vector_elem (x, index));
4404 root 1.1 }
4405    
4406     case OP_VECSET: /* vector-set! */
4407     {
4408     int index;
4409    
4410 root 1.16 if (is_immutable (x))
4411     Error_1 ("vector-set!: unable to alter immutable vector:", x);
4412 root 1.1
4413 root 1.16 index = ivalue (cadr (args));
4414 root 1.1
4415 root 1.16 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4416     Error_1 ("vector-set!: out of bounds:", cadr (args));
4417 root 1.1
4418 root 1.16 set_vector_elem (x, index, caddr (args));
4419     s_return (x);
4420 root 1.1 }
4421     }
4422    
4423     return S_T;
4424     }
4425    
4426     INTERFACE int
4427     is_list (SCHEME_P_ pointer a)
4428     {
4429     return list_length (SCHEME_A_ a) >= 0;
4430     }
4431    
4432     /* Result is:
4433     proper list: length
4434     circular list: -1
4435     not even a pair: -2
4436     dotted list: -2 minus length before dot
4437     */
4438     INTERFACE int
4439     list_length (SCHEME_P_ pointer a)
4440     {
4441     int i = 0;
4442     pointer slow, fast;
4443    
4444     slow = fast = a;
4445    
4446     while (1)
4447     {
4448     if (fast == NIL)
4449     return i;
4450    
4451     if (!is_pair (fast))
4452     return -2 - i;
4453    
4454     fast = cdr (fast);
4455     ++i;
4456    
4457     if (fast == NIL)
4458     return i;
4459    
4460     if (!is_pair (fast))
4461     return -2 - i;
4462    
4463     ++i;
4464     fast = cdr (fast);
4465    
4466     /* Safe because we would have already returned if `fast'
4467     encountered a non-pair. */
4468     slow = cdr (slow);
4469    
4470     if (fast == slow)
4471     {
4472     /* the fast pointer has looped back around and caught up
4473     with the slow pointer, hence the structure is circular,
4474     not of finite length, and therefore not a list */
4475     return -1;
4476     }
4477     }
4478     }
4479    
4480     static pointer
4481 root 1.14 opexe_r (SCHEME_P_ enum scheme_opcodes op)
4482 root 1.1 {
4483 root 1.14 pointer x = SCHEME_V->args;
4484 root 1.1
4485 root 1.14 for (;;)
4486 root 1.1 {
4487 root 1.14 num v = nvalue (car (x));
4488     x = cdr (x);
4489 root 1.1
4490 root 1.14 if (x == NIL)
4491     break;
4492 root 1.1
4493 root 1.14 int r = num_cmp (v, nvalue (car (x)));
4494 root 1.1
4495 root 1.14 switch (op)
4496     {
4497     case OP_NUMEQ: r = r == 0; break;
4498     case OP_LESS: r = r < 0; break;
4499     case OP_GRE: r = r > 0; break;
4500     case OP_LEQ: r = r <= 0; break;
4501     case OP_GEQ: r = r >= 0; break;
4502     }
4503 root 1.1
4504 root 1.14 if (!r)
4505     s_return (S_F);
4506     }
4507 root 1.1
4508 root 1.14 s_return (S_T);
4509     }
4510 root 1.1
4511 root 1.14 static pointer
4512     opexe_3 (SCHEME_P_ enum scheme_opcodes op)
4513     {
4514 root 1.16 pointer args = SCHEME_V->args;
4515     pointer a = car (args);
4516     pointer d = cdr (args);
4517 root 1.14 int r;
4518 root 1.1
4519 root 1.14 switch (op)
4520     {
4521 root 1.15 case OP_NOT: /* not */ r = is_false (a) ; break;
4522     case OP_BOOLP: /* boolean? */ r = a == S_F || a == S_T; break;
4523     case OP_EOFOBJP: /* eof-object? */ r = a == S_EOF ; break;
4524     case OP_NULLP: /* null? */ r = a == NIL ; break;
4525     case OP_SYMBOLP: /* symbol? */ r = is_symbol (a) ; break;
4526     case OP_NUMBERP: /* number? */ r = is_number (a) ; break;
4527     case OP_STRINGP: /* string? */ r = is_string (a) ; break;
4528     case OP_INTEGERP: /* integer? */ r = is_integer (a) ; break;
4529     case OP_REALP: /* real? */ r = is_number (a) ; break; /* all numbers are real */
4530     case OP_CHARP: /* char? */ r = is_character (a) ; break;
4531 root 1.14
4532 root 1.1 #if USE_CHAR_CLASSIFIERS
4533 root 1.15 case OP_CHARAP: /* char-alphabetic? */ r = Cisalpha (ivalue (a)); break;
4534     case OP_CHARNP: /* char-numeric? */ r = Cisdigit (ivalue (a)); break;
4535     case OP_CHARWP: /* char-whitespace? */ r = Cisspace (ivalue (a)); break;
4536     case OP_CHARUP: /* char-upper-case? */ r = Cisupper (ivalue (a)); break;
4537     case OP_CHARLP: /* char-lower-case? */ r = Cislower (ivalue (a)); break;
4538 root 1.1 #endif
4539 root 1.14
4540 root 1.1 #if USE_PORTS
4541 root 1.15 case OP_PORTP: /* port? */ r = is_port (a) ; break;
4542     case OP_INPORTP: /* input-port? */ r = is_inport (a) ; break;
4543     case OP_OUTPORTP: /* output-port? */ r = is_outport (a); break;
4544 root 1.1 #endif
4545    
4546     case OP_PROCP: /* procedure? */
4547    
4548 root 1.14 /*--
4549     * continuation should be procedure by the example
4550     * (call-with-current-continuation procedure?) ==> #t
4551     * in R^3 report sec. 6.9
4552     */
4553     r = is_proc (a) || is_closure (a) || is_continuation (a) || is_foreign (a);
4554     break;
4555 root 1.1
4556 root 1.15 case OP_PAIRP: /* pair? */ r = is_pair (a) ; break;
4557     case OP_LISTP: /* list? */ r = list_length (SCHEME_A_ a) >= 0; break;
4558     case OP_ENVP: /* environment? */ r = is_environment (a) ; break;
4559     case OP_VECTORP: /* vector? */ r = is_vector (a) ; break;
4560 root 1.16 case OP_EQ: /* eq? */ r = a == cadr (args) ; break;
4561     case OP_EQV: /* eqv? */ r = eqv (a, cadr (args)) ; break;
4562 root 1.1 }
4563    
4564 root 1.14 s_retbool (r);
4565 root 1.1 }
4566    
4567     static pointer
4568     opexe_4 (SCHEME_P_ enum scheme_opcodes op)
4569     {
4570 root 1.16 pointer args = SCHEME_V->args;
4571     pointer a = car (args);
4572 root 1.1 pointer x, y;
4573    
4574     switch (op)
4575     {
4576     case OP_FORCE: /* force */
4577 root 1.16 SCHEME_V->code = a;
4578 root 1.1
4579     if (is_promise (SCHEME_V->code))
4580     {
4581     /* Should change type to closure here */
4582     s_save (SCHEME_A_ OP_SAVE_FORCED, NIL, SCHEME_V->code);
4583     SCHEME_V->args = NIL;
4584     s_goto (OP_APPLY);
4585     }
4586     else
4587 root 1.2 s_return (SCHEME_V->code);
4588 root 1.1
4589     case OP_SAVE_FORCED: /* Save forced value replacing promise */
4590     memcpy (SCHEME_V->code, SCHEME_V->value, sizeof (struct cell));
4591     s_return (SCHEME_V->value);
4592    
4593     #if USE_PORTS
4594    
4595     case OP_WRITE: /* write */
4596     case OP_DISPLAY: /* display */
4597     case OP_WRITE_CHAR: /* write-char */
4598     if (is_pair (cdr (SCHEME_V->args)))
4599     {
4600     if (cadr (SCHEME_V->args) != SCHEME_V->outport)
4601     {
4602     x = cons (SCHEME_V->outport, NIL);
4603     s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4604     SCHEME_V->outport = cadr (SCHEME_V->args);
4605     }
4606     }
4607    
4608 root 1.16 SCHEME_V->args = a;
4609 root 1.1
4610     if (op == OP_WRITE)
4611     SCHEME_V->print_flag = 1;
4612     else
4613     SCHEME_V->print_flag = 0;
4614    
4615     s_goto (OP_P0LIST);
4616    
4617     case OP_NEWLINE: /* newline */
4618 root 1.16 if (is_pair (args))
4619 root 1.1 {
4620 root 1.16 if (a != SCHEME_V->outport)
4621 root 1.1 {
4622     x = cons (SCHEME_V->outport, NIL);
4623     s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4624 root 1.16 SCHEME_V->outport = a;
4625 root 1.1 }
4626     }
4627    
4628     putstr (SCHEME_A_ "\n");
4629     s_return (S_T);
4630     #endif
4631    
4632     case OP_ERR0: /* error */
4633     SCHEME_V->retcode = -1;
4634    
4635 root 1.16 if (!is_string (a))
4636 root 1.1 {
4637 root 1.16 args = cons (mk_string (SCHEME_A_ " -- "), args);
4638     setimmutable (car (args));
4639 root 1.1 }
4640    
4641     putstr (SCHEME_A_ "Error: ");
4642 root 1.16 putstr (SCHEME_A_ strvalue (car (args)));
4643     SCHEME_V->args = cdr (args);
4644 root 1.1 s_goto (OP_ERR1);
4645    
4646     case OP_ERR1: /* error */
4647     putstr (SCHEME_A_ " ");
4648    
4649 root 1.16 if (args != NIL)
4650 root 1.1 {
4651 root 1.16 s_save (SCHEME_A_ OP_ERR1, cdr (args), NIL);
4652     SCHEME_V->args = a;
4653 root 1.1 SCHEME_V->print_flag = 1;
4654     s_goto (OP_P0LIST);
4655     }
4656     else
4657     {
4658     putstr (SCHEME_A_ "\n");
4659    
4660     if (SCHEME_V->interactive_repl)
4661 root 1.2 s_goto (OP_T0LVL);
4662 root 1.1 else
4663 root 1.2 return NIL;
4664 root 1.1 }
4665    
4666     case OP_REVERSE: /* reverse */
4667 root 1.16 s_return (reverse (SCHEME_A_ a));
4668 root 1.1
4669     case OP_LIST_STAR: /* list* */
4670     s_return (list_star (SCHEME_A_ SCHEME_V->args));
4671    
4672     case OP_APPEND: /* append */
4673     x = NIL;
4674 root 1.16 y = args;
4675 root 1.1
4676     if (y == x)
4677     s_return (x);
4678    
4679     /* cdr() in the while condition is not a typo. If car() */
4680     /* is used (append '() 'a) will return the wrong result. */
4681     while (cdr (y) != NIL)
4682     {
4683     x = revappend (SCHEME_A_ x, car (y));
4684     y = cdr (y);
4685    
4686     if (x == S_F)
4687     Error_0 ("non-list argument to append");
4688     }
4689    
4690     s_return (reverse_in_place (SCHEME_A_ car (y), x));
4691    
4692     #if USE_PLIST
4693    
4694     case OP_PUT: /* put */
4695 root 1.16 if (!hasprop (a) || !hasprop (cadr (args)))
4696 root 1.2 Error_0 ("illegal use of put");
4697 root 1.1
4698 root 1.16 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4699 root 1.1 {
4700     if (caar (x) == y)
4701 root 1.2 break;
4702 root 1.1 }
4703    
4704     if (x != NIL)
4705 root 1.16 cdar (x) = caddr (args);
4706 root 1.1 else
4707 root 1.16 symprop (a) = cons (cons (y, caddr (args)), symprop (a));
4708 root 1.1
4709     s_return (S_T);
4710    
4711     case OP_GET: /* get */
4712 root 1.16 if (!hasprop (a) || !hasprop (cadr (args)))
4713 root 1.1 Error_0 ("illegal use of get");
4714    
4715 root 1.16 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4716 root 1.1 if (caar (x) == y)
4717     break;
4718    
4719     if (x != NIL)
4720     s_return (cdar (x));
4721     else
4722     s_return (NIL);
4723    
4724     #endif /* USE_PLIST */
4725    
4726     case OP_QUIT: /* quit */
4727 root 1.16 if (is_pair (args))
4728     SCHEME_V->retcode = ivalue (a);
4729 root 1.1
4730     return NIL;
4731    
4732     case OP_GC: /* gc */
4733     gc (SCHEME_A_ NIL, NIL);
4734     s_return (S_T);
4735    
4736     case OP_GCVERB: /* gc-verbose */
4737     {
4738     int was = SCHEME_V->gc_verbose;
4739    
4740 root 1.16 SCHEME_V->gc_verbose = (a != S_F);
4741 root 1.1 s_retbool (was);
4742     }
4743    
4744     case OP_NEWSEGMENT: /* new-segment */
4745 root 1.16 if (!is_pair (args) || !is_number (a))
4746 root 1.1 Error_0 ("new-segment: argument must be a number");
4747    
4748 root 1.16 alloc_cellseg (SCHEME_A_ (int)ivalue (a));
4749 root 1.1
4750     s_return (S_T);
4751    
4752     case OP_OBLIST: /* oblist */
4753     s_return (oblist_all_symbols (SCHEME_A));
4754    
4755     #if USE_PORTS
4756    
4757     case OP_CURR_INPORT: /* current-input-port */
4758     s_return (SCHEME_V->inport);
4759    
4760     case OP_CURR_OUTPORT: /* current-output-port */
4761     s_return (SCHEME_V->outport);
4762    
4763     case OP_OPEN_INFILE: /* open-input-file */
4764     case OP_OPEN_OUTFILE: /* open-output-file */
4765     case OP_OPEN_INOUTFILE: /* open-input-output-file */
4766     {
4767     int prop = 0;
4768     pointer p;
4769    
4770     switch (op)
4771     {
4772     case OP_OPEN_INFILE:
4773     prop = port_input;
4774     break;
4775    
4776     case OP_OPEN_OUTFILE:
4777     prop = port_output;
4778     break;
4779    
4780     case OP_OPEN_INOUTFILE:
4781     prop = port_input | port_output;
4782     break;
4783     }
4784    
4785 root 1.16 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
4786 root 1.1
4787     if (p == NIL)
4788 root 1.2 s_return (S_F);
4789 root 1.1
4790     s_return (p);
4791     }
4792    
4793     # if USE_STRING_PORTS
4794    
4795     case OP_OPEN_INSTRING: /* open-input-string */
4796     case OP_OPEN_INOUTSTRING: /* open-input-output-string */
4797     {
4798     int prop = 0;
4799     pointer p;
4800    
4801     switch (op)
4802     {
4803     case OP_OPEN_INSTRING:
4804     prop = port_input;
4805     break;
4806    
4807     case OP_OPEN_INOUTSTRING:
4808     prop = port_input | port_output;
4809     break;
4810     }
4811    
4812 root 1.16 p = port_from_string (SCHEME_A_ strvalue (a),
4813     strvalue (a) + strlength (a), prop);
4814 root 1.1
4815     if (p == NIL)
4816 root 1.2 s_return (S_F);
4817 root 1.1
4818     s_return (p);
4819     }
4820    
4821     case OP_OPEN_OUTSTRING: /* open-output-string */
4822     {
4823     pointer p;
4824    
4825 root 1.16 if (a == NIL)
4826 root 1.1 {
4827     p = port_from_scratch (SCHEME_A);
4828    
4829     if (p == NIL)
4830 root 1.2 s_return (S_F);
4831 root 1.1 }
4832     else
4833     {
4834 root 1.16 p = port_from_string (SCHEME_A_ strvalue (a),
4835     strvalue (a) + strlength (a), port_output);
4836 root 1.1
4837     if (p == NIL)
4838 root 1.2 s_return (S_F);
4839 root 1.1 }
4840    
4841     s_return (p);
4842     }
4843    
4844     case OP_GET_OUTSTRING: /* get-output-string */
4845     {
4846     port *p;
4847    
4848 root 1.16 if ((p = a->object.port)->kind & port_string)
4849 root 1.1 {
4850     off_t size;
4851     char *str;
4852    
4853     size = p->rep.string.curr - p->rep.string.start + 1;
4854     str = malloc (size);
4855    
4856     if (str != NULL)
4857     {
4858     pointer s;
4859    
4860     memcpy (str, p->rep.string.start, size - 1);
4861     str[size - 1] = '\0';
4862     s = mk_string (SCHEME_A_ str);
4863     free (str);
4864     s_return (s);
4865     }
4866     }
4867    
4868     s_return (S_F);
4869     }
4870    
4871     # endif
4872    
4873     case OP_CLOSE_INPORT: /* close-input-port */
4874 root 1.16 port_close (SCHEME_A_ a, port_input);
4875 root 1.1 s_return (S_T);
4876    
4877     case OP_CLOSE_OUTPORT: /* close-output-port */
4878 root 1.16 port_close (SCHEME_A_ a, port_output);
4879 root 1.1 s_return (S_T);
4880     #endif
4881    
4882     case OP_INT_ENV: /* interaction-environment */
4883     s_return (SCHEME_V->global_env);
4884    
4885     case OP_CURR_ENV: /* current-environment */
4886     s_return (SCHEME_V->envir);
4887    
4888     }
4889    
4890 root 1.14 abort ();
4891 root 1.1 }
4892    
4893     static pointer
4894     opexe_5 (SCHEME_P_ enum scheme_opcodes op)
4895     {
4896 root 1.18 pointer args = SCHEME_V->args;
4897 root 1.1 pointer x;
4898    
4899     if (SCHEME_V->nesting != 0)
4900     {
4901     int n = SCHEME_V->nesting;
4902    
4903     SCHEME_V->nesting = 0;
4904     SCHEME_V->retcode = -1;
4905     Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
4906     }
4907    
4908     switch (op)
4909     {
4910     /* ========== reading part ========== */
4911     #if USE_PORTS
4912     case OP_READ:
4913 root 1.18 if (!is_pair (args))
4914 root 1.2 s_goto (OP_READ_INTERNAL);
4915 root 1.1
4916 root 1.18 if (!is_inport (car (args)))
4917     Error_1 ("read: not an input port:", car (args));
4918 root 1.1
4919 root 1.18 if (car (args) == SCHEME_V->inport)
4920 root 1.2 s_goto (OP_READ_INTERNAL);
4921 root 1.1
4922     x = SCHEME_V->inport;
4923 root 1.18 SCHEME_V->inport = car (args);
4924 root 1.1 x = cons (x, NIL);
4925     s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4926     s_goto (OP_READ_INTERNAL);
4927    
4928     case OP_READ_CHAR: /* read-char */
4929     case OP_PEEK_CHAR: /* peek-char */
4930     {
4931     int c;
4932    
4933 root 1.18 if (is_pair (args))
4934 root 1.1 {
4935 root 1.18 if (car (args) != SCHEME_V->inport)
4936 root 1.1 {
4937     x = SCHEME_V->inport;
4938     x = cons (x, NIL);
4939     s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4940 root 1.18 SCHEME_V->inport = car (args);
4941 root 1.1 }
4942     }
4943    
4944     c = inchar (SCHEME_A);
4945    
4946     if (c == EOF)
4947     s_return (S_EOF);
4948    
4949     if (SCHEME_V->op == OP_PEEK_CHAR)
4950     backchar (SCHEME_A_ c);
4951    
4952     s_return (mk_character (SCHEME_A_ c));
4953     }
4954    
4955     case OP_CHAR_READY: /* char-ready? */
4956     {
4957     pointer p = SCHEME_V->inport;
4958     int res;
4959    
4960 root 1.18 if (is_pair (args))
4961     p = car (args);
4962 root 1.1
4963     res = p->object.port->kind & port_string;
4964    
4965     s_retbool (res);
4966     }
4967    
4968     case OP_SET_INPORT: /* set-input-port */
4969 root 1.18 SCHEME_V->inport = car (args);
4970 root 1.1 s_return (SCHEME_V->value);
4971    
4972     case OP_SET_OUTPORT: /* set-output-port */
4973 root 1.18 SCHEME_V->outport = car (args);
4974 root 1.1 s_return (SCHEME_V->value);
4975     #endif
4976    
4977     case OP_RDSEXPR:
4978     switch (SCHEME_V->tok)
4979     {
4980     case TOK_EOF:
4981     s_return (S_EOF);
4982     /* NOTREACHED */
4983    
4984     case TOK_VEC:
4985     s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
4986 root 1.2 /* fall through */
4987 root 1.1
4988     case TOK_LPAREN:
4989     SCHEME_V->tok = token (SCHEME_A);
4990    
4991     if (SCHEME_V->tok == TOK_RPAREN)
4992     s_return (NIL);
4993     else if (SCHEME_V->tok == TOK_DOT)
4994     Error_0 ("syntax error: illegal dot expression");
4995     else
4996     {
4997     SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
4998     s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
4999     s_goto (OP_RDSEXPR);
5000     }
5001    
5002     case TOK_QUOTE:
5003     s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
5004     SCHEME_V->tok = token (SCHEME_A);
5005     s_goto (OP_RDSEXPR);
5006    
5007     case TOK_BQUOTE:
5008     SCHEME_V->tok = token (SCHEME_A);
5009    
5010     if (SCHEME_V->tok == TOK_VEC)
5011     {
5012     s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
5013     SCHEME_V->tok = TOK_LPAREN;
5014     s_goto (OP_RDSEXPR);
5015     }
5016     else
5017 root 1.2 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
5018 root 1.1
5019     s_goto (OP_RDSEXPR);
5020    
5021     case TOK_COMMA:
5022     s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
5023     SCHEME_V->tok = token (SCHEME_A);
5024     s_goto (OP_RDSEXPR);
5025    
5026     case TOK_ATMARK:
5027     s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
5028     SCHEME_V->tok = token (SCHEME_A);
5029     s_goto (OP_RDSEXPR);
5030    
5031     case TOK_ATOM:
5032     s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS)));
5033    
5034     case TOK_DQUOTE:
5035     x = readstrexp (SCHEME_A);
5036    
5037     if (x == S_F)
5038     Error_0 ("Error reading string");
5039    
5040     setimmutable (x);
5041     s_return (x);
5042    
5043     case TOK_SHARP:
5044     {
5045     pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
5046    
5047     if (f == NIL)
5048     Error_0 ("undefined sharp expression");
5049     else
5050     {
5051     SCHEME_V->code = cons (slot_value_in_env (f), NIL);
5052     s_goto (OP_EVAL);
5053     }
5054     }
5055    
5056     case TOK_SHARP_CONST:
5057     if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS))) == NIL)
5058     Error_0 ("undefined sharp expression");
5059     else
5060     s_return (x);
5061    
5062     default:
5063     Error_0 ("syntax error: illegal token");
5064     }
5065    
5066     break;
5067    
5068     case OP_RDLIST:
5069 root 1.18 SCHEME_V->args = cons (SCHEME_V->value, args);
5070 root 1.2 SCHEME_V->tok = token (SCHEME_A);
5071 root 1.1
5072 root 1.2 switch (SCHEME_V->tok)
5073     {
5074     case TOK_EOF:
5075     s_return (S_EOF);
5076 root 1.1
5077 root 1.2 case TOK_RPAREN:
5078     {
5079     int c = inchar (SCHEME_A);
5080 root 1.1
5081 root 1.2 if (c != '\n')
5082     backchar (SCHEME_A_ c);
5083 root 1.1 #if SHOW_ERROR_LINE
5084 root 1.2 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5085     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5086     #endif
5087 root 1.1
5088 root 1.2 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5089     s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5090     }
5091    
5092     case TOK_DOT:
5093 root 1.1 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5094     SCHEME_V->tok = token (SCHEME_A);
5095     s_goto (OP_RDSEXPR);
5096 root 1.2
5097     default:
5098     s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5099 root 1.1 s_goto (OP_RDSEXPR);
5100 root 1.2 }
5101 root 1.1
5102     case OP_RDDOT:
5103     if (token (SCHEME_A) != TOK_RPAREN)
5104     Error_0 ("syntax error: illegal dot expression");
5105 root 1.2
5106     SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5107 root 1.18 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5108 root 1.1
5109     case OP_RDQUOTE:
5110     s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5111    
5112     case OP_RDQQUOTE:
5113     s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5114    
5115     case OP_RDQQUOTEVEC:
5116     s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5117     cons (mk_symbol (SCHEME_A_ "vector"),
5118     cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5119    
5120     case OP_RDUNQUOTE:
5121     s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5122    
5123     case OP_RDUQTSP:
5124     s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5125    
5126     case OP_RDVEC:
5127     /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5128     s_goto(OP_EVAL); Cannot be quoted */
5129     /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5130     s_return(x); Cannot be part of pairs */
5131     /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5132     SCHEME_V->args=SCHEME_V->value;
5133     s_goto(OP_APPLY); */
5134     SCHEME_V->args = SCHEME_V->value;
5135     s_goto (OP_VECTOR);
5136    
5137     /* ========== printing part ========== */
5138     case OP_P0LIST:
5139 root 1.18 if (is_vector (args))
5140 root 1.1 {
5141     putstr (SCHEME_A_ "#(");
5142 root 1.18 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5143 root 1.1 s_goto (OP_PVECFROM);
5144     }
5145 root 1.18 else if (is_environment (args))
5146 root 1.1 {
5147     putstr (SCHEME_A_ "#<ENVIRONMENT>");
5148     s_return (S_T);
5149     }
5150 root 1.18 else if (!is_pair (args))
5151 root 1.1 {
5152 root 1.18 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5153 root 1.1 s_return (S_T);
5154     }
5155     else
5156     {
5157 root 1.18 pointer a = car (args);
5158     pointer b = cdr (args);
5159     int ok_abbr = ok_abbrev (b);
5160     SCHEME_V->args = car (b);
5161    
5162     if (a == SCHEME_V->QUOTE && ok_abbr)
5163     putstr (SCHEME_A_ "'");
5164     else if (a == SCHEME_V->QQUOTE && ok_abbr)
5165     putstr (SCHEME_A_ "`");
5166     else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5167     putstr (SCHEME_A_ ",");
5168     else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5169     putstr (SCHEME_A_ ",@");
5170     else
5171     {
5172     putstr (SCHEME_A_ "(");
5173     s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5174     SCHEME_V->args = a;
5175     }
5176    
5177 root 1.1 s_goto (OP_P0LIST);
5178     }
5179    
5180     case OP_P1LIST:
5181 root 1.18 if (is_pair (args))
5182 root 1.1 {
5183 root 1.18 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5184 root 1.1 putstr (SCHEME_A_ " ");
5185 root 1.18 SCHEME_V->args = car (args);
5186 root 1.1 s_goto (OP_P0LIST);
5187     }
5188 root 1.18 else if (is_vector (args))
5189 root 1.1 {
5190     s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5191     putstr (SCHEME_A_ " . ");
5192     s_goto (OP_P0LIST);
5193     }
5194     else
5195     {
5196 root 1.18 if (args != NIL)
5197 root 1.1 {
5198     putstr (SCHEME_A_ " . ");
5199 root 1.18 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5200 root 1.1 }
5201    
5202     putstr (SCHEME_A_ ")");
5203     s_return (S_T);
5204     }
5205    
5206     case OP_PVECFROM:
5207     {
5208 root 1.18 int i = ivalue_unchecked (cdr (args));
5209     pointer vec = car (args);
5210 root 1.7 int len = veclength (vec);
5211 root 1.1
5212     if (i == len)
5213     {
5214     putstr (SCHEME_A_ ")");
5215     s_return (S_T);
5216     }
5217     else
5218     {
5219     pointer elem = vector_elem (vec, i);
5220    
5221 root 1.18 ivalue_unchecked (cdr (args)) = i + 1;
5222     s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5223 root 1.1 SCHEME_V->args = elem;
5224    
5225     if (i > 0)
5226     putstr (SCHEME_A_ " ");
5227    
5228     s_goto (OP_P0LIST);
5229     }
5230     }
5231     }
5232    
5233 root 1.14 abort ();
5234 root 1.1 }
5235    
5236     static pointer
5237     opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5238     {
5239 root 1.18 pointer args = SCHEME_V->args;
5240     pointer a = car (args);
5241 root 1.1 pointer x, y;
5242    
5243     switch (op)
5244     {
5245     case OP_LIST_LENGTH: /* length *//* a.k */
5246     {
5247 root 1.18 long v = list_length (SCHEME_A_ a);
5248 root 1.1
5249     if (v < 0)
5250 root 1.18 Error_1 ("length: not a list:", a);
5251 root 1.1
5252     s_return (mk_integer (SCHEME_A_ v));
5253     }
5254    
5255     case OP_ASSQ: /* assq *//* a.k */
5256 root 1.18 x = a;
5257 root 1.1
5258 root 1.18 for (y = cadr (args); is_pair (y); y = cdr (y))
5259 root 1.1 {
5260     if (!is_pair (car (y)))
5261     Error_0 ("unable to handle non pair element");
5262    
5263     if (x == caar (y))
5264     break;
5265     }
5266    
5267     if (is_pair (y))
5268     s_return (car (y));
5269     else
5270     s_return (S_F);
5271    
5272    
5273     case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5274 root 1.18 SCHEME_V->args = a;
5275 root 1.1
5276     if (SCHEME_V->args == NIL)
5277     s_return (S_F);
5278     else if (is_closure (SCHEME_V->args))
5279     s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5280     else if (is_macro (SCHEME_V->args))
5281     s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5282     else
5283     s_return (S_F);
5284    
5285     case OP_CLOSUREP: /* closure? */
5286     /*
5287     * Note, macro object is also a closure.
5288     * Therefore, (closure? <#MACRO>) ==> #t
5289     */
5290 root 1.18 s_retbool (is_closure (a));
5291 root 1.1
5292     case OP_MACROP: /* macro? */
5293 root 1.18 s_retbool (is_macro (a));
5294 root 1.1 }
5295    
5296 root 1.14 abort ();
5297 root 1.1 }
5298    
5299     typedef pointer (*dispatch_func) (SCHEME_P_ enum scheme_opcodes);
5300    
5301 root 1.19 typedef int (*test_predicate)(pointer);
5302 root 1.1 static int
5303     is_any (pointer p)
5304     {
5305     return 1;
5306     }
5307    
5308     static int
5309     is_nonneg (pointer p)
5310     {
5311     return ivalue (p) >= 0 && is_integer (p);
5312     }
5313    
5314 root 1.19 static int
5315     tst_is_list (pointer p)
5316     {
5317     return p == NIL || is_pair (p);
5318     }
5319    
5320 root 1.1 /* Correspond carefully with following defines! */
5321     static struct
5322     {
5323     test_predicate fct;
5324     const char *kind;
5325     } tests[] =
5326     {
5327 root 1.19 { is_any, 0 },
5328     { is_string, "string" },
5329     { is_symbol, "symbol" },
5330     { is_port, "port" },
5331     { is_inport, "input port" },
5332     { is_outport, "output port" },
5333     { is_environment, "environment" },
5334     { is_pair, "pair" },
5335     { tst_is_list, "pair or '()" },
5336     { is_character, "character" },
5337     { is_vector, "vector" },
5338     { is_number, "number" },
5339     { is_integer, "integer" },
5340     { is_nonneg, "non-negative integer" }
5341 root 1.1 };
5342    
5343 root 1.18 #define TST_NONE 0 /* TST_NONE used for standard procedures, for internal ops, 0 is used */
5344     #define TST_ANY "\001"
5345     #define TST_STRING "\002"
5346     #define TST_SYMBOL "\003"
5347     #define TST_PORT "\004"
5348     #define TST_INPORT "\005"
5349     #define TST_OUTPORT "\006"
5350 root 1.1 #define TST_ENVIRONMENT "\007"
5351 root 1.18 #define TST_PAIR "\010"
5352     #define TST_LIST "\011"
5353     #define TST_CHAR "\012"
5354     #define TST_VECTOR "\013"
5355     #define TST_NUMBER "\014"
5356     #define TST_INTEGER "\015"
5357     #define TST_NATURAL "\016"
5358 root 1.1
5359     typedef struct
5360     {
5361     dispatch_func func;
5362     char *name;
5363     int min_arity;
5364     int max_arity;
5365 root 1.18 char arg_tests_encoding[3];
5366 root 1.1 } op_code_info;
5367    
5368     #define INF_ARG 0xffff
5369    
5370     static op_code_info dispatch_table[] = {
5371 root 1.18 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { opexe_ ## func, name, minarity, maxarity, argtest },
5372 root 1.1 #include "opdefines.h"
5373 root 1.18 #undef OP_DEF
5374 root 1.1 {0}
5375     };
5376    
5377     static const char *
5378     procname (pointer x)
5379     {
5380     int n = procnum (x);
5381     const char *name = dispatch_table[n].name;
5382    
5383     if (name == 0)
5384 root 1.2 name = "ILLEGAL!";
5385 root 1.1
5386     return name;
5387     }
5388    
5389     /* kernel of this interpreter */
5390     static void
5391     Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5392     {
5393     SCHEME_V->op = op;
5394    
5395     for (;;)
5396     {
5397     op_code_info *pcd = dispatch_table + SCHEME_V->op;
5398    
5399 root 1.4 #if USE_ERROR_CHECKING
5400 root 1.2 if (pcd->name) /* if built-in function, check arguments */
5401 root 1.1 {
5402 root 1.4 int ok = 1;
5403 root 1.1 char msg[STRBUFFSIZE];
5404     int n = list_length (SCHEME_A_ SCHEME_V->args);
5405    
5406     /* Check number of arguments */
5407 root 1.10 if (ecb_expect_false (n < pcd->min_arity))
5408 root 1.1 {
5409     ok = 0;
5410     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5411     pcd->name, pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5412     }
5413 root 1.16 else if (ecb_expect_false (n > pcd->max_arity))
5414 root 1.1 {
5415     ok = 0;
5416     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5417     pcd->name, pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5418     }
5419    
5420 root 1.10 if (ecb_expect_false (ok))
5421 root 1.1 {
5422 root 1.18 if (*pcd->arg_tests_encoding)
5423 root 1.1 {
5424     int i = 0;
5425     int j;
5426     const char *t = pcd->arg_tests_encoding;
5427     pointer arglist = SCHEME_V->args;
5428    
5429     do
5430     {
5431     pointer arg = car (arglist);
5432    
5433 root 1.18 j = t[0];
5434 root 1.1
5435 root 1.19 if (!tests[j - 1].fct (arg))
5436     break;
5437 root 1.1
5438 root 1.18 if (t[1]) /* last test is replicated as necessary */
5439 root 1.2 t++;
5440 root 1.1
5441     arglist = cdr (arglist);
5442     i++;
5443     }
5444     while (i < n);
5445    
5446     if (i < n)
5447     {
5448     ok = 0;
5449     snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", pcd->name, i + 1, tests[j].kind);
5450     }
5451     }
5452     }
5453    
5454     if (!ok)
5455     {
5456     if (xError_1 (SCHEME_A_ msg, 0) == NIL)
5457     return;
5458    
5459     pcd = dispatch_table + SCHEME_V->op;
5460     }
5461     }
5462 root 1.4 #endif
5463 root 1.1
5464     ok_to_freely_gc (SCHEME_A);
5465    
5466 root 1.10 if (ecb_expect_false (pcd->func (SCHEME_A_ SCHEME_V->op) == NIL))
5467 root 1.1 return;
5468    
5469 root 1.5 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5470 root 1.1 {
5471     xwrstr ("No memory!\n");
5472     return;
5473     }
5474     }
5475     }
5476    
5477     /* ========== Initialization of internal keywords ========== */
5478    
5479     static void
5480 root 1.2 assign_syntax (SCHEME_P_ const char *name)
5481 root 1.1 {
5482     pointer x = oblist_add_by_name (SCHEME_A_ name);
5483     set_typeflag (x, typeflag (x) | T_SYNTAX);
5484     }
5485    
5486     static void
5487 root 1.2 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5488 root 1.1 {
5489     pointer x = mk_symbol (SCHEME_A_ name);
5490     pointer y = mk_proc (SCHEME_A_ op);
5491     new_slot_in_env (SCHEME_A_ x, y);
5492     }
5493    
5494     static pointer
5495     mk_proc (SCHEME_P_ enum scheme_opcodes op)
5496     {
5497     pointer y = get_cell (SCHEME_A_ NIL, NIL);
5498     set_typeflag (y, (T_PROC | T_ATOM));
5499 root 1.2 ivalue_unchecked (y) = op;
5500 root 1.1 set_num_integer (y);
5501     return y;
5502     }
5503    
5504     /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5505     static int
5506     syntaxnum (pointer p)
5507     {
5508     const char *s = strvalue (car (p));
5509    
5510     switch (strlength (car (p)))
5511     {
5512     case 2:
5513     if (s[0] == 'i')
5514     return OP_IF0; /* if */
5515     else
5516     return OP_OR0; /* or */
5517    
5518     case 3:
5519     if (s[0] == 'a')
5520     return OP_AND0; /* and */
5521     else
5522     return OP_LET0; /* let */
5523    
5524     case 4:
5525     switch (s[3])
5526     {
5527     case 'e':
5528     return OP_CASE0; /* case */
5529    
5530     case 'd':
5531     return OP_COND0; /* cond */
5532    
5533     case '*':
5534 root 1.10 return OP_LET0AST;/* let* */
5535 root 1.1
5536     default:
5537     return OP_SET0; /* set! */
5538     }
5539    
5540     case 5:
5541     switch (s[2])
5542     {
5543     case 'g':
5544     return OP_BEGIN; /* begin */
5545    
5546     case 'l':
5547     return OP_DELAY; /* delay */
5548    
5549     case 'c':
5550     return OP_MACRO0; /* macro */
5551    
5552     default:
5553     return OP_QUOTE; /* quote */
5554     }
5555    
5556     case 6:
5557     switch (s[2])
5558     {
5559     case 'm':
5560     return OP_LAMBDA; /* lambda */
5561    
5562     case 'f':
5563     return OP_DEF0; /* define */
5564    
5565     default:
5566 root 1.10 return OP_LET0REC;/* letrec */
5567 root 1.1 }
5568    
5569     default:
5570     return OP_C0STREAM; /* cons-stream */
5571     }
5572     }
5573    
5574     #if USE_MULTIPLICITY
5575     scheme *
5576     scheme_init_new ()
5577     {
5578     scheme *sc = malloc (sizeof (scheme));
5579    
5580     if (!scheme_init (SCHEME_A))
5581     {
5582     free (SCHEME_A);
5583     return 0;
5584     }
5585     else
5586     return sc;
5587     }
5588     #endif
5589    
5590     int
5591     scheme_init (SCHEME_P)
5592     {
5593     int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5594     pointer x;
5595    
5596     num_set_fixnum (num_zero, 1);
5597     num_set_ivalue (num_zero, 0);
5598     num_set_fixnum (num_one, 1);
5599     num_set_ivalue (num_one, 1);
5600    
5601     #if USE_INTERFACE
5602     SCHEME_V->vptr = &vtbl;
5603     #endif
5604     SCHEME_V->gensym_cnt = 0;
5605     SCHEME_V->last_cell_seg = -1;
5606     SCHEME_V->free_cell = NIL;
5607     SCHEME_V->fcells = 0;
5608     SCHEME_V->no_memory = 0;
5609     SCHEME_V->inport = NIL;
5610     SCHEME_V->outport = NIL;
5611     SCHEME_V->save_inport = NIL;
5612     SCHEME_V->loadport = NIL;
5613     SCHEME_V->nesting = 0;
5614     SCHEME_V->interactive_repl = 0;
5615    
5616     if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5617     {
5618     #if USE_ERROR_CHECKING
5619     SCHEME_V->no_memory = 1;
5620     return 0;
5621     #endif
5622     }
5623    
5624     SCHEME_V->gc_verbose = 0;
5625     dump_stack_initialize (SCHEME_A);
5626     SCHEME_V->code = NIL;
5627 root 1.2 SCHEME_V->args = NIL;
5628     SCHEME_V->envir = NIL;
5629 root 1.1 SCHEME_V->tracing = 0;
5630    
5631     /* init NIL */
5632 root 1.2 set_typeflag (NIL, T_ATOM | T_MARK);
5633 root 1.1 set_car (NIL, NIL);
5634     set_cdr (NIL, NIL);
5635     /* init T */
5636 root 1.2 set_typeflag (S_T, T_ATOM | T_MARK);
5637 root 1.1 set_car (S_T, S_T);
5638     set_cdr (S_T, S_T);
5639     /* init F */
5640 root 1.2 set_typeflag (S_F, T_ATOM | T_MARK);
5641 root 1.1 set_car (S_F, S_F);
5642     set_cdr (S_F, S_F);
5643 root 1.7 /* init EOF_OBJ */
5644     set_typeflag (S_EOF, T_ATOM | T_MARK);
5645     set_car (S_EOF, S_EOF);
5646     set_cdr (S_EOF, S_EOF);
5647 root 1.1 /* init sink */
5648 root 1.2 set_typeflag (S_SINK, T_PAIR | T_MARK);
5649 root 1.1 set_car (S_SINK, NIL);
5650 root 1.7
5651 root 1.1 /* init c_nest */
5652     SCHEME_V->c_nest = NIL;
5653    
5654     SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5655     /* init global_env */
5656     new_frame_in_env (SCHEME_A_ NIL);
5657     SCHEME_V->global_env = SCHEME_V->envir;
5658     /* init else */
5659     x = mk_symbol (SCHEME_A_ "else");
5660     new_slot_in_env (SCHEME_A_ x, S_T);
5661    
5662 root 1.2 {
5663     static const char *syntax_names[] = {
5664     "lambda", "quote", "define", "if", "begin", "set!",
5665     "let", "let*", "letrec", "cond", "delay", "and",
5666     "or", "cons-stream", "macro", "case"
5667     };
5668    
5669     for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5670     assign_syntax (SCHEME_A_ syntax_names[i]);
5671     }
5672 root 1.1
5673     for (i = 0; i < n; i++)
5674 root 1.2 if (dispatch_table[i].name != 0)
5675     assign_proc (SCHEME_A_ i, dispatch_table[i].name);
5676 root 1.1
5677     /* initialization of global pointers to special symbols */
5678 root 1.6 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5679     SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5680     SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5681     SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5682     SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5683     SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5684     SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5685     SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5686     SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5687 root 1.1 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5688    
5689     return !SCHEME_V->no_memory;
5690     }
5691    
5692     #if USE_PORTS
5693     void
5694     scheme_set_input_port_file (SCHEME_P_ int fin)
5695     {
5696     SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5697     }
5698    
5699     void
5700     scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5701     {
5702     SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5703     }
5704    
5705     void
5706     scheme_set_output_port_file (SCHEME_P_ int fout)
5707     {
5708     SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5709     }
5710    
5711     void
5712     scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5713     {
5714     SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5715     }
5716     #endif
5717    
5718     void
5719     scheme_set_external_data (SCHEME_P_ void *p)
5720     {
5721     SCHEME_V->ext_data = p;
5722     }
5723    
5724     void
5725     scheme_deinit (SCHEME_P)
5726     {
5727     int i;
5728    
5729     #if SHOW_ERROR_LINE
5730     char *fname;
5731     #endif
5732    
5733     SCHEME_V->oblist = NIL;
5734     SCHEME_V->global_env = NIL;
5735     dump_stack_free (SCHEME_A);
5736     SCHEME_V->envir = NIL;
5737     SCHEME_V->code = NIL;
5738     SCHEME_V->args = NIL;
5739     SCHEME_V->value = NIL;
5740    
5741     if (is_port (SCHEME_V->inport))
5742     set_typeflag (SCHEME_V->inport, T_ATOM);
5743    
5744     SCHEME_V->inport = NIL;
5745     SCHEME_V->outport = NIL;
5746    
5747     if (is_port (SCHEME_V->save_inport))
5748     set_typeflag (SCHEME_V->save_inport, T_ATOM);
5749    
5750     SCHEME_V->save_inport = NIL;
5751    
5752     if (is_port (SCHEME_V->loadport))
5753     set_typeflag (SCHEME_V->loadport, T_ATOM);
5754    
5755     SCHEME_V->loadport = NIL;
5756     SCHEME_V->gc_verbose = 0;
5757     gc (SCHEME_A_ NIL, NIL);
5758    
5759     for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5760     free (SCHEME_V->alloc_seg[i]);
5761    
5762     #if SHOW_ERROR_LINE
5763     for (i = 0; i <= SCHEME_V->file_i; i++)
5764     {
5765     if (SCHEME_V->load_stack[i].kind & port_file)
5766     {
5767     fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5768    
5769     if (fname)
5770     free (fname);
5771     }
5772     }
5773     #endif
5774     }
5775    
5776     void
5777     scheme_load_file (SCHEME_P_ int fin)
5778     {
5779     scheme_load_named_file (SCHEME_A_ fin, 0);
5780     }
5781    
5782     void
5783     scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5784     {
5785     dump_stack_reset (SCHEME_A);
5786     SCHEME_V->envir = SCHEME_V->global_env;
5787     SCHEME_V->file_i = 0;
5788     SCHEME_V->load_stack[0].unget = -1;
5789     SCHEME_V->load_stack[0].kind = port_input | port_file;
5790     SCHEME_V->load_stack[0].rep.stdio.file = fin;
5791     #if USE_PORTS
5792     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5793     #endif
5794     SCHEME_V->retcode = 0;
5795    
5796     #if USE_PORTS
5797     if (fin == STDIN_FILENO)
5798     SCHEME_V->interactive_repl = 1;
5799     #endif
5800    
5801     #if USE_PORTS
5802     #if SHOW_ERROR_LINE
5803     SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5804    
5805     if (fin != STDIN_FILENO && filename)
5806     SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5807     #endif
5808     #endif
5809    
5810     SCHEME_V->inport = SCHEME_V->loadport;
5811     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5812     Eval_Cycle (SCHEME_A_ OP_T0LVL);
5813     set_typeflag (SCHEME_V->loadport, T_ATOM);
5814    
5815     if (SCHEME_V->retcode == 0)
5816     SCHEME_V->retcode = SCHEME_V->nesting != 0;
5817     }
5818    
5819     void
5820     scheme_load_string (SCHEME_P_ const char *cmd)
5821     {
5822     dump_stack_reset (SCHEME_A);
5823     SCHEME_V->envir = SCHEME_V->global_env;
5824     SCHEME_V->file_i = 0;
5825     SCHEME_V->load_stack[0].kind = port_input | port_string;
5826 root 1.17 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
5827     SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
5828     SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
5829 root 1.1 #if USE_PORTS
5830     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5831     #endif
5832     SCHEME_V->retcode = 0;
5833     SCHEME_V->interactive_repl = 0;
5834     SCHEME_V->inport = SCHEME_V->loadport;
5835     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5836     Eval_Cycle (SCHEME_A_ OP_T0LVL);
5837     set_typeflag (SCHEME_V->loadport, T_ATOM);
5838    
5839     if (SCHEME_V->retcode == 0)
5840     SCHEME_V->retcode = SCHEME_V->nesting != 0;
5841     }
5842    
5843     void
5844     scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
5845     {
5846     pointer x;
5847    
5848     x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
5849    
5850     if (x != NIL)
5851 root 1.2 set_slot_in_env (SCHEME_A_ x, value);
5852 root 1.1 else
5853 root 1.2 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
5854 root 1.1 }
5855    
5856     #if !STANDALONE
5857 root 1.2
5858 root 1.1 void
5859     scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
5860     {
5861     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
5862     }
5863    
5864     void
5865     scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
5866     {
5867     int i;
5868    
5869     for (i = 0; i < count; i++)
5870 root 1.2 scheme_register_foreign_func (SCHEME_A_ list + i);
5871 root 1.1 }
5872    
5873     pointer
5874     scheme_apply0 (SCHEME_P_ const char *procname)
5875     {
5876     return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
5877     }
5878    
5879     void
5880     save_from_C_call (SCHEME_P)
5881     {
5882     pointer saved_data = cons (car (S_SINK),
5883     cons (SCHEME_V->envir,
5884     SCHEME_V->dump));
5885    
5886     /* Push */
5887     SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
5888     /* Truncate the dump stack so TS will return here when done, not
5889     directly resume pre-C-call operations. */
5890     dump_stack_reset (SCHEME_A);
5891     }
5892    
5893     void
5894     restore_from_C_call (SCHEME_P)
5895     {
5896     set_car (S_SINK, caar (SCHEME_V->c_nest));
5897     SCHEME_V->envir = cadar (SCHEME_V->c_nest);
5898     SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
5899     /* Pop */
5900     SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
5901     }
5902    
5903     /* "func" and "args" are assumed to be already eval'ed. */
5904     pointer
5905     scheme_call (SCHEME_P_ pointer func, pointer args)
5906     {
5907     int old_repl = SCHEME_V->interactive_repl;
5908    
5909     SCHEME_V->interactive_repl = 0;
5910     save_from_C_call (SCHEME_A);
5911     SCHEME_V->envir = SCHEME_V->global_env;
5912     SCHEME_V->args = args;
5913     SCHEME_V->code = func;
5914     SCHEME_V->retcode = 0;
5915     Eval_Cycle (SCHEME_A_ OP_APPLY);
5916     SCHEME_V->interactive_repl = old_repl;
5917     restore_from_C_call (SCHEME_A);
5918     return SCHEME_V->value;
5919     }
5920    
5921     pointer
5922     scheme_eval (SCHEME_P_ pointer obj)
5923     {
5924     int old_repl = SCHEME_V->interactive_repl;
5925    
5926     SCHEME_V->interactive_repl = 0;
5927     save_from_C_call (SCHEME_A);
5928     SCHEME_V->args = NIL;
5929     SCHEME_V->code = obj;
5930     SCHEME_V->retcode = 0;
5931     Eval_Cycle (SCHEME_A_ OP_EVAL);
5932     SCHEME_V->interactive_repl = old_repl;
5933     restore_from_C_call (SCHEME_A);
5934     return SCHEME_V->value;
5935     }
5936    
5937     #endif
5938    
5939     /* ========== Main ========== */
5940    
5941     #if STANDALONE
5942    
5943     int
5944     main (int argc, char **argv)
5945     {
5946     # if USE_MULTIPLICITY
5947     scheme ssc;
5948 root 1.2 scheme *const SCHEME_V = &ssc;
5949 root 1.1 # else
5950     # endif
5951     int fin;
5952     char *file_name = InitFile;
5953     int retcode;
5954     int isfile = 1;
5955    
5956     if (argc == 2 && strcmp (argv[1], "-?") == 0)
5957     {
5958     xwrstr ("Usage: tinyscheme -?\n");
5959     xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
5960     xwrstr ("followed by\n");
5961     xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
5962     xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5963     xwrstr ("assuming that the executable is named tinyscheme.\n");
5964     xwrstr ("Use - as filename for stdin.\n");
5965     return 1;
5966     }
5967    
5968     if (!scheme_init (SCHEME_A))
5969     {
5970     xwrstr ("Could not initialize!\n");
5971     return 2;
5972     }
5973    
5974     # if USE_PORTS
5975     scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
5976     scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
5977     # endif
5978    
5979     argv++;
5980    
5981     #if 0
5982     if (access (file_name, 0) != 0)
5983     {
5984     char *p = getenv ("TINYSCHEMEINIT");
5985    
5986     if (p != 0)
5987 root 1.2 file_name = p;
5988 root 1.1 }
5989     #endif
5990    
5991     do
5992     {
5993     #if USE_PORTS
5994     if (strcmp (file_name, "-") == 0)
5995     fin = STDIN_FILENO;
5996     else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
5997     {
5998     pointer args = NIL;
5999    
6000     isfile = file_name[1] == '1';
6001     file_name = *argv++;
6002    
6003     if (strcmp (file_name, "-") == 0)
6004     fin = STDIN_FILENO;
6005     else if (isfile)
6006     fin = open (file_name, O_RDONLY);
6007    
6008     for (; *argv; argv++)
6009     {
6010     pointer value = mk_string (SCHEME_A_ * argv);
6011    
6012     args = cons (value, args);
6013     }
6014    
6015     args = reverse_in_place (SCHEME_A_ NIL, args);
6016     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
6017    
6018     }
6019     else
6020     fin = open (file_name, O_RDONLY);
6021     #endif
6022    
6023     if (isfile && fin < 0)
6024     {
6025     xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
6026     }
6027     else
6028     {
6029     if (isfile)
6030     scheme_load_named_file (SCHEME_A_ fin, file_name);
6031     else
6032     scheme_load_string (SCHEME_A_ file_name);
6033    
6034     #if USE_PORTS
6035     if (!isfile || fin != STDIN_FILENO)
6036     {
6037     if (SCHEME_V->retcode != 0)
6038     {
6039     xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
6040     }
6041    
6042     if (isfile)
6043     close (fin);
6044     }
6045     #endif
6046     }
6047    
6048     file_name = *argv++;
6049     }
6050     while (file_name != 0);
6051    
6052     if (argc == 1)
6053     scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6054    
6055     retcode = SCHEME_V->retcode;
6056     scheme_deinit (SCHEME_A);
6057    
6058     return retcode;
6059     }
6060    
6061     #endif
6062    
6063     /*
6064     Local variables:
6065     c-file-style: "k&r"
6066     End:
6067     */