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