ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.70
Committed: Mon Dec 7 22:13:31 2015 UTC (8 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.69: +8 -8 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 root 1.69 new_frame = mk_vector (SCHEME_A_ 29); // was 461
2826 root 1.1 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.68 BOP_DELAY,
3400 root 1.66 BOP_OP,
3401 root 1.64 };
3402    
3403     ecb_cold static void compile_expr (SCHEME_P_ stream s, pointer x);
3404    
3405     ecb_cold static void
3406     compile_list (SCHEME_P_ stream s, pointer x)
3407     {
3408 root 1.66 // TODO: improper list
3409    
3410 root 1.64 for (; x != NIL; x = cdr (x))
3411 root 1.66 {
3412     stream t = stream_init ();
3413     compile_expr (SCHEME_A_ t, car (x));
3414     stream_put_v (s, stream_size (t));
3415     stream_put_stream (s, t);
3416     }
3417    
3418     stream_put_v (s, 0);
3419 root 1.64 }
3420    
3421     static void
3422     compile_if (SCHEME_P_ stream s, pointer cond, pointer ift, pointer iff)
3423     {
3424     stream sift = stream_init (); compile_expr (SCHEME_A_ sift, ift);
3425    
3426 root 1.66 stream_put (s, BOP_IF);
3427 root 1.64 compile_expr (SCHEME_A_ s, cond);
3428     stream_put_v (s, stream_size (sift));
3429     stream_put_stream (s, sift);
3430 root 1.66 compile_expr (SCHEME_A_ s, iff);
3431 root 1.64 }
3432    
3433     typedef uint32_t stream_fixup;
3434    
3435     static stream_fixup
3436     stream_put_fixup (stream s)
3437     {
3438     stream_put (s, 0);
3439     stream_put (s, 0);
3440    
3441     return stream_size (s);
3442     }
3443    
3444     static void
3445     stream_fix_fixup (stream s, stream_fixup fixup, uint32_t target)
3446     {
3447     target -= fixup;
3448     assert (target < (1 << 14));
3449     stream_data (s)[fixup - 2] = target | 0x80;
3450     stream_data (s)[fixup - 1] = target >> 7;
3451     }
3452    
3453 root 1.61 static void
3454 root 1.64 compile_and_or (SCHEME_P_ stream s, int and, pointer x)
3455 root 1.61 {
3456 root 1.66 for (; cdr (x) != NIL; x = cdr (x))
3457     {
3458     stream t = stream_init ();
3459     compile_expr (SCHEME_A_ t, car (x));
3460     stream_put_v (s, stream_size (t));
3461     stream_put_stream (s, t);
3462     }
3463    
3464     stream_put_v (s, 0);
3465     }
3466    
3467     static void
3468     compile_case (SCHEME_P_ stream s, pointer x)
3469     {
3470     compile_expr (SCHEME_A_ s, caar (x));
3471    
3472     for (;;)
3473 root 1.61 {
3474 root 1.66 x = cdr (x);
3475 root 1.64
3476 root 1.66 if (x == NIL)
3477     break;
3478    
3479     compile_expr (SCHEME_A_ s, caar (x));
3480     stream t = stream_init (); compile_expr (SCHEME_A_ t, cdar (x));
3481     stream_put_v (s, stream_size (t));
3482     stream_put_stream (s, t);
3483 root 1.61 }
3484 root 1.66
3485     stream_put_v (s, 0);
3486     }
3487    
3488     static void
3489     compile_cond (SCHEME_P_ stream s, pointer x)
3490     {
3491     for ( ; x != NIL; x = cdr (x))
3492     {
3493     compile_expr (SCHEME_A_ s, caar (x));
3494     stream t = stream_init (); compile_expr (SCHEME_A_ t, cdar (x));
3495     stream_put_v (s, stream_size (t));
3496     stream_put_stream (s, t);
3497     }
3498    
3499     stream_put_v (s, 0);
3500     }
3501    
3502     static pointer
3503     lookup (SCHEME_P_ pointer x)
3504     {
3505     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, x, 1);
3506    
3507     if (x != NIL)
3508     x = slot_value_in_env (x);
3509    
3510     return x;
3511 root 1.64 }
3512 root 1.61
3513 root 1.64 ecb_cold static void
3514     compile_expr (SCHEME_P_ stream s, pointer x)
3515     {
3516     if (x == NIL)
3517 root 1.61 {
3518 root 1.64 stream_put (s, BOP_NIL);
3519 root 1.61 return;
3520     }
3521    
3522 root 1.64 if (is_pair (x))
3523 root 1.61 {
3524 root 1.64 pointer head = car (x);
3525 root 1.61
3526 root 1.64 if (is_syntax (head))
3527 root 1.61 {
3528 root 1.68 int syn = syntaxnum (head);
3529 root 1.64 x = cdr (x);
3530    
3531     switch (syntaxnum (head))
3532     {
3533     case OP_IF0: /* if */
3534 root 1.66 stream_put_v (s, BOP_IF);
3535 root 1.64 compile_if (SCHEME_A_ s, car (x), cadr (x), caddr (x));
3536     break;
3537    
3538     case OP_OR0: /* or */
3539 root 1.66 stream_put_v (s, BOP_OR);
3540 root 1.64 compile_and_or (SCHEME_A_ s, 0, x);
3541     break;
3542 root 1.61
3543 root 1.64 case OP_AND0: /* and */
3544 root 1.66 stream_put_v (s, BOP_AND);
3545 root 1.64 compile_and_or (SCHEME_A_ s, 1, x);
3546     break;
3547 root 1.61
3548 root 1.64 case OP_CASE0: /* case */
3549 root 1.66 stream_put_v (s, BOP_CASE);
3550     compile_case (SCHEME_A_ s, x);
3551 root 1.64 break;
3552    
3553     case OP_COND0: /* cond */
3554 root 1.66 stream_put_v (s, BOP_COND);
3555     compile_cond (SCHEME_A_ s, x);
3556 root 1.64 break;
3557    
3558     case OP_LET0: /* let */
3559     case OP_LET0AST: /* let* */
3560     case OP_LET0REC: /* letrec */
3561 root 1.68 switch (syn)
3562 root 1.64 {
3563     case OP_LET0: stream_put (s, BOP_LET ); break;
3564     case OP_LET0AST: stream_put (s, BOP_LETAST); break;
3565     case OP_LET0REC: stream_put (s, BOP_LETREC); break;
3566     }
3567    
3568     {
3569     pointer bindings = car (x);
3570     pointer body = cadr (x);
3571    
3572     for (x = bindings; x != NIL; x = cdr (x))
3573     {
3574     pointer init = NIL;
3575     pointer var = car (x);
3576    
3577     if (is_pair (var))
3578     {
3579     init = cdr (var);
3580     var = car (var);
3581     }
3582    
3583     stream_put_v (s, symbol_id (SCHEME_A_ var));
3584     compile_expr (SCHEME_A_ s, init);
3585     }
3586    
3587     stream_put_v (s, 0);
3588     compile_expr (SCHEME_A_ s, body);
3589     }
3590     break;
3591    
3592     case OP_DEF0: /* define */
3593     case OP_MACRO0: /* macro */
3594     stream_put (s, syntaxnum (head) == OP_DEF0 ? BOP_DEFINE : BOP_MACRO);
3595     stream_put_v (s, cell_id (SCHEME_A_ car (x)));
3596     compile_expr (SCHEME_A_ s, cadr (x));
3597     break;
3598    
3599     case OP_SET0: /* set! */
3600     stream_put (s, BOP_SET);
3601     stream_put_v (s, symbol_id (SCHEME_A_ car (x)));
3602     compile_expr (SCHEME_A_ s, cadr (x));
3603     break;
3604    
3605     case OP_BEGIN: /* begin */
3606     stream_put (s, BOP_BEGIN);
3607     compile_list (SCHEME_A_ s, x);
3608     return;
3609    
3610     case OP_QUOTE: /* quote */
3611     stream_put_tv (s, BOP_DATUM, cell_id (SCHEME_A_ x));
3612     break;
3613    
3614 root 1.68 case OP_DELAY: /* delay */
3615 root 1.69 stream_put (s, BOP_DELAY);
3616     compile_expr (SCHEME_A_ s, x);
3617     break;
3618    
3619 root 1.64 case OP_LAMBDA: /* lambda */
3620     {
3621     pointer formals = car (x);
3622     pointer body = cadr (x);
3623    
3624 root 1.69 stream_put (s, BOP_LAMBDA);
3625 root 1.64
3626     for (; is_pair (formals); formals = cdr (formals))
3627     stream_put_v (s, symbol_id (SCHEME_A_ car (formals)));
3628    
3629     stream_put_v (s, 0);
3630     stream_put_v (s, formals == NIL ? 0 : symbol_id (SCHEME_A_ formals));
3631    
3632     compile_expr (SCHEME_A_ s, body);
3633     }
3634     break;
3635    
3636     case OP_C0STREAM:/* cons-stream */
3637     abort ();
3638     break;
3639     }
3640    
3641     return;
3642     }
3643    
3644 root 1.66 pointer m = lookup (SCHEME_A_ head);
3645 root 1.64
3646 root 1.66 if (is_macro (m))
3647 root 1.64 {
3648 root 1.66 s_save (SCHEME_A_ OP_DEBUG2, SCHEME_V->args, SCHEME_V->code);
3649     SCHEME_V->code = m;
3650     SCHEME_V->args = cons (x, NIL);
3651     Eval_Cycle (SCHEME_A_ OP_APPLY);
3652     x = SCHEME_V->value;
3653     compile_expr (SCHEME_A_ s, SCHEME_V->value);
3654     return;
3655     }
3656 root 1.64
3657 root 1.66 stream_put (s, BOP_LIST_BEG);
3658    
3659     for (; x != NIL; x = cdr (x))
3660     compile_expr (SCHEME_A_ s, car (x));
3661    
3662     stream_put (s, BOP_LIST_END);
3663     return;
3664 root 1.64 }
3665 root 1.61
3666 root 1.64 switch (type (x))
3667     {
3668     case T_INTEGER:
3669     {
3670     IVALUE iv = ivalue_unchecked (x);
3671 root 1.66 iv = iv < 0 ? ((~(uint32_t)iv) << 1) | 1 : (uint32_t)iv << 1;
3672 root 1.64 stream_put_tv (s, BOP_INTEGER, iv);
3673 root 1.61 }
3674     return;
3675    
3676 root 1.64 case T_SYMBOL:
3677 root 1.66 if (0)
3678     {
3679     // no can do without more analysis
3680     pointer m = lookup (SCHEME_A_ x);
3681 root 1.64
3682 root 1.66 if (is_proc (m))
3683     {
3684     printf ("compile proc %s %d\n", procname(m), procnum(m));
3685     stream_put_tv (s, BOP_SYMBOL, BOP_OP + procnum (m));
3686     }
3687     else
3688     stream_put_tv (s, BOP_SYMBOL, symbol_id (SCHEME_A_ x));
3689     }
3690 root 1.64
3691 root 1.66 stream_put_tv (s, BOP_SYMBOL, symbol_id (SCHEME_A_ x));
3692 root 1.61 return;
3693    
3694     default:
3695 root 1.64 stream_put_tv (s, BOP_DATUM, cell_id (SCHEME_A_ x));
3696 root 1.61 break;
3697     }
3698     }
3699    
3700 root 1.64 ecb_cold static int
3701 root 1.61 compile_closure (SCHEME_P_ pointer p)
3702     {
3703     stream s = stream_init ();
3704    
3705 root 1.64 compile_list (SCHEME_A_ s, cdar (p));
3706 root 1.61
3707     FILE *xxd = popen ("xxd", "we");
3708     fwrite (stream_data (s), 1, stream_size (s), xxd);
3709     fclose (xxd);
3710    
3711     return stream_size (s);
3712     }
3713    
3714 root 1.39 #endif
3715    
3716 root 1.60 /* syntax, eval, core, ... */
3717     ecb_hot static int
3718 root 1.1 opexe_0 (SCHEME_P_ enum scheme_opcodes op)
3719     {
3720 root 1.16 pointer args = SCHEME_V->args;
3721 root 1.1 pointer x, y;
3722    
3723     switch (op)
3724     {
3725 root 1.43 #if EXPERIMENT //D
3726 root 1.39 case OP_DEBUG:
3727 root 1.61 {
3728     uint32_t len = compile_closure (SCHEME_A_ car (args));
3729     printf ("len = %d\n", len);
3730     printf ("\n");
3731     s_return (S_T);
3732     }
3733 root 1.64
3734     case OP_DEBUG2:
3735     return -1;
3736 root 1.39 #endif
3737 root 1.64
3738 root 1.1 case OP_LOAD: /* load */
3739     if (file_interactive (SCHEME_A))
3740     {
3741 root 1.61 putstr (SCHEME_A_ "Loading ");
3742     putstr (SCHEME_A_ strvalue (car (args)));
3743     putcharacter (SCHEME_A_ '\n');
3744 root 1.1 }
3745    
3746 root 1.16 if (!file_push (SCHEME_A_ strvalue (car (args))))
3747     Error_1 ("unable to open", car (args));
3748 root 1.61
3749     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
3750     s_goto (OP_T0LVL);
3751 root 1.1
3752     case OP_T0LVL: /* top level */
3753    
3754     /* If we reached the end of file, this loop is done. */
3755 root 1.51 if (port (SCHEME_V->loadport)->kind & port_saw_EOF)
3756 root 1.1 {
3757     if (SCHEME_V->file_i == 0)
3758     {
3759     SCHEME_V->args = NIL;
3760     s_goto (OP_QUIT);
3761     }
3762     else
3763     {
3764     file_pop (SCHEME_A);
3765     s_return (SCHEME_V->value);
3766     }
3767    
3768     /* NOTREACHED */
3769     }
3770    
3771     /* If interactive, be nice to user. */
3772     if (file_interactive (SCHEME_A))
3773     {
3774     SCHEME_V->envir = SCHEME_V->global_env;
3775     dump_stack_reset (SCHEME_A);
3776 root 1.61 putcharacter (SCHEME_A_ '\n');
3777 root 1.63 #if EXPERIMENT
3778     system ("ps v $PPID");
3779     #endif
3780 root 1.1 putstr (SCHEME_A_ prompt);
3781     }
3782    
3783     /* Set up another iteration of REPL */
3784     SCHEME_V->nesting = 0;
3785     SCHEME_V->save_inport = SCHEME_V->inport;
3786     SCHEME_V->inport = SCHEME_V->loadport;
3787     s_save (SCHEME_A_ OP_T0LVL, NIL, NIL);
3788     s_save (SCHEME_A_ OP_VALUEPRINT, NIL, NIL);
3789     s_save (SCHEME_A_ OP_T1LVL, NIL, NIL);
3790     s_goto (OP_READ_INTERNAL);
3791    
3792     case OP_T1LVL: /* top level */
3793 root 1.7 SCHEME_V->code = SCHEME_V->value;
3794 root 1.1 SCHEME_V->inport = SCHEME_V->save_inport;
3795     s_goto (OP_EVAL);
3796    
3797     case OP_READ_INTERNAL: /* internal read */
3798     SCHEME_V->tok = token (SCHEME_A);
3799    
3800     if (SCHEME_V->tok == TOK_EOF)
3801 root 1.2 s_return (S_EOF);
3802 root 1.1
3803     s_goto (OP_RDSEXPR);
3804    
3805     case OP_GENSYM:
3806     s_return (gensym (SCHEME_A));
3807    
3808     case OP_VALUEPRINT: /* print evaluation result */
3809    
3810     /* OP_VALUEPRINT is always pushed, because when changing from
3811     non-interactive to interactive mode, it needs to be
3812     already on the stack */
3813     #if USE_TRACING
3814     if (SCHEME_V->tracing)
3815 root 1.2 putstr (SCHEME_A_ "\nGives: ");
3816 root 1.1 #endif
3817    
3818     if (file_interactive (SCHEME_A))
3819     {
3820     SCHEME_V->print_flag = 1;
3821     SCHEME_V->args = SCHEME_V->value;
3822     s_goto (OP_P0LIST);
3823     }
3824 root 1.61
3825     s_return (SCHEME_V->value);
3826 root 1.1
3827     case OP_EVAL: /* main part of evaluation */
3828     #if USE_TRACING
3829     if (SCHEME_V->tracing)
3830     {
3831     /*s_save(SCHEME_A_ OP_VALUEPRINT,NIL,NIL); */
3832 root 1.16 s_save (SCHEME_A_ OP_REAL_EVAL, args, SCHEME_V->code);
3833 root 1.1 SCHEME_V->args = SCHEME_V->code;
3834     putstr (SCHEME_A_ "\nEval: ");
3835     s_goto (OP_P0LIST);
3836     }
3837    
3838     /* fall through */
3839 root 1.2
3840 root 1.1 case OP_REAL_EVAL:
3841     #endif
3842     if (is_symbol (SCHEME_V->code)) /* symbol */
3843     {
3844     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3845    
3846 root 1.51 if (x == NIL)
3847 root 1.1 Error_1 ("eval: unbound variable:", SCHEME_V->code);
3848 root 1.51
3849     s_return (slot_value_in_env (x));
3850 root 1.1 }
3851     else if (is_pair (SCHEME_V->code))
3852     {
3853 root 1.7 x = car (SCHEME_V->code);
3854    
3855     if (is_syntax (x)) /* SYNTAX */
3856 root 1.1 {
3857     SCHEME_V->code = cdr (SCHEME_V->code);
3858     s_goto (syntaxnum (x));
3859     }
3860     else /* first, eval top element and eval arguments */
3861     {
3862     s_save (SCHEME_A_ OP_E0ARGS, NIL, SCHEME_V->code);
3863     /* If no macros => s_save(SCHEME_A_ OP_E1ARGS, NIL, cdr(SCHEME_V->code)); */
3864 root 1.7 SCHEME_V->code = x;
3865 root 1.1 s_goto (OP_EVAL);
3866     }
3867     }
3868 root 1.61
3869     s_return (SCHEME_V->code);
3870 root 1.1
3871     case OP_E0ARGS: /* eval arguments */
3872 root 1.38 if (ecb_expect_false (is_macro (SCHEME_V->value))) /* macro expansion */
3873 root 1.1 {
3874     s_save (SCHEME_A_ OP_DOMACRO, NIL, NIL);
3875     SCHEME_V->args = cons (SCHEME_V->code, NIL);
3876     SCHEME_V->code = SCHEME_V->value;
3877     s_goto (OP_APPLY);
3878     }
3879 root 1.64
3880     SCHEME_V->code = cdr (SCHEME_V->code);
3881     s_goto (OP_E1ARGS);
3882 root 1.1
3883     case OP_E1ARGS: /* eval arguments */
3884 root 1.16 args = cons (SCHEME_V->value, args);
3885 root 1.1
3886     if (is_pair (SCHEME_V->code)) /* continue */
3887     {
3888 root 1.16 s_save (SCHEME_A_ OP_E1ARGS, args, cdr (SCHEME_V->code));
3889 root 1.1 SCHEME_V->code = car (SCHEME_V->code);
3890     SCHEME_V->args = NIL;
3891     s_goto (OP_EVAL);
3892     }
3893     else /* end */
3894     {
3895 root 1.16 args = reverse_in_place (SCHEME_A_ NIL, args);
3896     SCHEME_V->code = car (args);
3897     SCHEME_V->args = cdr (args);
3898 root 1.1 s_goto (OP_APPLY);
3899     }
3900    
3901     #if USE_TRACING
3902     case OP_TRACING:
3903     {
3904     int tr = SCHEME_V->tracing;
3905    
3906 root 1.26 SCHEME_V->tracing = ivalue_unchecked (car (args));
3907 root 1.1 s_return (mk_integer (SCHEME_A_ tr));
3908     }
3909     #endif
3910    
3911     case OP_APPLY: /* apply 'code' to 'args' */
3912     #if USE_TRACING
3913     if (SCHEME_V->tracing)
3914     {
3915 root 1.16 s_save (SCHEME_A_ OP_REAL_APPLY, args, SCHEME_V->code);
3916 root 1.1 SCHEME_V->print_flag = 1;
3917 root 1.16 /* args=cons(SCHEME_V->code,args); */
3918 root 1.1 putstr (SCHEME_A_ "\nApply to: ");
3919     s_goto (OP_P0LIST);
3920     }
3921    
3922     /* fall through */
3923 root 1.2
3924 root 1.1 case OP_REAL_APPLY:
3925     #endif
3926     if (is_proc (SCHEME_V->code))
3927 root 1.18 s_goto (procnum (SCHEME_V->code)); /* PROCEDURE */
3928 root 1.1 else if (is_closure (SCHEME_V->code) || is_macro (SCHEME_V->code) || is_promise (SCHEME_V->code)) /* CLOSURE */
3929     {
3930     /* Should not accept promise */
3931     /* make environment */
3932     new_frame_in_env (SCHEME_A_ closure_env (SCHEME_V->code));
3933    
3934 root 1.16 for (x = car (closure_code (SCHEME_V->code)), y = args; is_pair (x); x = cdr (x), y = cdr (y))
3935 root 1.1 {
3936     if (y == NIL)
3937 root 1.2 Error_0 ("not enough arguments");
3938 root 1.1 else
3939 root 1.2 new_slot_in_env (SCHEME_A_ car (x), car (y));
3940 root 1.1 }
3941    
3942     if (x == NIL)
3943     {
3944 root 1.2 /*--
3945     * if (y != NIL) {
3946     * Error_0("too many arguments");
3947     * }
3948     */
3949 root 1.1 }
3950     else if (is_symbol (x))
3951     new_slot_in_env (SCHEME_A_ x, y);
3952     else
3953 root 1.2 Error_1 ("syntax error in closure: not a symbol:", x);
3954 root 1.1
3955     SCHEME_V->code = cdr (closure_code (SCHEME_V->code));
3956     SCHEME_V->args = NIL;
3957     s_goto (OP_BEGIN);
3958     }
3959     else if (is_continuation (SCHEME_V->code)) /* CONTINUATION */
3960     {
3961     ss_set_cont (SCHEME_A_ cont_dump (SCHEME_V->code));
3962 root 1.16 s_return (args != NIL ? car (args) : NIL);
3963 root 1.1 }
3964 root 1.70 else if (is_foreign (SCHEME_V->code))
3965     {
3966     /* Keep nested calls from GC'ing the arglist */
3967     push_recent_alloc (SCHEME_A_ args, NIL);
3968     x = CELL(SCHEME_V->code)->object.ff (SCHEME_A_ args);
3969    
3970     s_return (x);
3971     }
3972 root 1.64
3973     Error_0 ("illegal function");
3974 root 1.1
3975     case OP_DOMACRO: /* do macro */
3976     SCHEME_V->code = SCHEME_V->value;
3977     s_goto (OP_EVAL);
3978    
3979     case OP_LAMBDA: /* lambda */
3980     /* If the hook is defined, apply it to SCHEME_V->code, otherwise
3981     set SCHEME_V->value fall thru */
3982     {
3983     pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->COMPILE_HOOK, 1);
3984    
3985     if (f != NIL)
3986     {
3987 root 1.16 s_save (SCHEME_A_ OP_LAMBDA1, args, SCHEME_V->code);
3988 root 1.1 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3989     SCHEME_V->code = slot_value_in_env (f);
3990     s_goto (OP_APPLY);
3991     }
3992    
3993     SCHEME_V->value = SCHEME_V->code;
3994     }
3995 root 1.48 /* Fallthru */
3996 root 1.1
3997     case OP_LAMBDA1:
3998     s_return (mk_closure (SCHEME_A_ SCHEME_V->value, SCHEME_V->envir));
3999    
4000     case OP_MKCLOSURE: /* make-closure */
4001 root 1.16 x = car (args);
4002 root 1.1
4003     if (car (x) == SCHEME_V->LAMBDA)
4004     x = cdr (x);
4005    
4006 root 1.16 if (cdr (args) == NIL)
4007 root 1.1 y = SCHEME_V->envir;
4008     else
4009 root 1.16 y = cadr (args);
4010 root 1.1
4011     s_return (mk_closure (SCHEME_A_ x, y));
4012    
4013     case OP_QUOTE: /* quote */
4014     s_return (car (SCHEME_V->code));
4015    
4016     case OP_DEF0: /* define */
4017     if (is_immutable (car (SCHEME_V->code)))
4018     Error_1 ("define: unable to alter immutable", car (SCHEME_V->code));
4019    
4020     if (is_pair (car (SCHEME_V->code)))
4021     {
4022     x = caar (SCHEME_V->code);
4023     SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
4024     }
4025     else
4026     {
4027     x = car (SCHEME_V->code);
4028     SCHEME_V->code = cadr (SCHEME_V->code);
4029     }
4030    
4031     if (!is_symbol (x))
4032 root 1.2 Error_0 ("variable is not a symbol");
4033 root 1.1
4034     s_save (SCHEME_A_ OP_DEF1, NIL, x);
4035     s_goto (OP_EVAL);
4036    
4037     case OP_DEF1: /* define */
4038     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
4039    
4040     if (x != NIL)
4041 root 1.2 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
4042 root 1.1 else
4043 root 1.2 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
4044 root 1.1
4045     s_return (SCHEME_V->code);
4046    
4047     case OP_DEFP: /* defined? */
4048     x = SCHEME_V->envir;
4049    
4050 root 1.16 if (cdr (args) != NIL)
4051     x = cadr (args);
4052 root 1.1
4053 root 1.16 s_retbool (find_slot_in_env (SCHEME_A_ x, car (args), 1) != NIL);
4054 root 1.1
4055     case OP_SET0: /* set! */
4056     if (is_immutable (car (SCHEME_V->code)))
4057     Error_1 ("set!: unable to alter immutable variable", car (SCHEME_V->code));
4058    
4059     s_save (SCHEME_A_ OP_SET1, NIL, car (SCHEME_V->code));
4060     SCHEME_V->code = cadr (SCHEME_V->code);
4061     s_goto (OP_EVAL);
4062    
4063     case OP_SET1: /* set! */
4064     y = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
4065    
4066     if (y != NIL)
4067     {
4068     set_slot_in_env (SCHEME_A_ y, SCHEME_V->value);
4069     s_return (SCHEME_V->value);
4070     }
4071     else
4072 root 1.2 Error_1 ("set!: unbound variable:", SCHEME_V->code);
4073 root 1.1
4074     case OP_BEGIN: /* begin */
4075     if (!is_pair (SCHEME_V->code))
4076 root 1.2 s_return (SCHEME_V->code);
4077 root 1.1
4078     if (cdr (SCHEME_V->code) != NIL)
4079 root 1.2 s_save (SCHEME_A_ OP_BEGIN, NIL, cdr (SCHEME_V->code));
4080 root 1.1
4081     SCHEME_V->code = car (SCHEME_V->code);
4082     s_goto (OP_EVAL);
4083    
4084     case OP_IF0: /* if */
4085     s_save (SCHEME_A_ OP_IF1, NIL, cdr (SCHEME_V->code));
4086     SCHEME_V->code = car (SCHEME_V->code);
4087     s_goto (OP_EVAL);
4088    
4089     case OP_IF1: /* if */
4090     if (is_true (SCHEME_V->value))
4091     SCHEME_V->code = car (SCHEME_V->code);
4092     else
4093 root 1.18 SCHEME_V->code = cadr (SCHEME_V->code); /* (if #f 1) ==> () because * car(NIL) = NIL */
4094 root 1.61
4095 root 1.1 s_goto (OP_EVAL);
4096    
4097     case OP_LET0: /* let */
4098     SCHEME_V->args = NIL;
4099     SCHEME_V->value = SCHEME_V->code;
4100     SCHEME_V->code = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code);
4101     s_goto (OP_LET1);
4102    
4103     case OP_LET1: /* let (calculate parameters) */
4104 root 1.64 case OP_LET1REC: /* letrec (calculate parameters) */
4105 root 1.16 args = cons (SCHEME_V->value, args);
4106 root 1.1
4107     if (is_pair (SCHEME_V->code)) /* continue */
4108     {
4109     if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
4110 root 1.64 Error_1 ("Bad syntax of binding spec in let/letrec:", car (SCHEME_V->code));
4111 root 1.1
4112 root 1.64 s_save (SCHEME_A_ op, args, cdr (SCHEME_V->code));
4113 root 1.1 SCHEME_V->code = cadar (SCHEME_V->code);
4114     SCHEME_V->args = NIL;
4115     s_goto (OP_EVAL);
4116     }
4117 root 1.64
4118     /* end */
4119     args = reverse_in_place (SCHEME_A_ NIL, args);
4120     SCHEME_V->code = car (args);
4121     SCHEME_V->args = cdr (args);
4122     s_goto (op == OP_LET1 ? OP_LET2 : OP_LET2REC);
4123 root 1.1
4124     case OP_LET2: /* let */
4125     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
4126    
4127 root 1.16 for (x = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code), y = args;
4128 root 1.1 y != NIL; x = cdr (x), y = cdr (y))
4129 root 1.39 new_slot_in_env (SCHEME_A_ caar (x), car (y));
4130 root 1.1
4131     if (is_symbol (car (SCHEME_V->code))) /* named let */
4132     {
4133 root 1.16 for (x = cadr (SCHEME_V->code), args = NIL; x != NIL; x = cdr (x))
4134 root 1.1 {
4135     if (!is_pair (x))
4136 root 1.64 Error_1 ("Bad syntax of binding in let:", x);
4137 root 1.1
4138     if (!is_list (SCHEME_A_ car (x)))
4139 root 1.64 Error_1 ("Bad syntax of binding in let:", car (x));
4140 root 1.1
4141 root 1.16 args = cons (caar (x), args);
4142 root 1.1 }
4143    
4144 root 1.16 x = mk_closure (SCHEME_A_ cons (reverse_in_place (SCHEME_A_ NIL, args), cddr (SCHEME_V->code)),
4145     SCHEME_V->envir);
4146 root 1.1 new_slot_in_env (SCHEME_A_ car (SCHEME_V->code), x);
4147     SCHEME_V->code = cddr (SCHEME_V->code);
4148     }
4149     else
4150     {
4151     SCHEME_V->code = cdr (SCHEME_V->code);
4152     }
4153    
4154 root 1.16 SCHEME_V->args = NIL;
4155 root 1.1 s_goto (OP_BEGIN);
4156    
4157     case OP_LET0AST: /* let* */
4158     if (car (SCHEME_V->code) == NIL)
4159     {
4160     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
4161     SCHEME_V->code = cdr (SCHEME_V->code);
4162     s_goto (OP_BEGIN);
4163     }
4164    
4165     if (!is_pair (car (SCHEME_V->code)) || !is_pair (caar (SCHEME_V->code)) || !is_pair (cdaar (SCHEME_V->code)))
4166 root 1.64 Error_1 ("Bad syntax of binding spec in let*:", car (SCHEME_V->code));
4167 root 1.1
4168     s_save (SCHEME_A_ OP_LET1AST, cdr (SCHEME_V->code), car (SCHEME_V->code));
4169     SCHEME_V->code = car (cdaar (SCHEME_V->code));
4170     s_goto (OP_EVAL);
4171    
4172     case OP_LET1AST: /* let* (make new frame) */
4173     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
4174     s_goto (OP_LET2AST);
4175    
4176     case OP_LET2AST: /* let* (calculate parameters) */
4177     new_slot_in_env (SCHEME_A_ caar (SCHEME_V->code), SCHEME_V->value);
4178     SCHEME_V->code = cdr (SCHEME_V->code);
4179    
4180     if (is_pair (SCHEME_V->code)) /* continue */
4181     {
4182 root 1.16 s_save (SCHEME_A_ OP_LET2AST, args, SCHEME_V->code);
4183 root 1.1 SCHEME_V->code = cadar (SCHEME_V->code);
4184     SCHEME_V->args = NIL;
4185     s_goto (OP_EVAL);
4186     }
4187 root 1.64
4188     /* end */
4189    
4190     SCHEME_V->code = args;
4191     SCHEME_V->args = NIL;
4192     s_goto (OP_BEGIN);
4193 root 1.1
4194     case OP_LET0REC: /* letrec */
4195     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
4196     SCHEME_V->args = NIL;
4197     SCHEME_V->value = SCHEME_V->code;
4198     SCHEME_V->code = car (SCHEME_V->code);
4199     s_goto (OP_LET1REC);
4200    
4201 root 1.64 /* OP_LET1REC handled by OP_LET1 */
4202 root 1.1
4203     case OP_LET2REC: /* letrec */
4204 root 1.16 for (x = car (SCHEME_V->code), y = args; y != NIL; x = cdr (x), y = cdr (y))
4205 root 1.2 new_slot_in_env (SCHEME_A_ caar (x), car (y));
4206 root 1.1
4207     SCHEME_V->code = cdr (SCHEME_V->code);
4208     SCHEME_V->args = NIL;
4209     s_goto (OP_BEGIN);
4210    
4211     case OP_COND0: /* cond */
4212     if (!is_pair (SCHEME_V->code))
4213 root 1.2 Error_0 ("syntax error in cond");
4214 root 1.1
4215     s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
4216     SCHEME_V->code = caar (SCHEME_V->code);
4217     s_goto (OP_EVAL);
4218    
4219     case OP_COND1: /* cond */
4220     if (is_true (SCHEME_V->value))
4221     {
4222     if ((SCHEME_V->code = cdar (SCHEME_V->code)) == NIL)
4223 root 1.2 s_return (SCHEME_V->value);
4224 root 1.1
4225     if (car (SCHEME_V->code) == SCHEME_V->FEED_TO)
4226     {
4227     if (!is_pair (cdr (SCHEME_V->code)))
4228 root 1.2 Error_0 ("syntax error in cond");
4229 root 1.1
4230     x = cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL));
4231     SCHEME_V->code = cons (cadr (SCHEME_V->code), cons (x, NIL));
4232     s_goto (OP_EVAL);
4233     }
4234    
4235     s_goto (OP_BEGIN);
4236     }
4237     else
4238     {
4239     if ((SCHEME_V->code = cdr (SCHEME_V->code)) == NIL)
4240 root 1.2 s_return (NIL);
4241 root 1.61
4242     s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
4243     SCHEME_V->code = caar (SCHEME_V->code);
4244     s_goto (OP_EVAL);
4245 root 1.1 }
4246    
4247     case OP_DELAY: /* delay */
4248     x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
4249     set_typeflag (x, T_PROMISE);
4250     s_return (x);
4251    
4252     case OP_AND0: /* and */
4253     if (SCHEME_V->code == NIL)
4254 root 1.2 s_return (S_T);
4255 root 1.1
4256     s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
4257     SCHEME_V->code = car (SCHEME_V->code);
4258     s_goto (OP_EVAL);
4259    
4260     case OP_AND1: /* and */
4261     if (is_false (SCHEME_V->value))
4262 root 1.2 s_return (SCHEME_V->value);
4263 root 1.1 else if (SCHEME_V->code == NIL)
4264 root 1.2 s_return (SCHEME_V->value);
4265 root 1.61
4266     s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
4267     SCHEME_V->code = car (SCHEME_V->code);
4268     s_goto (OP_EVAL);
4269 root 1.1
4270     case OP_OR0: /* or */
4271     if (SCHEME_V->code == NIL)
4272 root 1.2 s_return (S_F);
4273 root 1.1
4274     s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
4275     SCHEME_V->code = car (SCHEME_V->code);
4276     s_goto (OP_EVAL);
4277    
4278     case OP_OR1: /* or */
4279     if (is_true (SCHEME_V->value))
4280 root 1.2 s_return (SCHEME_V->value);
4281 root 1.1 else if (SCHEME_V->code == NIL)
4282 root 1.2 s_return (SCHEME_V->value);
4283 root 1.61
4284     s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
4285     SCHEME_V->code = car (SCHEME_V->code);
4286     s_goto (OP_EVAL);
4287 root 1.1
4288     case OP_C0STREAM: /* cons-stream */
4289     s_save (SCHEME_A_ OP_C1STREAM, NIL, cdr (SCHEME_V->code));
4290     SCHEME_V->code = car (SCHEME_V->code);
4291     s_goto (OP_EVAL);
4292    
4293     case OP_C1STREAM: /* cons-stream */
4294 root 1.16 SCHEME_V->args = SCHEME_V->value; /* save SCHEME_V->value to register args for gc */
4295 root 1.1 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
4296     set_typeflag (x, T_PROMISE);
4297 root 1.16 s_return (cons (args, x));
4298 root 1.1
4299     case OP_MACRO0: /* macro */
4300     if (is_pair (car (SCHEME_V->code)))
4301     {
4302     x = caar (SCHEME_V->code);
4303     SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
4304     }
4305     else
4306     {
4307     x = car (SCHEME_V->code);
4308     SCHEME_V->code = cadr (SCHEME_V->code);
4309     }
4310    
4311     if (!is_symbol (x))
4312 root 1.2 Error_0 ("variable is not a symbol");
4313 root 1.1
4314     s_save (SCHEME_A_ OP_MACRO1, NIL, x);
4315     s_goto (OP_EVAL);
4316    
4317     case OP_MACRO1: /* macro */
4318     set_typeflag (SCHEME_V->value, T_MACRO);
4319     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
4320    
4321     if (x != NIL)
4322 root 1.2 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
4323 root 1.1 else
4324 root 1.2 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
4325 root 1.1
4326     s_return (SCHEME_V->code);
4327    
4328     case OP_CASE0: /* case */
4329     s_save (SCHEME_A_ OP_CASE1, NIL, cdr (SCHEME_V->code));
4330     SCHEME_V->code = car (SCHEME_V->code);
4331     s_goto (OP_EVAL);
4332    
4333     case OP_CASE1: /* case */
4334     for (x = SCHEME_V->code; x != NIL; x = cdr (x))
4335     {
4336     if (!is_pair (y = caar (x)))
4337 root 1.2 break;
4338 root 1.1
4339     for (; y != NIL; y = cdr (y))
4340 root 1.16 if (eqv (car (y), SCHEME_V->value))
4341 root 1.2 break;
4342 root 1.1
4343     if (y != NIL)
4344 root 1.2 break;
4345 root 1.1 }
4346    
4347     if (x != NIL)
4348     {
4349     if (is_pair (caar (x)))
4350     {
4351     SCHEME_V->code = cdar (x);
4352     s_goto (OP_BEGIN);
4353     }
4354     else /* else */
4355     {
4356     s_save (SCHEME_A_ OP_CASE2, NIL, cdar (x));
4357     SCHEME_V->code = caar (x);
4358     s_goto (OP_EVAL);
4359     }
4360     }
4361 root 1.61
4362     s_return (NIL);
4363 root 1.1
4364     case OP_CASE2: /* case */
4365     if (is_true (SCHEME_V->value))
4366 root 1.2 s_goto (OP_BEGIN);
4367 root 1.61
4368     s_return (NIL);
4369 root 1.1
4370     case OP_PAPPLY: /* apply */
4371 root 1.16 SCHEME_V->code = car (args);
4372     SCHEME_V->args = list_star (SCHEME_A_ cdr (args));
4373     /*SCHEME_V->args = cadr(args); */
4374 root 1.1 s_goto (OP_APPLY);
4375    
4376     case OP_PEVAL: /* eval */
4377 root 1.16 if (cdr (args) != NIL)
4378     SCHEME_V->envir = cadr (args);
4379 root 1.1
4380 root 1.16 SCHEME_V->code = car (args);
4381 root 1.1 s_goto (OP_EVAL);
4382    
4383     case OP_CONTINUATION: /* call-with-current-continuation */
4384 root 1.16 SCHEME_V->code = car (args);
4385 root 1.7 SCHEME_V->args = cons (mk_continuation (SCHEME_A_ ss_get_cont (SCHEME_A)), NIL);
4386 root 1.1 s_goto (OP_APPLY);
4387     }
4388    
4389 root 1.24 if (USE_ERROR_CHECKING) abort ();
4390 root 1.1 }
4391    
4392 root 1.60 /* math, cxr */
4393     ecb_hot static int
4394 root 1.20 opexe_1 (SCHEME_P_ enum scheme_opcodes op)
4395 root 1.1 {
4396 root 1.16 pointer args = SCHEME_V->args;
4397     pointer x = car (args);
4398 root 1.1 num v;
4399    
4400     switch (op)
4401     {
4402     #if USE_MATH
4403     case OP_INEX2EX: /* inexact->exact */
4404 root 1.55 if (!is_integer (x))
4405     {
4406     RVALUE r = rvalue_unchecked (x);
4407 root 1.26
4408 root 1.55 if (r == (RVALUE)(IVALUE)r)
4409     x = mk_integer (SCHEME_A_ rvalue_unchecked (x));
4410     else
4411     Error_1 ("inexact->exact: not integral:", x);
4412     }
4413 root 1.26
4414 root 1.55 s_return (x);
4415 root 1.1
4416 root 1.56 case OP_FLOOR: s_return (mk_real (SCHEME_A_ floor (rvalue (x))));
4417     case OP_CEILING: s_return (mk_real (SCHEME_A_ ceil (rvalue (x))));
4418     case OP_TRUNCATE: s_return (mk_real (SCHEME_A_ trunc (rvalue (x))));
4419     case OP_ROUND: s_return (mk_real (SCHEME_A_ nearbyint (rvalue (x))));
4420    
4421     case OP_SQRT: s_return (mk_real (SCHEME_A_ sqrt (rvalue (x))));
4422 root 1.16 case OP_EXP: s_return (mk_real (SCHEME_A_ exp (rvalue (x))));
4423 root 1.55 case OP_LOG: s_return (mk_real (SCHEME_A_ log (rvalue (x))
4424     / (cadr (args) == NIL ? 1 : log (rvalue (cadr (args))))));
4425 root 1.16 case OP_SIN: s_return (mk_real (SCHEME_A_ sin (rvalue (x))));
4426     case OP_COS: s_return (mk_real (SCHEME_A_ cos (rvalue (x))));
4427     case OP_TAN: s_return (mk_real (SCHEME_A_ tan (rvalue (x))));
4428     case OP_ASIN: s_return (mk_real (SCHEME_A_ asin (rvalue (x))));
4429     case OP_ACOS: s_return (mk_real (SCHEME_A_ acos (rvalue (x))));
4430 root 1.1
4431     case OP_ATAN:
4432 root 1.55 s_return (mk_real (SCHEME_A_
4433     cdr (args) == NIL
4434     ? atan (rvalue (x))
4435     : atan2 (rvalue (x), rvalue (cadr (args)))));
4436 root 1.1
4437     case OP_EXPT:
4438     {
4439     RVALUE result;
4440     int real_result = 1;
4441 root 1.16 pointer y = cadr (args);
4442 root 1.1
4443 root 1.25 if (is_integer (x) && is_integer (y))
4444 root 1.1 real_result = 0;
4445    
4446     /* This 'if' is an R5RS compatibility fix. */
4447     /* NOTE: Remove this 'if' fix for R6RS. */
4448     if (rvalue (x) == 0 && rvalue (y) < 0)
4449 root 1.16 result = 0;
4450 root 1.1 else
4451 root 1.2 result = pow (rvalue (x), rvalue (y));
4452 root 1.1
4453     /* Before returning integer result make sure we can. */
4454     /* If the test fails, result is too big for integer. */
4455     if (!real_result)
4456     {
4457 root 1.16 long result_as_long = result;
4458 root 1.1
4459 root 1.26 if (result != result_as_long)
4460 root 1.1 real_result = 1;
4461     }
4462    
4463     if (real_result)
4464 root 1.2 s_return (mk_real (SCHEME_A_ result));
4465 root 1.1 else
4466 root 1.2 s_return (mk_integer (SCHEME_A_ result));
4467 root 1.1 }
4468     #endif
4469    
4470     case OP_ADD: /* + */
4471     v = num_zero;
4472    
4473 root 1.16 for (x = args; x != NIL; x = cdr (x))
4474 root 1.23 v = num_op (NUM_ADD, v, nvalue (car (x)));
4475 root 1.1
4476     s_return (mk_number (SCHEME_A_ v));
4477    
4478     case OP_MUL: /* * */
4479     v = num_one;
4480    
4481 root 1.16 for (x = args; x != NIL; x = cdr (x))
4482 root 1.23 v = num_op (NUM_MUL, v, nvalue (car (x)));
4483 root 1.1
4484     s_return (mk_number (SCHEME_A_ v));
4485    
4486     case OP_SUB: /* - */
4487 root 1.16 if (cdr (args) == NIL)
4488 root 1.1 {
4489 root 1.16 x = args;
4490 root 1.1 v = num_zero;
4491     }
4492     else
4493     {
4494 root 1.16 x = cdr (args);
4495     v = nvalue (car (args));
4496 root 1.1 }
4497    
4498     for (; x != NIL; x = cdr (x))
4499 root 1.23 v = num_op (NUM_SUB, v, nvalue (car (x)));
4500 root 1.1
4501     s_return (mk_number (SCHEME_A_ v));
4502    
4503     case OP_DIV: /* / */
4504 root 1.16 if (cdr (args) == NIL)
4505 root 1.1 {
4506 root 1.16 x = args;
4507 root 1.1 v = num_one;
4508     }
4509     else
4510     {
4511 root 1.16 x = cdr (args);
4512     v = nvalue (car (args));
4513 root 1.1 }
4514    
4515     for (; x != NIL; x = cdr (x))
4516 root 1.23 if (!is_zero_rvalue (rvalue (car (x))))
4517     v = num_div (v, nvalue (car (x)));
4518     else
4519     Error_0 ("/: division by zero");
4520 root 1.1
4521     s_return (mk_number (SCHEME_A_ v));
4522    
4523     case OP_INTDIV: /* quotient */
4524 root 1.16 if (cdr (args) == NIL)
4525 root 1.1 {
4526 root 1.16 x = args;
4527 root 1.1 v = num_one;
4528     }
4529     else
4530     {
4531 root 1.16 x = cdr (args);
4532     v = nvalue (car (args));
4533 root 1.1 }
4534    
4535     for (; x != NIL; x = cdr (x))
4536     {
4537     if (ivalue (car (x)) != 0)
4538 root 1.23 v = num_op (NUM_INTDIV, v, nvalue (car (x)));
4539 root 1.1 else
4540     Error_0 ("quotient: division by zero");
4541     }
4542    
4543     s_return (mk_number (SCHEME_A_ v));
4544    
4545     case OP_REM: /* remainder */
4546 root 1.16 v = nvalue (x);
4547 root 1.1
4548 root 1.16 if (ivalue (cadr (args)) != 0)
4549     v = num_rem (v, nvalue (cadr (args)));
4550 root 1.1 else
4551     Error_0 ("remainder: division by zero");
4552    
4553     s_return (mk_number (SCHEME_A_ v));
4554    
4555     case OP_MOD: /* modulo */
4556 root 1.16 v = nvalue (x);
4557 root 1.1
4558 root 1.16 if (ivalue (cadr (args)) != 0)
4559     v = num_mod (v, nvalue (cadr (args)));
4560 root 1.1 else
4561     Error_0 ("modulo: division by zero");
4562    
4563     s_return (mk_number (SCHEME_A_ v));
4564    
4565 root 1.46 /* the compiler will optimize this mess... */
4566     case OP_CAR: op_car: s_return (car (x));
4567     case OP_CDR: op_cdr: s_return (cdr (x));
4568     case OP_CAAR: op_caar: x = car (x); goto op_car;
4569     case OP_CADR: op_cadr: x = cdr (x); goto op_car;
4570     case OP_CDAR: op_cdar: x = car (x); goto op_cdr;
4571     case OP_CDDR: op_cddr: x = cdr (x); goto op_cdr;
4572     case OP_CAAAR: op_caaar: x = car (x); goto op_caar;
4573     case OP_CAADR: op_caadr: x = cdr (x); goto op_caar;
4574     case OP_CADAR: op_cadar: x = car (x); goto op_cadr;
4575     case OP_CADDR: op_caddr: x = cdr (x); goto op_cadr;
4576     case OP_CDAAR: op_cdaar: x = car (x); goto op_cdar;
4577     case OP_CDADR: op_cdadr: x = cdr (x); goto op_cdar;
4578     case OP_CDDAR: op_cddar: x = car (x); goto op_cddr;
4579     case OP_CDDDR: op_cdddr: x = cdr (x); goto op_cddr;
4580     case OP_CAAAAR: x = car (x); goto op_caaar;
4581     case OP_CAAADR: x = cdr (x); goto op_caaar;
4582     case OP_CAADAR: x = car (x); goto op_caadr;
4583     case OP_CAADDR: x = cdr (x); goto op_caadr;
4584     case OP_CADAAR: x = car (x); goto op_cadar;
4585     case OP_CADADR: x = cdr (x); goto op_cadar;
4586     case OP_CADDAR: x = car (x); goto op_caddr;
4587     case OP_CADDDR: x = cdr (x); goto op_caddr;
4588     case OP_CDAAAR: x = car (x); goto op_cdaar;
4589     case OP_CDAADR: x = cdr (x); goto op_cdaar;
4590     case OP_CDADAR: x = car (x); goto op_cdadr;
4591     case OP_CDADDR: x = cdr (x); goto op_cdadr;
4592     case OP_CDDAAR: x = car (x); goto op_cddar;
4593     case OP_CDDADR: x = cdr (x); goto op_cddar;
4594     case OP_CDDDAR: x = car (x); goto op_cdddr;
4595     case OP_CDDDDR: x = cdr (x); goto op_cdddr;
4596 root 1.1
4597     case OP_CONS: /* cons */
4598 root 1.16 set_cdr (args, cadr (args));
4599     s_return (args);
4600 root 1.1
4601     case OP_SETCAR: /* set-car! */
4602 root 1.16 if (!is_immutable (x))
4603 root 1.1 {
4604 root 1.16 set_car (x, cadr (args));
4605     s_return (car (args));
4606 root 1.1 }
4607     else
4608     Error_0 ("set-car!: unable to alter immutable pair");
4609    
4610     case OP_SETCDR: /* set-cdr! */
4611 root 1.16 if (!is_immutable (x))
4612 root 1.1 {
4613 root 1.16 set_cdr (x, cadr (args));
4614     s_return (car (args));
4615 root 1.1 }
4616     else
4617     Error_0 ("set-cdr!: unable to alter immutable pair");
4618    
4619     case OP_CHAR2INT: /* char->integer */
4620 root 1.26 s_return (mk_integer (SCHEME_A_ ivalue_unchecked (x)));
4621 root 1.1
4622     case OP_INT2CHAR: /* integer->char */
4623 root 1.26 s_return (mk_character (SCHEME_A_ ivalue_unchecked (x)));
4624 root 1.1
4625     case OP_CHARUPCASE:
4626     {
4627 root 1.26 unsigned char c = ivalue_unchecked (x);
4628 root 1.1 c = toupper (c);
4629 root 1.2 s_return (mk_character (SCHEME_A_ c));
4630 root 1.1 }
4631    
4632     case OP_CHARDNCASE:
4633     {
4634 root 1.26 unsigned char c = ivalue_unchecked (x);
4635 root 1.1 c = tolower (c);
4636 root 1.2 s_return (mk_character (SCHEME_A_ c));
4637 root 1.1 }
4638    
4639     case OP_STR2SYM: /* string->symbol */
4640 root 1.16 s_return (mk_symbol (SCHEME_A_ strvalue (x)));
4641 root 1.1
4642     case OP_STR2ATOM: /* string->atom */
4643     {
4644 root 1.16 char *s = strvalue (x);
4645 root 1.1 long pf = 0;
4646    
4647 root 1.16 if (cdr (args) != NIL)
4648 root 1.1 {
4649 root 1.16 /* we know cadr(args) is a natural number */
4650 root 1.1 /* see if it is 2, 8, 10, or 16, or error */
4651 root 1.16 pf = ivalue_unchecked (cadr (args));
4652 root 1.1
4653     if (pf == 16 || pf == 10 || pf == 8 || pf == 2)
4654     {
4655     /* base is OK */
4656     }
4657     else
4658 root 1.2 pf = -1;
4659 root 1.1 }
4660    
4661     if (pf < 0)
4662 root 1.16 Error_1 ("string->atom: bad base:", cadr (args));
4663 root 1.1 else if (*s == '#') /* no use of base! */
4664 root 1.2 s_return (mk_sharp_const (SCHEME_A_ s + 1));
4665 root 1.1 else
4666     {
4667     if (pf == 0 || pf == 10)
4668 root 1.2 s_return (mk_atom (SCHEME_A_ s));
4669 root 1.1 else
4670     {
4671     char *ep;
4672     long iv = strtol (s, &ep, (int) pf);
4673    
4674     if (*ep == 0)
4675 root 1.2 s_return (mk_integer (SCHEME_A_ iv));
4676 root 1.1 else
4677 root 1.2 s_return (S_F);
4678 root 1.1 }
4679     }
4680     }
4681    
4682     case OP_SYM2STR: /* symbol->string */
4683 root 1.16 x = mk_string (SCHEME_A_ symname (x));
4684 root 1.1 setimmutable (x);
4685     s_return (x);
4686    
4687     case OP_ATOM2STR: /* atom->string */
4688     {
4689     long pf = 0;
4690    
4691 root 1.16 if (cdr (args) != NIL)
4692 root 1.1 {
4693 root 1.16 /* we know cadr(args) is a natural number */
4694 root 1.1 /* see if it is 2, 8, 10, or 16, or error */
4695 root 1.16 pf = ivalue_unchecked (cadr (args));
4696 root 1.1
4697     if (is_number (x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2))
4698     {
4699     /* base is OK */
4700     }
4701     else
4702 root 1.2 pf = -1;
4703 root 1.1 }
4704    
4705     if (pf < 0)
4706 root 1.16 Error_1 ("atom->string: bad base:", cadr (args));
4707 root 1.1 else if (is_number (x) || is_character (x) || is_string (x) || is_symbol (x))
4708     {
4709     char *p;
4710     int len;
4711    
4712 root 1.2 atom2str (SCHEME_A_ x, pf, &p, &len);
4713 root 1.1 s_return (mk_counted_string (SCHEME_A_ p, len));
4714     }
4715     else
4716 root 1.2 Error_1 ("atom->string: not an atom:", x);
4717 root 1.1 }
4718    
4719     case OP_MKSTRING: /* make-string */
4720     {
4721 root 1.26 int fill = cdr (args) != NIL ? charvalue (cadr (args)) : ' ';
4722     int len = ivalue_unchecked (x);
4723 root 1.1
4724 root 1.17 s_return (mk_empty_string (SCHEME_A_ len, fill));
4725 root 1.1 }
4726    
4727     case OP_STRLEN: /* string-length */
4728 root 1.16 s_return (mk_integer (SCHEME_A_ strlength (x)));
4729 root 1.1
4730     case OP_STRREF: /* string-ref */
4731     {
4732 root 1.26 char *str = strvalue (x);
4733     int index = ivalue_unchecked (cadr (args));
4734 root 1.1
4735 root 1.16 if (index >= strlength (x))
4736     Error_1 ("string-ref: out of bounds:", cadr (args));
4737 root 1.1
4738 root 1.17 s_return (mk_character (SCHEME_A_ ((unsigned char *)str)[index]));
4739 root 1.1 }
4740    
4741     case OP_STRSET: /* string-set! */
4742     {
4743 root 1.26 char *str = strvalue (x);
4744     int index = ivalue_unchecked (cadr (args));
4745 root 1.1 int c;
4746    
4747 root 1.16 if (is_immutable (x))
4748     Error_1 ("string-set!: unable to alter immutable string:", x);
4749 root 1.1
4750 root 1.16 if (index >= strlength (x))
4751     Error_1 ("string-set!: out of bounds:", cadr (args));
4752 root 1.1
4753 root 1.16 c = charvalue (caddr (args));
4754 root 1.1
4755 root 1.17 str[index] = c;
4756 root 1.16 s_return (car (args));
4757 root 1.1 }
4758    
4759     case OP_STRAPPEND: /* string-append */
4760     {
4761     /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4762     int len = 0;
4763     pointer newstr;
4764     char *pos;
4765    
4766     /* compute needed length for new string */
4767 root 1.16 for (x = args; x != NIL; x = cdr (x))
4768 root 1.2 len += strlength (car (x));
4769 root 1.1
4770     newstr = mk_empty_string (SCHEME_A_ len, ' ');
4771    
4772     /* store the contents of the argument strings into the new string */
4773 root 1.16 for (pos = strvalue (newstr), x = args; x != NIL; pos += strlength (car (x)), x = cdr (x))
4774 root 1.2 memcpy (pos, strvalue (car (x)), strlength (car (x)));
4775 root 1.1
4776     s_return (newstr);
4777     }
4778    
4779 root 1.57 case OP_STRING_COPY: /* substring/string-copy */
4780 root 1.1 {
4781 root 1.26 char *str = strvalue (x);
4782 root 1.57 int index0 = cadr (args) == NIL ? 0 : ivalue_unchecked (cadr (args));
4783 root 1.1 int index1;
4784     int len;
4785    
4786 root 1.16 if (index0 > strlength (x))
4787 root 1.57 Error_1 ("string->copy: start out of bounds:", cadr (args));
4788 root 1.1
4789 root 1.16 if (cddr (args) != NIL)
4790 root 1.1 {
4791 root 1.26 index1 = ivalue_unchecked (caddr (args));
4792 root 1.1
4793 root 1.16 if (index1 > strlength (x) || index1 < index0)
4794 root 1.57 Error_1 ("string->copy: end out of bounds:", caddr (args));
4795 root 1.1 }
4796     else
4797 root 1.16 index1 = strlength (x);
4798 root 1.1
4799     len = index1 - index0;
4800 root 1.57 x = mk_counted_string (SCHEME_A_ str + index0, len);
4801 root 1.1
4802     s_return (x);
4803     }
4804    
4805     case OP_VECTOR: /* vector */
4806     {
4807     int i;
4808     pointer vec;
4809 root 1.16 int len = list_length (SCHEME_A_ args);
4810 root 1.1
4811     if (len < 0)
4812 root 1.16 Error_1 ("vector: not a proper list:", args);
4813 root 1.1
4814     vec = mk_vector (SCHEME_A_ len);
4815    
4816     #if USE_ERROR_CHECKING
4817     if (SCHEME_V->no_memory)
4818     s_return (S_SINK);
4819     #endif
4820    
4821 root 1.16 for (x = args, i = 0; is_pair (x); x = cdr (x), i++)
4822 root 1.28 vector_set (vec, i, car (x));
4823 root 1.1
4824     s_return (vec);
4825     }
4826    
4827     case OP_MKVECTOR: /* make-vector */
4828     {
4829     pointer fill = NIL;
4830     pointer vec;
4831 root 1.26 int len = ivalue_unchecked (x);
4832 root 1.1
4833 root 1.16 if (cdr (args) != NIL)
4834     fill = cadr (args);
4835 root 1.1
4836     vec = mk_vector (SCHEME_A_ len);
4837    
4838     #if USE_ERROR_CHECKING
4839     if (SCHEME_V->no_memory)
4840     s_return (S_SINK);
4841     #endif
4842    
4843     if (fill != NIL)
4844 root 1.28 fill_vector (vec, 0, fill);
4845 root 1.1
4846     s_return (vec);
4847     }
4848    
4849     case OP_VECLEN: /* vector-length */
4850 root 1.16 s_return (mk_integer (SCHEME_A_ veclength (x)));
4851 root 1.1
4852 root 1.37 case OP_VECRESIZE:
4853     vector_resize (x, ivalue_unchecked (cadr (args)), caddr (args));
4854     s_return (x);
4855    
4856 root 1.1 case OP_VECREF: /* vector-ref */
4857     {
4858 root 1.26 int index = ivalue_unchecked (cadr (args));
4859 root 1.1
4860 root 1.16 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4861     Error_1 ("vector-ref: out of bounds:", cadr (args));
4862 root 1.1
4863 root 1.28 s_return (vector_get (x, index));
4864 root 1.1 }
4865    
4866     case OP_VECSET: /* vector-set! */
4867     {
4868 root 1.26 int index = ivalue_unchecked (cadr (args));
4869 root 1.1
4870 root 1.16 if (is_immutable (x))
4871     Error_1 ("vector-set!: unable to alter immutable vector:", x);
4872 root 1.1
4873 root 1.16 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4874     Error_1 ("vector-set!: out of bounds:", cadr (args));
4875 root 1.1
4876 root 1.28 vector_set (x, index, caddr (args));
4877 root 1.16 s_return (x);
4878 root 1.1 }
4879     }
4880    
4881 root 1.24 if (USE_ERROR_CHECKING) abort ();
4882 root 1.1 }
4883    
4884 root 1.60 /* relational ops */
4885     ecb_hot static int
4886 root 1.20 opexe_2 (SCHEME_P_ enum scheme_opcodes op)
4887 root 1.1 {
4888 root 1.14 pointer x = SCHEME_V->args;
4889 root 1.1
4890 root 1.14 for (;;)
4891 root 1.1 {
4892 root 1.14 num v = nvalue (car (x));
4893     x = cdr (x);
4894 root 1.1
4895 root 1.14 if (x == NIL)
4896     break;
4897 root 1.1
4898 root 1.14 int r = num_cmp (v, nvalue (car (x)));
4899 root 1.1
4900 root 1.14 switch (op)
4901     {
4902     case OP_NUMEQ: r = r == 0; break;
4903     case OP_LESS: r = r < 0; break;
4904     case OP_GRE: r = r > 0; break;
4905     case OP_LEQ: r = r <= 0; break;
4906     case OP_GEQ: r = r >= 0; break;
4907     }
4908 root 1.1
4909 root 1.14 if (!r)
4910     s_return (S_F);
4911     }
4912 root 1.1
4913 root 1.14 s_return (S_T);
4914     }
4915 root 1.1
4916 root 1.60 /* predicates */
4917     ecb_hot static int
4918 root 1.14 opexe_3 (SCHEME_P_ enum scheme_opcodes op)
4919     {
4920 root 1.16 pointer args = SCHEME_V->args;
4921     pointer a = car (args);
4922     pointer d = cdr (args);
4923 root 1.14 int r;
4924 root 1.1
4925 root 1.14 switch (op)
4926     {
4927 root 1.43 case OP_NOT: /* not */ r = is_false (a) ; break;
4928     case OP_BOOLP: /* boolean? */ r = a == S_F || a == S_T ; break;
4929     case OP_EOFOBJP: /* eof-object? */ r = a == S_EOF ; break;
4930     case OP_NULLP: /* null? */ r = a == NIL ; break;
4931     case OP_SYMBOLP: /* symbol? */ r = is_symbol (a) ; break;
4932     case OP_GENSYMP: /* gensym? */ r = is_gensym (SCHEME_A_ a); break;
4933     case OP_NUMBERP: /* number? */ r = is_number (a) ; break;
4934     case OP_STRINGP: /* string? */ r = is_string (a) ; break;
4935     case OP_INTEGERP: /* integer? */ r = is_integer (a) ; break;
4936     case OP_REALP: /* real? */ r = is_number (a) ; break; /* all numbers are real */
4937     case OP_CHARP: /* char? */ r = is_character (a) ; break;
4938 root 1.14
4939 root 1.1 #if USE_CHAR_CLASSIFIERS
4940 root 1.26 case OP_CHARAP: /* char-alphabetic? */ r = Cisalpha (ivalue_unchecked (a)); break;
4941     case OP_CHARNP: /* char-numeric? */ r = Cisdigit (ivalue_unchecked (a)); break;
4942     case OP_CHARWP: /* char-whitespace? */ r = Cisspace (ivalue_unchecked (a)); break;
4943     case OP_CHARUP: /* char-upper-case? */ r = Cisupper (ivalue_unchecked (a)); break;
4944     case OP_CHARLP: /* char-lower-case? */ r = Cislower (ivalue_unchecked (a)); break;
4945 root 1.1 #endif
4946 root 1.14
4947 root 1.1 #if USE_PORTS
4948 root 1.15 case OP_PORTP: /* port? */ r = is_port (a) ; break;
4949     case OP_INPORTP: /* input-port? */ r = is_inport (a) ; break;
4950     case OP_OUTPORTP: /* output-port? */ r = is_outport (a); break;
4951 root 1.1 #endif
4952    
4953     case OP_PROCP: /* procedure? */
4954    
4955 root 1.14 /*--
4956     * continuation should be procedure by the example
4957     * (call-with-current-continuation procedure?) ==> #t
4958     * in R^3 report sec. 6.9
4959     */
4960     r = is_proc (a) || is_closure (a) || is_continuation (a) || is_foreign (a);
4961     break;
4962 root 1.1
4963 root 1.15 case OP_PAIRP: /* pair? */ r = is_pair (a) ; break;
4964     case OP_LISTP: /* list? */ r = list_length (SCHEME_A_ a) >= 0; break;
4965     case OP_ENVP: /* environment? */ r = is_environment (a) ; break;
4966     case OP_VECTORP: /* vector? */ r = is_vector (a) ; break;
4967 root 1.16 case OP_EQ: /* eq? */ r = a == cadr (args) ; break;
4968     case OP_EQV: /* eqv? */ r = eqv (a, cadr (args)) ; break;
4969 root 1.1 }
4970    
4971 root 1.14 s_retbool (r);
4972 root 1.1 }
4973    
4974 root 1.60 /* promises, list ops, ports */
4975     ecb_hot static int
4976 root 1.1 opexe_4 (SCHEME_P_ enum scheme_opcodes op)
4977     {
4978 root 1.16 pointer args = SCHEME_V->args;
4979     pointer a = car (args);
4980 root 1.1 pointer x, y;
4981    
4982     switch (op)
4983     {
4984     case OP_FORCE: /* force */
4985 root 1.16 SCHEME_V->code = a;
4986 root 1.1
4987     if (is_promise (SCHEME_V->code))
4988     {
4989     /* Should change type to closure here */
4990     s_save (SCHEME_A_ OP_SAVE_FORCED, NIL, SCHEME_V->code);
4991     SCHEME_V->args = NIL;
4992     s_goto (OP_APPLY);
4993     }
4994     else
4995 root 1.2 s_return (SCHEME_V->code);
4996 root 1.1
4997     case OP_SAVE_FORCED: /* Save forced value replacing promise */
4998 root 1.51 *CELL (SCHEME_V->code) = *CELL (SCHEME_V->value);
4999 root 1.1 s_return (SCHEME_V->value);
5000    
5001     #if USE_PORTS
5002    
5003 root 1.58 case OP_EOF_OBJECT: /* eof-object */
5004     s_return (S_EOF);
5005    
5006 root 1.1 case OP_WRITE: /* write */
5007     case OP_DISPLAY: /* display */
5008     case OP_WRITE_CHAR: /* write-char */
5009     if (is_pair (cdr (SCHEME_V->args)))
5010     {
5011     if (cadr (SCHEME_V->args) != SCHEME_V->outport)
5012     {
5013     x = cons (SCHEME_V->outport, NIL);
5014     s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
5015     SCHEME_V->outport = cadr (SCHEME_V->args);
5016     }
5017     }
5018    
5019 root 1.16 SCHEME_V->args = a;
5020 root 1.1
5021     if (op == OP_WRITE)
5022     SCHEME_V->print_flag = 1;
5023     else
5024     SCHEME_V->print_flag = 0;
5025    
5026     s_goto (OP_P0LIST);
5027    
5028 root 1.61 //TODO: move to scheme
5029 root 1.1 case OP_NEWLINE: /* newline */
5030 root 1.16 if (is_pair (args))
5031 root 1.1 {
5032 root 1.16 if (a != SCHEME_V->outport)
5033 root 1.1 {
5034     x = cons (SCHEME_V->outport, NIL);
5035     s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
5036 root 1.16 SCHEME_V->outport = a;
5037 root 1.1 }
5038     }
5039    
5040 root 1.61 putcharacter (SCHEME_A_ '\n');
5041 root 1.1 s_return (S_T);
5042     #endif
5043    
5044     case OP_ERR0: /* error */
5045     SCHEME_V->retcode = -1;
5046    
5047 root 1.16 if (!is_string (a))
5048 root 1.1 {
5049 root 1.16 args = cons (mk_string (SCHEME_A_ " -- "), args);
5050     setimmutable (car (args));
5051 root 1.1 }
5052    
5053     putstr (SCHEME_A_ "Error: ");
5054 root 1.16 putstr (SCHEME_A_ strvalue (car (args)));
5055     SCHEME_V->args = cdr (args);
5056 root 1.1 s_goto (OP_ERR1);
5057    
5058     case OP_ERR1: /* error */
5059 root 1.61 putcharacter (SCHEME_A_ ' ');
5060 root 1.1
5061 root 1.16 if (args != NIL)
5062 root 1.1 {
5063 root 1.16 s_save (SCHEME_A_ OP_ERR1, cdr (args), NIL);
5064     SCHEME_V->args = a;
5065 root 1.1 SCHEME_V->print_flag = 1;
5066     s_goto (OP_P0LIST);
5067     }
5068     else
5069     {
5070 root 1.61 putcharacter (SCHEME_A_ '\n');
5071 root 1.1
5072     if (SCHEME_V->interactive_repl)
5073 root 1.2 s_goto (OP_T0LVL);
5074 root 1.1 else
5075 root 1.20 return -1;
5076 root 1.1 }
5077    
5078     case OP_REVERSE: /* reverse */
5079 root 1.16 s_return (reverse (SCHEME_A_ a));
5080 root 1.1
5081     case OP_LIST_STAR: /* list* */
5082     s_return (list_star (SCHEME_A_ SCHEME_V->args));
5083    
5084     case OP_APPEND: /* append */
5085     x = NIL;
5086 root 1.16 y = args;
5087 root 1.1
5088     if (y == x)
5089     s_return (x);
5090    
5091     /* cdr() in the while condition is not a typo. If car() */
5092     /* is used (append '() 'a) will return the wrong result. */
5093     while (cdr (y) != NIL)
5094     {
5095     x = revappend (SCHEME_A_ x, car (y));
5096     y = cdr (y);
5097    
5098     if (x == S_F)
5099     Error_0 ("non-list argument to append");
5100     }
5101    
5102     s_return (reverse_in_place (SCHEME_A_ car (y), x));
5103    
5104     #if USE_PLIST
5105    
5106     case OP_PUT: /* put */
5107 root 1.16 if (!hasprop (a) || !hasprop (cadr (args)))
5108 root 1.2 Error_0 ("illegal use of put");
5109 root 1.1
5110 root 1.16 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
5111 root 1.1 {
5112     if (caar (x) == y)
5113 root 1.2 break;
5114 root 1.1 }
5115    
5116     if (x != NIL)
5117 root 1.16 cdar (x) = caddr (args);
5118 root 1.1 else
5119 root 1.16 symprop (a) = cons (cons (y, caddr (args)), symprop (a));
5120 root 1.1
5121     s_return (S_T);
5122    
5123     case OP_GET: /* get */
5124 root 1.16 if (!hasprop (a) || !hasprop (cadr (args)))
5125 root 1.1 Error_0 ("illegal use of get");
5126    
5127 root 1.16 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
5128 root 1.1 if (caar (x) == y)
5129     break;
5130    
5131     if (x != NIL)
5132     s_return (cdar (x));
5133     else
5134     s_return (NIL);
5135    
5136     #endif /* USE_PLIST */
5137    
5138     case OP_QUIT: /* quit */
5139 root 1.16 if (is_pair (args))
5140     SCHEME_V->retcode = ivalue (a);
5141 root 1.1
5142 root 1.20 return -1;
5143 root 1.1
5144     case OP_GC: /* gc */
5145     gc (SCHEME_A_ NIL, NIL);
5146     s_return (S_T);
5147    
5148     case OP_GCVERB: /* gc-verbose */
5149     {
5150     int was = SCHEME_V->gc_verbose;
5151    
5152 root 1.16 SCHEME_V->gc_verbose = (a != S_F);
5153 root 1.1 s_retbool (was);
5154     }
5155    
5156     case OP_NEWSEGMENT: /* new-segment */
5157 root 1.51 #if 0
5158 root 1.16 if (!is_pair (args) || !is_number (a))
5159 root 1.1 Error_0 ("new-segment: argument must be a number");
5160 root 1.51 #endif
5161     s_retbool (alloc_cellseg (SCHEME_A));
5162 root 1.1
5163     case OP_OBLIST: /* oblist */
5164     s_return (oblist_all_symbols (SCHEME_A));
5165    
5166     #if USE_PORTS
5167    
5168     case OP_CURR_INPORT: /* current-input-port */
5169     s_return (SCHEME_V->inport);
5170    
5171     case OP_CURR_OUTPORT: /* current-output-port */
5172     s_return (SCHEME_V->outport);
5173    
5174     case OP_OPEN_INFILE: /* open-input-file */
5175     case OP_OPEN_OUTFILE: /* open-output-file */
5176     case OP_OPEN_INOUTFILE: /* open-input-output-file */
5177     {
5178     int prop = 0;
5179     pointer p;
5180    
5181     switch (op)
5182     {
5183     case OP_OPEN_INFILE:
5184     prop = port_input;
5185     break;
5186    
5187     case OP_OPEN_OUTFILE:
5188     prop = port_output;
5189     break;
5190    
5191     case OP_OPEN_INOUTFILE:
5192     prop = port_input | port_output;
5193     break;
5194     }
5195    
5196 root 1.16 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
5197 root 1.1
5198 root 1.23 s_return (p == NIL ? S_F : p);
5199 root 1.1 }
5200    
5201     # if USE_STRING_PORTS
5202    
5203     case OP_OPEN_INSTRING: /* open-input-string */
5204     case OP_OPEN_INOUTSTRING: /* open-input-output-string */
5205     {
5206     int prop = 0;
5207     pointer p;
5208    
5209     switch (op)
5210     {
5211     case OP_OPEN_INSTRING:
5212     prop = port_input;
5213     break;
5214    
5215     case OP_OPEN_INOUTSTRING:
5216     prop = port_input | port_output;
5217     break;
5218     }
5219    
5220 root 1.16 p = port_from_string (SCHEME_A_ strvalue (a),
5221     strvalue (a) + strlength (a), prop);
5222 root 1.1
5223 root 1.23 s_return (p == NIL ? S_F : p);
5224 root 1.1 }
5225    
5226     case OP_OPEN_OUTSTRING: /* open-output-string */
5227     {
5228     pointer p;
5229    
5230 root 1.16 if (a == NIL)
5231 root 1.23 p = port_from_scratch (SCHEME_A);
5232 root 1.1 else
5233 root 1.23 p = port_from_string (SCHEME_A_ strvalue (a),
5234     strvalue (a) + strlength (a), port_output);
5235 root 1.1
5236 root 1.23 s_return (p == NIL ? S_F : p);
5237 root 1.1 }
5238    
5239     case OP_GET_OUTSTRING: /* get-output-string */
5240     {
5241 root 1.51 port *p = port (a);
5242 root 1.1
5243 root 1.51 if (p->kind & port_string)
5244 root 1.1 {
5245     off_t size;
5246     char *str;
5247    
5248     size = p->rep.string.curr - p->rep.string.start + 1;
5249     str = malloc (size);
5250    
5251     if (str != NULL)
5252     {
5253     pointer s;
5254    
5255     memcpy (str, p->rep.string.start, size - 1);
5256     str[size - 1] = '\0';
5257     s = mk_string (SCHEME_A_ str);
5258     free (str);
5259     s_return (s);
5260     }
5261     }
5262    
5263     s_return (S_F);
5264     }
5265    
5266     # endif
5267    
5268     case OP_CLOSE_INPORT: /* close-input-port */
5269 root 1.16 port_close (SCHEME_A_ a, port_input);
5270 root 1.1 s_return (S_T);
5271    
5272     case OP_CLOSE_OUTPORT: /* close-output-port */
5273 root 1.16 port_close (SCHEME_A_ a, port_output);
5274 root 1.1 s_return (S_T);
5275     #endif
5276    
5277     case OP_INT_ENV: /* interaction-environment */
5278     s_return (SCHEME_V->global_env);
5279    
5280     case OP_CURR_ENV: /* current-environment */
5281     s_return (SCHEME_V->envir);
5282    
5283     }
5284    
5285 root 1.24 if (USE_ERROR_CHECKING) abort ();
5286 root 1.1 }
5287    
5288 root 1.60 /* reading */
5289     ecb_cold static int
5290 root 1.1 opexe_5 (SCHEME_P_ enum scheme_opcodes op)
5291     {
5292 root 1.18 pointer args = SCHEME_V->args;
5293 root 1.1 pointer x;
5294    
5295     if (SCHEME_V->nesting != 0)
5296     {
5297     int n = SCHEME_V->nesting;
5298    
5299     SCHEME_V->nesting = 0;
5300     SCHEME_V->retcode = -1;
5301     Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
5302     }
5303    
5304     switch (op)
5305     {
5306     /* ========== reading part ========== */
5307     #if USE_PORTS
5308     case OP_READ:
5309 root 1.18 if (!is_pair (args))
5310 root 1.2 s_goto (OP_READ_INTERNAL);
5311 root 1.1
5312 root 1.18 if (!is_inport (car (args)))
5313     Error_1 ("read: not an input port:", car (args));
5314 root 1.1
5315 root 1.18 if (car (args) == SCHEME_V->inport)
5316 root 1.2 s_goto (OP_READ_INTERNAL);
5317 root 1.1
5318     x = SCHEME_V->inport;
5319 root 1.18 SCHEME_V->inport = car (args);
5320 root 1.1 x = cons (x, NIL);
5321     s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
5322     s_goto (OP_READ_INTERNAL);
5323    
5324     case OP_READ_CHAR: /* read-char */
5325     case OP_PEEK_CHAR: /* peek-char */
5326     {
5327     int c;
5328    
5329 root 1.18 if (is_pair (args))
5330 root 1.1 {
5331 root 1.18 if (car (args) != SCHEME_V->inport)
5332 root 1.1 {
5333     x = SCHEME_V->inport;
5334     x = cons (x, NIL);
5335     s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
5336 root 1.18 SCHEME_V->inport = car (args);
5337 root 1.1 }
5338     }
5339    
5340     c = inchar (SCHEME_A);
5341    
5342     if (c == EOF)
5343     s_return (S_EOF);
5344    
5345     if (SCHEME_V->op == OP_PEEK_CHAR)
5346     backchar (SCHEME_A_ c);
5347    
5348     s_return (mk_character (SCHEME_A_ c));
5349     }
5350    
5351     case OP_CHAR_READY: /* char-ready? */
5352     {
5353     pointer p = SCHEME_V->inport;
5354     int res;
5355    
5356 root 1.18 if (is_pair (args))
5357     p = car (args);
5358 root 1.1
5359 root 1.51 res = port (p)->kind & port_string;
5360 root 1.1
5361     s_retbool (res);
5362     }
5363    
5364     case OP_SET_INPORT: /* set-input-port */
5365 root 1.18 SCHEME_V->inport = car (args);
5366 root 1.1 s_return (SCHEME_V->value);
5367    
5368     case OP_SET_OUTPORT: /* set-output-port */
5369 root 1.18 SCHEME_V->outport = car (args);
5370 root 1.1 s_return (SCHEME_V->value);
5371     #endif
5372    
5373     case OP_RDSEXPR:
5374     switch (SCHEME_V->tok)
5375     {
5376     case TOK_EOF:
5377     s_return (S_EOF);
5378    
5379     case TOK_VEC:
5380     s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
5381 root 1.2 /* fall through */
5382 root 1.1
5383     case TOK_LPAREN:
5384     SCHEME_V->tok = token (SCHEME_A);
5385    
5386     if (SCHEME_V->tok == TOK_RPAREN)
5387     s_return (NIL);
5388     else if (SCHEME_V->tok == TOK_DOT)
5389     Error_0 ("syntax error: illegal dot expression");
5390 root 1.64
5391     SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
5392     s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
5393     s_goto (OP_RDSEXPR);
5394 root 1.1
5395     case TOK_QUOTE:
5396     s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
5397     SCHEME_V->tok = token (SCHEME_A);
5398     s_goto (OP_RDSEXPR);
5399    
5400     case TOK_BQUOTE:
5401     SCHEME_V->tok = token (SCHEME_A);
5402    
5403     if (SCHEME_V->tok == TOK_VEC)
5404     {
5405     s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
5406     SCHEME_V->tok = TOK_LPAREN;
5407     s_goto (OP_RDSEXPR);
5408     }
5409    
5410 root 1.64 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
5411 root 1.1 s_goto (OP_RDSEXPR);
5412    
5413     case TOK_COMMA:
5414     s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
5415     SCHEME_V->tok = token (SCHEME_A);
5416     s_goto (OP_RDSEXPR);
5417    
5418     case TOK_ATMARK:
5419     s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
5420     SCHEME_V->tok = token (SCHEME_A);
5421     s_goto (OP_RDSEXPR);
5422    
5423     case TOK_ATOM:
5424 root 1.35 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS)));
5425    
5426     case TOK_DOTATOM:
5427     SCHEME_V->strbuff[0] = '.';
5428     s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ 1, DELIMITERS)));
5429 root 1.1
5430 root 1.36 case TOK_STRATOM:
5431 root 1.64 //TODO: haven't checked whether the garbage collector could interfere and free x
5432     gc (SCHEME_A_ NIL, NIL); //TODO: superheavyhanded
5433 root 1.36 x = readstrexp (SCHEME_A_ '|');
5434     s_return (mk_atom (SCHEME_A_ strvalue (x)));
5435    
5436 root 1.1 case TOK_DQUOTE:
5437 root 1.35 x = readstrexp (SCHEME_A_ '"');
5438 root 1.1
5439     if (x == S_F)
5440     Error_0 ("Error reading string");
5441    
5442     setimmutable (x);
5443     s_return (x);
5444    
5445     case TOK_SHARP:
5446     {
5447     pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
5448    
5449     if (f == NIL)
5450     Error_0 ("undefined sharp expression");
5451 root 1.64
5452     SCHEME_V->code = cons (slot_value_in_env (f), NIL);
5453     s_goto (OP_EVAL);
5454 root 1.1 }
5455    
5456     case TOK_SHARP_CONST:
5457 root 1.35 if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS))) == NIL)
5458 root 1.1 Error_0 ("undefined sharp expression");
5459 root 1.64
5460     s_return (x);
5461 root 1.1
5462     default:
5463     Error_0 ("syntax error: illegal token");
5464     }
5465    
5466     break;
5467    
5468     case OP_RDLIST:
5469 root 1.18 SCHEME_V->args = cons (SCHEME_V->value, args);
5470 root 1.2 SCHEME_V->tok = token (SCHEME_A);
5471 root 1.1
5472 root 1.2 switch (SCHEME_V->tok)
5473     {
5474     case TOK_EOF:
5475     s_return (S_EOF);
5476 root 1.1
5477 root 1.2 case TOK_RPAREN:
5478     {
5479     int c = inchar (SCHEME_A);
5480 root 1.1
5481 root 1.2 if (c != '\n')
5482     backchar (SCHEME_A_ c);
5483 root 1.1 #if SHOW_ERROR_LINE
5484 root 1.2 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5485     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5486     #endif
5487 root 1.1
5488 root 1.2 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5489     s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5490     }
5491    
5492     case TOK_DOT:
5493 root 1.1 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5494     SCHEME_V->tok = token (SCHEME_A);
5495     s_goto (OP_RDSEXPR);
5496 root 1.2
5497     default:
5498     s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5499 root 1.1 s_goto (OP_RDSEXPR);
5500 root 1.2 }
5501 root 1.1
5502     case OP_RDDOT:
5503     if (token (SCHEME_A) != TOK_RPAREN)
5504     Error_0 ("syntax error: illegal dot expression");
5505 root 1.2
5506     SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5507 root 1.18 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5508 root 1.1
5509     case OP_RDQUOTE:
5510     s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5511    
5512     case OP_RDQQUOTE:
5513     s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5514    
5515     case OP_RDQQUOTEVEC:
5516     s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5517     cons (mk_symbol (SCHEME_A_ "vector"),
5518     cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5519    
5520     case OP_RDUNQUOTE:
5521     s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5522    
5523     case OP_RDUQTSP:
5524     s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5525    
5526     case OP_RDVEC:
5527     /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5528     s_goto(OP_EVAL); Cannot be quoted */
5529     /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5530     s_return(x); Cannot be part of pairs */
5531     /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5532     SCHEME_V->args=SCHEME_V->value;
5533     s_goto(OP_APPLY); */
5534     SCHEME_V->args = SCHEME_V->value;
5535     s_goto (OP_VECTOR);
5536    
5537     /* ========== printing part ========== */
5538     case OP_P0LIST:
5539 root 1.18 if (is_vector (args))
5540 root 1.1 {
5541     putstr (SCHEME_A_ "#(");
5542 root 1.18 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5543 root 1.1 s_goto (OP_PVECFROM);
5544     }
5545 root 1.18 else if (is_environment (args))
5546 root 1.1 {
5547     putstr (SCHEME_A_ "#<ENVIRONMENT>");
5548     s_return (S_T);
5549     }
5550 root 1.18 else if (!is_pair (args))
5551 root 1.1 {
5552 root 1.18 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5553 root 1.1 s_return (S_T);
5554     }
5555     else
5556     {
5557 root 1.18 pointer a = car (args);
5558     pointer b = cdr (args);
5559     int ok_abbr = ok_abbrev (b);
5560     SCHEME_V->args = car (b);
5561    
5562     if (a == SCHEME_V->QUOTE && ok_abbr)
5563 root 1.61 putcharacter (SCHEME_A_ '\'');
5564 root 1.18 else if (a == SCHEME_V->QQUOTE && ok_abbr)
5565 root 1.61 putcharacter (SCHEME_A_ '`');
5566 root 1.18 else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5567 root 1.61 putcharacter (SCHEME_A_ ',');
5568 root 1.18 else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5569     putstr (SCHEME_A_ ",@");
5570     else
5571     {
5572 root 1.61 putcharacter (SCHEME_A_ '(');
5573 root 1.18 s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5574     SCHEME_V->args = a;
5575     }
5576    
5577 root 1.1 s_goto (OP_P0LIST);
5578     }
5579    
5580     case OP_P1LIST:
5581 root 1.18 if (is_pair (args))
5582 root 1.1 {
5583 root 1.18 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5584 root 1.61 putcharacter (SCHEME_A_ ' ');
5585 root 1.18 SCHEME_V->args = car (args);
5586 root 1.1 s_goto (OP_P0LIST);
5587     }
5588 root 1.18 else if (is_vector (args))
5589 root 1.1 {
5590     s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5591     putstr (SCHEME_A_ " . ");
5592     s_goto (OP_P0LIST);
5593     }
5594     else
5595     {
5596 root 1.18 if (args != NIL)
5597 root 1.1 {
5598     putstr (SCHEME_A_ " . ");
5599 root 1.18 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5600 root 1.1 }
5601    
5602 root 1.61 putcharacter (SCHEME_A_ ')');
5603 root 1.1 s_return (S_T);
5604     }
5605    
5606     case OP_PVECFROM:
5607     {
5608 root 1.67 IVALUE i = ivalue_unchecked (cdr (args));
5609 root 1.18 pointer vec = car (args);
5610 root 1.67 uint32_t len = veclength (vec);
5611 root 1.1
5612     if (i == len)
5613     {
5614 root 1.61 putcharacter (SCHEME_A_ ')');
5615 root 1.1 s_return (S_T);
5616     }
5617     else
5618     {
5619 root 1.28 pointer elem = vector_get (vec, i);
5620 root 1.1
5621 root 1.67 set_cdr (args, mk_integer (SCHEME_A_ i + 1));
5622 root 1.18 s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5623 root 1.1 SCHEME_V->args = elem;
5624    
5625     if (i > 0)
5626 root 1.61 putcharacter (SCHEME_A_ ' ');
5627 root 1.1
5628     s_goto (OP_P0LIST);
5629     }
5630     }
5631     }
5632    
5633 root 1.24 if (USE_ERROR_CHECKING) abort ();
5634 root 1.1 }
5635    
5636 root 1.60 /* list ops */
5637     ecb_hot static int
5638 root 1.1 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5639     {
5640 root 1.18 pointer args = SCHEME_V->args;
5641     pointer a = car (args);
5642 root 1.1 pointer x, y;
5643    
5644     switch (op)
5645     {
5646     case OP_LIST_LENGTH: /* length *//* a.k */
5647     {
5648 root 1.18 long v = list_length (SCHEME_A_ a);
5649 root 1.1
5650     if (v < 0)
5651 root 1.18 Error_1 ("length: not a list:", a);
5652 root 1.1
5653     s_return (mk_integer (SCHEME_A_ v));
5654     }
5655    
5656     case OP_ASSQ: /* assq *//* a.k */
5657 root 1.18 x = a;
5658 root 1.1
5659 root 1.18 for (y = cadr (args); is_pair (y); y = cdr (y))
5660 root 1.1 {
5661     if (!is_pair (car (y)))
5662     Error_0 ("unable to handle non pair element");
5663    
5664     if (x == caar (y))
5665     break;
5666     }
5667    
5668     if (is_pair (y))
5669     s_return (car (y));
5670    
5671 root 1.63 s_return (S_F);
5672 root 1.1
5673     case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5674 root 1.18 SCHEME_V->args = a;
5675 root 1.1
5676     if (SCHEME_V->args == NIL)
5677     s_return (S_F);
5678 root 1.63 else if (is_closure (SCHEME_V->args) || is_macro (SCHEME_V->args))
5679 root 1.1 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5680 root 1.63
5681     s_return (S_F);
5682 root 1.1
5683     case OP_CLOSUREP: /* closure? */
5684     /*
5685     * Note, macro object is also a closure.
5686     * Therefore, (closure? <#MACRO>) ==> #t
5687 root 1.38 * (schmorp) well, obviously not, fix? TODO
5688 root 1.1 */
5689 root 1.18 s_retbool (is_closure (a));
5690 root 1.1
5691     case OP_MACROP: /* macro? */
5692 root 1.18 s_retbool (is_macro (a));
5693 root 1.1 }
5694    
5695 root 1.24 if (USE_ERROR_CHECKING) abort ();
5696 root 1.1 }
5697    
5698 root 1.20 /* dispatch functions (opexe_x) return new opcode, or 0 for same opcode, or -1 to stop */
5699     typedef int (*dispatch_func)(SCHEME_P_ enum scheme_opcodes);
5700 root 1.1
5701 root 1.19 typedef int (*test_predicate)(pointer);
5702 root 1.60
5703     ecb_hot static int
5704 root 1.26 tst_any (pointer p)
5705 root 1.1 {
5706     return 1;
5707     }
5708    
5709 root 1.60 ecb_hot static int
5710 root 1.26 tst_inonneg (pointer p)
5711 root 1.1 {
5712 root 1.26 return is_integer (p) && ivalue_unchecked (p) >= 0;
5713 root 1.1 }
5714    
5715 root 1.60 ecb_hot static int
5716 root 1.26 tst_is_list (SCHEME_P_ pointer p)
5717 root 1.19 {
5718     return p == NIL || is_pair (p);
5719     }
5720    
5721 root 1.1 /* Correspond carefully with following defines! */
5722     static struct
5723     {
5724     test_predicate fct;
5725     const char *kind;
5726 root 1.26 } tests[] = {
5727     { tst_any , 0 },
5728     { is_string , "string" },
5729     { is_symbol , "symbol" },
5730     { is_port , "port" },
5731     { is_inport , "input port" },
5732     { is_outport , "output port" },
5733 root 1.19 { is_environment, "environment" },
5734 root 1.26 { is_pair , "pair" },
5735     { 0 , "pair or '()" },
5736     { is_character , "character" },
5737     { is_vector , "vector" },
5738     { is_number , "number" },
5739     { is_integer , "integer" },
5740     { tst_inonneg , "non-negative integer" }
5741 root 1.1 };
5742    
5743 root 1.20 #define TST_NONE 0 /* TST_NONE used for built-ins, 0 for internal ops */
5744 root 1.18 #define TST_ANY "\001"
5745     #define TST_STRING "\002"
5746     #define TST_SYMBOL "\003"
5747     #define TST_PORT "\004"
5748     #define TST_INPORT "\005"
5749     #define TST_OUTPORT "\006"
5750 root 1.1 #define TST_ENVIRONMENT "\007"
5751 root 1.18 #define TST_PAIR "\010"
5752     #define TST_LIST "\011"
5753     #define TST_CHAR "\012"
5754     #define TST_VECTOR "\013"
5755     #define TST_NUMBER "\014"
5756     #define TST_INTEGER "\015"
5757     #define TST_NATURAL "\016"
5758 root 1.1
5759 root 1.20 #define INF_ARG 0xff
5760     #define UNNAMED_OP ""
5761    
5762     static const char opnames[] =
5763     #define OP_DEF(func,name,minarity,maxarity,argtest,op) name "\x00"
5764     #include "opdefines.h"
5765     #undef OP_DEF
5766     ;
5767    
5768 root 1.60 ecb_cold static const char *
5769 root 1.20 opname (int idx)
5770     {
5771     const char *name = opnames;
5772    
5773     /* should do this at compile time, but would require external program, right? */
5774     while (idx--)
5775     name += strlen (name) + 1;
5776    
5777     return *name ? name : "ILLEGAL";
5778     }
5779    
5780 root 1.60 ecb_cold static const char *
5781 root 1.20 procname (pointer x)
5782     {
5783     return opname (procnum (x));
5784     }
5785    
5786 root 1.1 typedef struct
5787     {
5788 root 1.20 uint8_t func;
5789     /*dispatch_func func;*//*TODO: maybe optionally keep the pointer, for speed? */
5790     uint8_t builtin;
5791 root 1.26 #if USE_ERROR_CHECKING
5792 root 1.20 uint8_t min_arity;
5793     uint8_t max_arity;
5794 root 1.18 char arg_tests_encoding[3];
5795 root 1.26 #endif
5796 root 1.1 } op_code_info;
5797    
5798 root 1.20 static const op_code_info dispatch_table[] = {
5799 root 1.26 #if USE_ERROR_CHECKING
5800 root 1.20 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1, minarity, maxarity, argtest },
5801 root 1.26 #else
5802     #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1 },
5803     #endif
5804 root 1.1 #include "opdefines.h"
5805 root 1.18 #undef OP_DEF
5806 root 1.1 {0}
5807     };
5808    
5809     /* kernel of this interpreter */
5810 root 1.60 ecb_hot static void
5811 root 1.1 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5812     {
5813     SCHEME_V->op = op;
5814    
5815     for (;;)
5816     {
5817 root 1.20 const op_code_info *pcd = dispatch_table + SCHEME_V->op;
5818 root 1.1
5819 root 1.4 #if USE_ERROR_CHECKING
5820 root 1.20 if (pcd->builtin) /* if built-in function, check arguments */
5821 root 1.1 {
5822     char msg[STRBUFFSIZE];
5823     int n = list_length (SCHEME_A_ SCHEME_V->args);
5824    
5825     /* Check number of arguments */
5826 root 1.10 if (ecb_expect_false (n < pcd->min_arity))
5827 root 1.1 {
5828     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5829 root 1.20 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5830 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5831     continue;
5832 root 1.1 }
5833 root 1.20 else if (ecb_expect_false (n > pcd->max_arity && pcd->max_arity != INF_ARG))
5834 root 1.1 {
5835     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5836 root 1.20 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5837 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5838     continue;
5839 root 1.1 }
5840 root 1.20 else
5841 root 1.1 {
5842 root 1.20 if (*pcd->arg_tests_encoding) /* literal 0 and TST_NONE treated the same */
5843 root 1.1 {
5844     int i = 0;
5845     int j;
5846     const char *t = pcd->arg_tests_encoding;
5847     pointer arglist = SCHEME_V->args;
5848    
5849     do
5850     {
5851     pointer arg = car (arglist);
5852    
5853 root 1.18 j = t[0];
5854 root 1.1
5855 root 1.26 /*TODO: tst_is_list has different prototype - fix if other tests acquire same prototype */
5856     if (j == TST_LIST[0])
5857     {
5858     if (!tst_is_list (SCHEME_A_ arg))
5859     break;
5860     }
5861     else
5862     {
5863     if (!tests[j - 1].fct (arg))
5864     break;
5865     }
5866 root 1.1
5867 root 1.28 if (t < pcd->arg_tests_encoding + sizeof (pcd->arg_tests_encoding) - 1 && t[1]) /* last test is replicated as necessary */
5868 root 1.2 t++;
5869 root 1.1
5870     arglist = cdr (arglist);
5871     i++;
5872     }
5873     while (i < n);
5874    
5875     if (i < n)
5876     {
5877 root 1.20 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", opname (SCHEME_V->op), i + 1, tests[j].kind);
5878 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5879     continue;
5880 root 1.1 }
5881     }
5882     }
5883     }
5884 root 1.4 #endif
5885 root 1.1
5886     ok_to_freely_gc (SCHEME_A);
5887    
5888 root 1.20 static const dispatch_func dispatch_funcs[] = {
5889     opexe_0,
5890     opexe_1,
5891     opexe_2,
5892     opexe_3,
5893     opexe_4,
5894     opexe_5,
5895     opexe_6,
5896     };
5897    
5898     if (ecb_expect_false (dispatch_funcs [pcd->func] (SCHEME_A_ SCHEME_V->op) != 0))
5899 root 1.1 return;
5900    
5901 root 1.5 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5902 root 1.1 {
5903 root 1.53 putstr (SCHEME_A_ "No memory!\n");
5904 root 1.1 return;
5905     }
5906     }
5907     }
5908    
5909     /* ========== Initialization of internal keywords ========== */
5910    
5911 root 1.60 ecb_cold static void
5912 root 1.2 assign_syntax (SCHEME_P_ const char *name)
5913 root 1.1 {
5914     pointer x = oblist_add_by_name (SCHEME_A_ name);
5915     set_typeflag (x, typeflag (x) | T_SYNTAX);
5916     }
5917    
5918 root 1.60 ecb_cold static void
5919 root 1.2 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5920 root 1.1 {
5921     pointer x = mk_symbol (SCHEME_A_ name);
5922     pointer y = mk_proc (SCHEME_A_ op);
5923     new_slot_in_env (SCHEME_A_ x, y);
5924     }
5925    
5926     static pointer
5927     mk_proc (SCHEME_P_ enum scheme_opcodes op)
5928     {
5929     pointer y = get_cell (SCHEME_A_ NIL, NIL);
5930     set_typeflag (y, (T_PROC | T_ATOM));
5931 root 1.67 set_ivalue (y, op);
5932 root 1.1 return y;
5933     }
5934    
5935     /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5936 root 1.60 ecb_hot static int
5937 root 1.1 syntaxnum (pointer p)
5938     {
5939 root 1.38 const char *s = strvalue (p);
5940 root 1.1
5941 root 1.38 switch (strlength (p))
5942 root 1.1 {
5943     case 2:
5944     if (s[0] == 'i')
5945     return OP_IF0; /* if */
5946     else
5947     return OP_OR0; /* or */
5948    
5949     case 3:
5950     if (s[0] == 'a')
5951     return OP_AND0; /* and */
5952     else
5953     return OP_LET0; /* let */
5954    
5955     case 4:
5956     switch (s[3])
5957     {
5958     case 'e':
5959     return OP_CASE0; /* case */
5960    
5961     case 'd':
5962     return OP_COND0; /* cond */
5963    
5964     case '*':
5965 root 1.10 return OP_LET0AST;/* let* */
5966 root 1.1
5967     default:
5968     return OP_SET0; /* set! */
5969     }
5970    
5971     case 5:
5972     switch (s[2])
5973     {
5974     case 'g':
5975     return OP_BEGIN; /* begin */
5976    
5977     case 'l':
5978     return OP_DELAY; /* delay */
5979    
5980     case 'c':
5981     return OP_MACRO0; /* macro */
5982    
5983     default:
5984     return OP_QUOTE; /* quote */
5985     }
5986    
5987     case 6:
5988     switch (s[2])
5989     {
5990     case 'm':
5991     return OP_LAMBDA; /* lambda */
5992    
5993     case 'f':
5994     return OP_DEF0; /* define */
5995    
5996     default:
5997 root 1.10 return OP_LET0REC;/* letrec */
5998 root 1.1 }
5999    
6000     default:
6001     return OP_C0STREAM; /* cons-stream */
6002     }
6003     }
6004    
6005     #if USE_MULTIPLICITY
6006 root 1.23 ecb_cold scheme *
6007 root 1.1 scheme_init_new ()
6008     {
6009     scheme *sc = malloc (sizeof (scheme));
6010    
6011     if (!scheme_init (SCHEME_A))
6012     {
6013     free (SCHEME_A);
6014     return 0;
6015     }
6016     else
6017     return sc;
6018     }
6019     #endif
6020    
6021 root 1.23 ecb_cold int
6022 root 1.1 scheme_init (SCHEME_P)
6023     {
6024     int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
6025    
6026 root 1.49 /* this memset is not strictly correct, as we assume (intcache)
6027     * that memset 0 will also set pointers to 0, but memset does
6028     * of course not guarantee that. screw such systems.
6029     */
6030     memset (SCHEME_V, 0, sizeof (*SCHEME_V));
6031 root 1.48
6032 root 1.1 num_set_fixnum (num_zero, 1);
6033     num_set_ivalue (num_zero, 0);
6034     num_set_fixnum (num_one, 1);
6035     num_set_ivalue (num_one, 1);
6036    
6037     #if USE_INTERFACE
6038     SCHEME_V->vptr = &vtbl;
6039     #endif
6040     SCHEME_V->gensym_cnt = 0;
6041     SCHEME_V->last_cell_seg = -1;
6042     SCHEME_V->free_cell = NIL;
6043     SCHEME_V->fcells = 0;
6044     SCHEME_V->no_memory = 0;
6045     SCHEME_V->inport = NIL;
6046     SCHEME_V->outport = NIL;
6047     SCHEME_V->save_inport = NIL;
6048     SCHEME_V->loadport = NIL;
6049     SCHEME_V->nesting = 0;
6050     SCHEME_V->interactive_repl = 0;
6051    
6052 root 1.51 if (!alloc_cellseg (SCHEME_A))
6053 root 1.1 {
6054     #if USE_ERROR_CHECKING
6055     SCHEME_V->no_memory = 1;
6056     return 0;
6057     #endif
6058     }
6059    
6060     SCHEME_V->gc_verbose = 0;
6061     dump_stack_initialize (SCHEME_A);
6062 root 1.61 SCHEME_V->code = NIL;
6063     SCHEME_V->args = NIL;
6064 root 1.2 SCHEME_V->envir = NIL;
6065 root 1.61 SCHEME_V->value = NIL;
6066 root 1.1 SCHEME_V->tracing = 0;
6067    
6068     /* init NIL */
6069 root 1.66 set_typeflag (NIL, T_SPECIAL | T_ATOM);
6070 root 1.1 set_car (NIL, NIL);
6071     set_cdr (NIL, NIL);
6072     /* init T */
6073 root 1.66 set_typeflag (S_T, T_SPECIAL | T_ATOM);
6074 root 1.1 set_car (S_T, S_T);
6075     set_cdr (S_T, S_T);
6076     /* init F */
6077 root 1.66 set_typeflag (S_F, T_SPECIAL | T_ATOM);
6078 root 1.1 set_car (S_F, S_F);
6079     set_cdr (S_F, S_F);
6080 root 1.7 /* init EOF_OBJ */
6081 root 1.66 set_typeflag (S_EOF, T_SPECIAL | T_ATOM);
6082 root 1.7 set_car (S_EOF, S_EOF);
6083     set_cdr (S_EOF, S_EOF);
6084 root 1.1 /* init sink */
6085 root 1.66 set_typeflag (S_SINK, T_PAIR);
6086 root 1.1 set_car (S_SINK, NIL);
6087 root 1.7
6088 root 1.1 /* init c_nest */
6089     SCHEME_V->c_nest = NIL;
6090    
6091     SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
6092     /* init global_env */
6093     new_frame_in_env (SCHEME_A_ NIL);
6094     SCHEME_V->global_env = SCHEME_V->envir;
6095     /* init else */
6096 root 1.66 new_slot_in_env (SCHEME_A_ mk_symbol (SCHEME_A_ "else"), S_T);
6097 root 1.1
6098 root 1.2 {
6099     static const char *syntax_names[] = {
6100     "lambda", "quote", "define", "if", "begin", "set!",
6101     "let", "let*", "letrec", "cond", "delay", "and",
6102     "or", "cons-stream", "macro", "case"
6103     };
6104    
6105     for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
6106     assign_syntax (SCHEME_A_ syntax_names[i]);
6107     }
6108 root 1.1
6109 root 1.20 // TODO: should iterate via strlen, to avoid n² complexity
6110 root 1.1 for (i = 0; i < n; i++)
6111 root 1.20 if (dispatch_table[i].builtin)
6112     assign_proc (SCHEME_A_ i, opname (i));
6113 root 1.1
6114     /* initialization of global pointers to special symbols */
6115 root 1.6 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
6116     SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
6117     SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
6118     SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
6119     SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
6120     SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
6121     SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
6122     SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
6123     SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
6124 root 1.1 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
6125    
6126     return !SCHEME_V->no_memory;
6127     }
6128    
6129     #if USE_PORTS
6130 root 1.60 ecb_cold void
6131 root 1.1 scheme_set_input_port_file (SCHEME_P_ int fin)
6132     {
6133     SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
6134     }
6135    
6136 root 1.60 ecb_cold void
6137 root 1.1 scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
6138     {
6139     SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
6140     }
6141    
6142 root 1.60 ecb_cold void
6143 root 1.1 scheme_set_output_port_file (SCHEME_P_ int fout)
6144     {
6145     SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
6146     }
6147    
6148 root 1.60 ecb_cold void
6149 root 1.1 scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
6150     {
6151     SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
6152     }
6153     #endif
6154    
6155 root 1.60 ecb_cold void
6156 root 1.1 scheme_set_external_data (SCHEME_P_ void *p)
6157     {
6158     SCHEME_V->ext_data = p;
6159     }
6160    
6161 root 1.23 ecb_cold void
6162 root 1.1 scheme_deinit (SCHEME_P)
6163     {
6164     int i;
6165    
6166     #if SHOW_ERROR_LINE
6167     char *fname;
6168     #endif
6169    
6170     SCHEME_V->oblist = NIL;
6171     SCHEME_V->global_env = NIL;
6172     dump_stack_free (SCHEME_A);
6173     SCHEME_V->envir = NIL;
6174     SCHEME_V->code = NIL;
6175     SCHEME_V->args = NIL;
6176     SCHEME_V->value = NIL;
6177    
6178     if (is_port (SCHEME_V->inport))
6179     set_typeflag (SCHEME_V->inport, T_ATOM);
6180    
6181     SCHEME_V->inport = NIL;
6182     SCHEME_V->outport = NIL;
6183    
6184     if (is_port (SCHEME_V->save_inport))
6185     set_typeflag (SCHEME_V->save_inport, T_ATOM);
6186    
6187     SCHEME_V->save_inport = NIL;
6188    
6189     if (is_port (SCHEME_V->loadport))
6190     set_typeflag (SCHEME_V->loadport, T_ATOM);
6191    
6192     SCHEME_V->loadport = NIL;
6193     SCHEME_V->gc_verbose = 0;
6194     gc (SCHEME_A_ NIL, NIL);
6195    
6196     for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
6197 root 1.62 free (SCHEME_V->cell_seg[i]);
6198 root 1.1
6199     #if SHOW_ERROR_LINE
6200     for (i = 0; i <= SCHEME_V->file_i; i++)
6201 root 1.63 if (SCHEME_V->load_stack[i].kind & port_file)
6202     {
6203     fname = SCHEME_V->load_stack[i].rep.stdio.filename;
6204 root 1.1
6205 root 1.63 if (fname)
6206     free (fname);
6207     }
6208 root 1.1 #endif
6209     }
6210    
6211 root 1.60 ecb_cold void
6212 root 1.1 scheme_load_file (SCHEME_P_ int fin)
6213     {
6214     scheme_load_named_file (SCHEME_A_ fin, 0);
6215     }
6216    
6217 root 1.60 ecb_cold void
6218 root 1.1 scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
6219     {
6220     dump_stack_reset (SCHEME_A);
6221     SCHEME_V->envir = SCHEME_V->global_env;
6222     SCHEME_V->file_i = 0;
6223     SCHEME_V->load_stack[0].unget = -1;
6224     SCHEME_V->load_stack[0].kind = port_input | port_file;
6225     SCHEME_V->load_stack[0].rep.stdio.file = fin;
6226     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
6227     SCHEME_V->retcode = 0;
6228    
6229     if (fin == STDIN_FILENO)
6230     SCHEME_V->interactive_repl = 1;
6231    
6232     #if USE_PORTS
6233     #if SHOW_ERROR_LINE
6234     SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
6235    
6236     if (fin != STDIN_FILENO && filename)
6237     SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
6238     #endif
6239     #endif
6240    
6241     SCHEME_V->inport = SCHEME_V->loadport;
6242     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
6243     Eval_Cycle (SCHEME_A_ OP_T0LVL);
6244 root 1.61
6245 root 1.1 set_typeflag (SCHEME_V->loadport, T_ATOM);
6246    
6247     if (SCHEME_V->retcode == 0)
6248     SCHEME_V->retcode = SCHEME_V->nesting != 0;
6249     }
6250    
6251 root 1.60 ecb_cold void
6252 root 1.1 scheme_load_string (SCHEME_P_ const char *cmd)
6253     {
6254 root 1.61 #if USE_PORTs
6255 root 1.1 dump_stack_reset (SCHEME_A);
6256     SCHEME_V->envir = SCHEME_V->global_env;
6257     SCHEME_V->file_i = 0;
6258     SCHEME_V->load_stack[0].kind = port_input | port_string;
6259 root 1.17 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
6260     SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
6261     SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
6262 root 1.1 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
6263     SCHEME_V->retcode = 0;
6264     SCHEME_V->interactive_repl = 0;
6265     SCHEME_V->inport = SCHEME_V->loadport;
6266     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
6267     Eval_Cycle (SCHEME_A_ OP_T0LVL);
6268     set_typeflag (SCHEME_V->loadport, T_ATOM);
6269    
6270     if (SCHEME_V->retcode == 0)
6271     SCHEME_V->retcode = SCHEME_V->nesting != 0;
6272 root 1.61 #else
6273     abort ();
6274     #endif
6275 root 1.1 }
6276    
6277 root 1.60 ecb_cold void
6278 root 1.1 scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
6279     {
6280     pointer x;
6281    
6282     x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
6283    
6284     if (x != NIL)
6285 root 1.2 set_slot_in_env (SCHEME_A_ x, value);
6286 root 1.1 else
6287 root 1.2 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
6288 root 1.1 }
6289    
6290     #if !STANDALONE
6291 root 1.2
6292 root 1.60 ecb_cold void
6293 root 1.1 scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
6294     {
6295     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
6296     }
6297    
6298 root 1.60 ecb_cold void
6299 root 1.1 scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
6300     {
6301     int i;
6302    
6303     for (i = 0; i < count; i++)
6304 root 1.2 scheme_register_foreign_func (SCHEME_A_ list + i);
6305 root 1.1 }
6306    
6307 root 1.60 ecb_cold pointer
6308 root 1.1 scheme_apply0 (SCHEME_P_ const char *procname)
6309     {
6310     return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
6311     }
6312    
6313 root 1.60 ecb_cold void
6314 root 1.1 save_from_C_call (SCHEME_P)
6315     {
6316     pointer saved_data = cons (car (S_SINK),
6317     cons (SCHEME_V->envir,
6318     SCHEME_V->dump));
6319    
6320     /* Push */
6321     SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
6322     /* Truncate the dump stack so TS will return here when done, not
6323     directly resume pre-C-call operations. */
6324     dump_stack_reset (SCHEME_A);
6325     }
6326    
6327 root 1.60 ecb_cold void
6328 root 1.1 restore_from_C_call (SCHEME_P)
6329     {
6330     set_car (S_SINK, caar (SCHEME_V->c_nest));
6331     SCHEME_V->envir = cadar (SCHEME_V->c_nest);
6332     SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
6333     /* Pop */
6334     SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
6335     }
6336    
6337     /* "func" and "args" are assumed to be already eval'ed. */
6338 root 1.60 ecb_cold pointer
6339 root 1.1 scheme_call (SCHEME_P_ pointer func, pointer args)
6340     {
6341     int old_repl = SCHEME_V->interactive_repl;
6342    
6343     SCHEME_V->interactive_repl = 0;
6344     save_from_C_call (SCHEME_A);
6345     SCHEME_V->envir = SCHEME_V->global_env;
6346     SCHEME_V->args = args;
6347     SCHEME_V->code = func;
6348     SCHEME_V->retcode = 0;
6349     Eval_Cycle (SCHEME_A_ OP_APPLY);
6350     SCHEME_V->interactive_repl = old_repl;
6351     restore_from_C_call (SCHEME_A);
6352     return SCHEME_V->value;
6353     }
6354    
6355 root 1.60 ecb_cold pointer
6356 root 1.1 scheme_eval (SCHEME_P_ pointer obj)
6357     {
6358     int old_repl = SCHEME_V->interactive_repl;
6359    
6360     SCHEME_V->interactive_repl = 0;
6361     save_from_C_call (SCHEME_A);
6362     SCHEME_V->args = NIL;
6363     SCHEME_V->code = obj;
6364     SCHEME_V->retcode = 0;
6365     Eval_Cycle (SCHEME_A_ OP_EVAL);
6366     SCHEME_V->interactive_repl = old_repl;
6367     restore_from_C_call (SCHEME_A);
6368     return SCHEME_V->value;
6369     }
6370    
6371     #endif
6372    
6373     /* ========== Main ========== */
6374    
6375     #if STANDALONE
6376    
6377 root 1.60 ecb_cold int
6378 root 1.1 main (int argc, char **argv)
6379     {
6380     # if USE_MULTIPLICITY
6381     scheme ssc;
6382 root 1.2 scheme *const SCHEME_V = &ssc;
6383 root 1.1 # else
6384     # endif
6385     int fin;
6386     char *file_name = InitFile;
6387     int retcode;
6388     int isfile = 1;
6389 root 1.63 #if EXPERIMENT
6390     system ("ps v $PPID");
6391     #endif
6392 root 1.1
6393     if (argc == 2 && strcmp (argv[1], "-?") == 0)
6394     {
6395 root 1.53 putstr (SCHEME_A_ "Usage: tinyscheme -?\n");
6396     putstr (SCHEME_A_ "or: tinyscheme [<file1> <file2> ...]\n");
6397     putstr (SCHEME_A_ "followed by\n");
6398     putstr (SCHEME_A_ " -1 <file> [<arg1> <arg2> ...]\n");
6399     putstr (SCHEME_A_ " -c <Scheme commands> [<arg1> <arg2> ...]\n");
6400     putstr (SCHEME_A_ "assuming that the executable is named tinyscheme.\n");
6401     putstr (SCHEME_A_ "Use - as filename for stdin.\n");
6402 root 1.1 return 1;
6403     }
6404    
6405     if (!scheme_init (SCHEME_A))
6406     {
6407 root 1.53 putstr (SCHEME_A_ "Could not initialize!\n");
6408 root 1.1 return 2;
6409     }
6410    
6411     # if USE_PORTS
6412     scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
6413     scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
6414     # endif
6415    
6416     argv++;
6417    
6418     #if 0
6419     if (access (file_name, 0) != 0)
6420     {
6421     char *p = getenv ("TINYSCHEMEINIT");
6422    
6423     if (p != 0)
6424 root 1.2 file_name = p;
6425 root 1.1 }
6426     #endif
6427    
6428     do
6429     {
6430     if (strcmp (file_name, "-") == 0)
6431     fin = STDIN_FILENO;
6432     else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
6433     {
6434     pointer args = NIL;
6435    
6436     isfile = file_name[1] == '1';
6437     file_name = *argv++;
6438    
6439     if (strcmp (file_name, "-") == 0)
6440     fin = STDIN_FILENO;
6441     else if (isfile)
6442     fin = open (file_name, O_RDONLY);
6443    
6444     for (; *argv; argv++)
6445     {
6446     pointer value = mk_string (SCHEME_A_ * argv);
6447    
6448     args = cons (value, args);
6449     }
6450    
6451     args = reverse_in_place (SCHEME_A_ NIL, args);
6452     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
6453    
6454     }
6455     else
6456     fin = open (file_name, O_RDONLY);
6457    
6458     if (isfile && fin < 0)
6459     {
6460 root 1.61 putstr (SCHEME_A_ "Could not open file ");
6461     putstr (SCHEME_A_ file_name);
6462     putcharacter (SCHEME_A_ '\n');
6463 root 1.1 }
6464     else
6465     {
6466     if (isfile)
6467     scheme_load_named_file (SCHEME_A_ fin, file_name);
6468     else
6469     scheme_load_string (SCHEME_A_ file_name);
6470    
6471     if (!isfile || fin != STDIN_FILENO)
6472     {
6473     if (SCHEME_V->retcode != 0)
6474     {
6475 root 1.61 putstr (SCHEME_A_ "Errors encountered reading ");
6476     putstr (SCHEME_A_ file_name);
6477     putcharacter (SCHEME_A_ '\n');
6478 root 1.1 }
6479    
6480     if (isfile)
6481     close (fin);
6482     }
6483     }
6484    
6485     file_name = *argv++;
6486     }
6487     while (file_name != 0);
6488    
6489     if (argc == 1)
6490     scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6491    
6492     retcode = SCHEME_V->retcode;
6493     scheme_deinit (SCHEME_A);
6494    
6495     return retcode;
6496     }
6497    
6498     #endif
6499    
6500     /*
6501     Local variables:
6502     c-file-style: "k&r"
6503     End:
6504     */