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