ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.68
Committed: Mon Dec 7 21:12:56 2015 UTC (10 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.67: +5 -6 lines
Log Message:
*** empty log message ***

File Contents

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