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