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