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