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