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