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