ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.36
Committed: Sun Nov 29 05:04:29 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.35: +5 -0 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 root 1.36 case TOK_STRATOM:
4954     x = readstrexp (SCHEME_A_ '|');
4955     //TODO: haven't checked whether the garbage collector could interfere
4956     s_return (mk_atom (SCHEME_A_ strvalue (x)));
4957    
4958 root 1.1 case TOK_DQUOTE:
4959 root 1.35 x = readstrexp (SCHEME_A_ '"');
4960 root 1.1
4961     if (x == S_F)
4962     Error_0 ("Error reading string");
4963    
4964     setimmutable (x);
4965     s_return (x);
4966    
4967     case TOK_SHARP:
4968     {
4969     pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
4970    
4971     if (f == NIL)
4972     Error_0 ("undefined sharp expression");
4973     else
4974     {
4975     SCHEME_V->code = cons (slot_value_in_env (f), NIL);
4976     s_goto (OP_EVAL);
4977     }
4978     }
4979    
4980     case TOK_SHARP_CONST:
4981 root 1.35 if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS))) == NIL)
4982 root 1.1 Error_0 ("undefined sharp expression");
4983     else
4984     s_return (x);
4985    
4986     default:
4987     Error_0 ("syntax error: illegal token");
4988     }
4989    
4990     break;
4991    
4992     case OP_RDLIST:
4993 root 1.18 SCHEME_V->args = cons (SCHEME_V->value, args);
4994 root 1.2 SCHEME_V->tok = token (SCHEME_A);
4995 root 1.1
4996 root 1.2 switch (SCHEME_V->tok)
4997     {
4998     case TOK_EOF:
4999     s_return (S_EOF);
5000 root 1.1
5001 root 1.2 case TOK_RPAREN:
5002     {
5003     int c = inchar (SCHEME_A);
5004 root 1.1
5005 root 1.2 if (c != '\n')
5006     backchar (SCHEME_A_ c);
5007 root 1.1 #if SHOW_ERROR_LINE
5008 root 1.2 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5009     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5010     #endif
5011 root 1.1
5012 root 1.2 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5013     s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5014     }
5015    
5016     case TOK_DOT:
5017 root 1.1 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5018     SCHEME_V->tok = token (SCHEME_A);
5019     s_goto (OP_RDSEXPR);
5020 root 1.2
5021     default:
5022     s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5023 root 1.1 s_goto (OP_RDSEXPR);
5024 root 1.2 }
5025 root 1.1
5026     case OP_RDDOT:
5027     if (token (SCHEME_A) != TOK_RPAREN)
5028     Error_0 ("syntax error: illegal dot expression");
5029 root 1.2
5030     SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5031 root 1.18 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5032 root 1.1
5033     case OP_RDQUOTE:
5034     s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5035    
5036     case OP_RDQQUOTE:
5037     s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5038    
5039     case OP_RDQQUOTEVEC:
5040     s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5041     cons (mk_symbol (SCHEME_A_ "vector"),
5042     cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5043    
5044     case OP_RDUNQUOTE:
5045     s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5046    
5047     case OP_RDUQTSP:
5048     s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5049    
5050     case OP_RDVEC:
5051     /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5052     s_goto(OP_EVAL); Cannot be quoted */
5053     /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5054     s_return(x); Cannot be part of pairs */
5055     /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5056     SCHEME_V->args=SCHEME_V->value;
5057     s_goto(OP_APPLY); */
5058     SCHEME_V->args = SCHEME_V->value;
5059     s_goto (OP_VECTOR);
5060    
5061     /* ========== printing part ========== */
5062     case OP_P0LIST:
5063 root 1.18 if (is_vector (args))
5064 root 1.1 {
5065     putstr (SCHEME_A_ "#(");
5066 root 1.18 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5067 root 1.1 s_goto (OP_PVECFROM);
5068     }
5069 root 1.18 else if (is_environment (args))
5070 root 1.1 {
5071     putstr (SCHEME_A_ "#<ENVIRONMENT>");
5072     s_return (S_T);
5073     }
5074 root 1.18 else if (!is_pair (args))
5075 root 1.1 {
5076 root 1.18 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5077 root 1.1 s_return (S_T);
5078     }
5079     else
5080     {
5081 root 1.18 pointer a = car (args);
5082     pointer b = cdr (args);
5083     int ok_abbr = ok_abbrev (b);
5084     SCHEME_V->args = car (b);
5085    
5086     if (a == SCHEME_V->QUOTE && ok_abbr)
5087     putstr (SCHEME_A_ "'");
5088     else if (a == SCHEME_V->QQUOTE && ok_abbr)
5089     putstr (SCHEME_A_ "`");
5090     else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5091     putstr (SCHEME_A_ ",");
5092     else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5093     putstr (SCHEME_A_ ",@");
5094     else
5095     {
5096     putstr (SCHEME_A_ "(");
5097     s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5098     SCHEME_V->args = a;
5099     }
5100    
5101 root 1.1 s_goto (OP_P0LIST);
5102     }
5103    
5104     case OP_P1LIST:
5105 root 1.18 if (is_pair (args))
5106 root 1.1 {
5107 root 1.18 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5108 root 1.1 putstr (SCHEME_A_ " ");
5109 root 1.18 SCHEME_V->args = car (args);
5110 root 1.1 s_goto (OP_P0LIST);
5111     }
5112 root 1.18 else if (is_vector (args))
5113 root 1.1 {
5114     s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5115     putstr (SCHEME_A_ " . ");
5116     s_goto (OP_P0LIST);
5117     }
5118     else
5119     {
5120 root 1.18 if (args != NIL)
5121 root 1.1 {
5122     putstr (SCHEME_A_ " . ");
5123 root 1.18 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5124 root 1.1 }
5125    
5126     putstr (SCHEME_A_ ")");
5127     s_return (S_T);
5128     }
5129    
5130     case OP_PVECFROM:
5131     {
5132 root 1.18 int i = ivalue_unchecked (cdr (args));
5133     pointer vec = car (args);
5134 root 1.7 int len = veclength (vec);
5135 root 1.1
5136     if (i == len)
5137     {
5138     putstr (SCHEME_A_ ")");
5139     s_return (S_T);
5140     }
5141     else
5142     {
5143 root 1.28 pointer elem = vector_get (vec, i);
5144 root 1.1
5145 root 1.18 ivalue_unchecked (cdr (args)) = i + 1;
5146     s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5147 root 1.1 SCHEME_V->args = elem;
5148    
5149     if (i > 0)
5150     putstr (SCHEME_A_ " ");
5151    
5152     s_goto (OP_P0LIST);
5153     }
5154     }
5155     }
5156    
5157 root 1.24 if (USE_ERROR_CHECKING) abort ();
5158 root 1.1 }
5159    
5160 root 1.20 static int
5161 root 1.1 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5162     {
5163 root 1.18 pointer args = SCHEME_V->args;
5164     pointer a = car (args);
5165 root 1.1 pointer x, y;
5166    
5167     switch (op)
5168     {
5169     case OP_LIST_LENGTH: /* length *//* a.k */
5170     {
5171 root 1.18 long v = list_length (SCHEME_A_ a);
5172 root 1.1
5173     if (v < 0)
5174 root 1.18 Error_1 ("length: not a list:", a);
5175 root 1.1
5176     s_return (mk_integer (SCHEME_A_ v));
5177     }
5178    
5179     case OP_ASSQ: /* assq *//* a.k */
5180 root 1.18 x = a;
5181 root 1.1
5182 root 1.18 for (y = cadr (args); is_pair (y); y = cdr (y))
5183 root 1.1 {
5184     if (!is_pair (car (y)))
5185     Error_0 ("unable to handle non pair element");
5186    
5187     if (x == caar (y))
5188     break;
5189     }
5190    
5191     if (is_pair (y))
5192     s_return (car (y));
5193     else
5194     s_return (S_F);
5195    
5196    
5197     case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5198 root 1.18 SCHEME_V->args = a;
5199 root 1.1
5200     if (SCHEME_V->args == NIL)
5201     s_return (S_F);
5202     else if (is_closure (SCHEME_V->args))
5203     s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5204     else if (is_macro (SCHEME_V->args))
5205     s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5206     else
5207     s_return (S_F);
5208    
5209     case OP_CLOSUREP: /* closure? */
5210     /*
5211     * Note, macro object is also a closure.
5212     * Therefore, (closure? <#MACRO>) ==> #t
5213     */
5214 root 1.18 s_retbool (is_closure (a));
5215 root 1.1
5216     case OP_MACROP: /* macro? */
5217 root 1.18 s_retbool (is_macro (a));
5218 root 1.1 }
5219    
5220 root 1.24 if (USE_ERROR_CHECKING) abort ();
5221 root 1.1 }
5222    
5223 root 1.20 /* dispatch functions (opexe_x) return new opcode, or 0 for same opcode, or -1 to stop */
5224     typedef int (*dispatch_func)(SCHEME_P_ enum scheme_opcodes);
5225 root 1.1
5226 root 1.19 typedef int (*test_predicate)(pointer);
5227 root 1.1 static int
5228 root 1.26 tst_any (pointer p)
5229 root 1.1 {
5230     return 1;
5231     }
5232    
5233     static int
5234 root 1.26 tst_inonneg (pointer p)
5235 root 1.1 {
5236 root 1.26 return is_integer (p) && ivalue_unchecked (p) >= 0;
5237 root 1.1 }
5238    
5239 root 1.19 static int
5240 root 1.26 tst_is_list (SCHEME_P_ pointer p)
5241 root 1.19 {
5242     return p == NIL || is_pair (p);
5243     }
5244    
5245 root 1.1 /* Correspond carefully with following defines! */
5246     static struct
5247     {
5248     test_predicate fct;
5249     const char *kind;
5250 root 1.26 } tests[] = {
5251     { tst_any , 0 },
5252     { is_string , "string" },
5253     { is_symbol , "symbol" },
5254     { is_port , "port" },
5255     { is_inport , "input port" },
5256     { is_outport , "output port" },
5257 root 1.19 { is_environment, "environment" },
5258 root 1.26 { is_pair , "pair" },
5259     { 0 , "pair or '()" },
5260     { is_character , "character" },
5261     { is_vector , "vector" },
5262     { is_number , "number" },
5263     { is_integer , "integer" },
5264     { tst_inonneg , "non-negative integer" }
5265 root 1.1 };
5266    
5267 root 1.20 #define TST_NONE 0 /* TST_NONE used for built-ins, 0 for internal ops */
5268 root 1.18 #define TST_ANY "\001"
5269     #define TST_STRING "\002"
5270     #define TST_SYMBOL "\003"
5271     #define TST_PORT "\004"
5272     #define TST_INPORT "\005"
5273     #define TST_OUTPORT "\006"
5274 root 1.1 #define TST_ENVIRONMENT "\007"
5275 root 1.18 #define TST_PAIR "\010"
5276     #define TST_LIST "\011"
5277     #define TST_CHAR "\012"
5278     #define TST_VECTOR "\013"
5279     #define TST_NUMBER "\014"
5280     #define TST_INTEGER "\015"
5281     #define TST_NATURAL "\016"
5282 root 1.1
5283 root 1.20 #define INF_ARG 0xff
5284     #define UNNAMED_OP ""
5285    
5286     static const char opnames[] =
5287     #define OP_DEF(func,name,minarity,maxarity,argtest,op) name "\x00"
5288     #include "opdefines.h"
5289     #undef OP_DEF
5290     ;
5291    
5292     static const char *
5293     opname (int idx)
5294     {
5295     const char *name = opnames;
5296    
5297     /* should do this at compile time, but would require external program, right? */
5298     while (idx--)
5299     name += strlen (name) + 1;
5300    
5301     return *name ? name : "ILLEGAL";
5302     }
5303    
5304     static const char *
5305     procname (pointer x)
5306     {
5307     return opname (procnum (x));
5308     }
5309    
5310 root 1.1 typedef struct
5311     {
5312 root 1.20 uint8_t func;
5313     /*dispatch_func func;*//*TODO: maybe optionally keep the pointer, for speed? */
5314     uint8_t builtin;
5315 root 1.26 #if USE_ERROR_CHECKING
5316 root 1.20 uint8_t min_arity;
5317     uint8_t max_arity;
5318 root 1.18 char arg_tests_encoding[3];
5319 root 1.26 #endif
5320 root 1.1 } op_code_info;
5321    
5322 root 1.20 static const op_code_info dispatch_table[] = {
5323 root 1.26 #if USE_ERROR_CHECKING
5324 root 1.20 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1, minarity, maxarity, argtest },
5325 root 1.26 #else
5326     #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1 },
5327     #endif
5328 root 1.1 #include "opdefines.h"
5329 root 1.18 #undef OP_DEF
5330 root 1.1 {0}
5331     };
5332    
5333     /* kernel of this interpreter */
5334 root 1.23 static void ecb_hot
5335 root 1.1 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5336     {
5337     SCHEME_V->op = op;
5338    
5339     for (;;)
5340     {
5341 root 1.20 const op_code_info *pcd = dispatch_table + SCHEME_V->op;
5342 root 1.1
5343 root 1.4 #if USE_ERROR_CHECKING
5344 root 1.20 if (pcd->builtin) /* if built-in function, check arguments */
5345 root 1.1 {
5346     char msg[STRBUFFSIZE];
5347     int n = list_length (SCHEME_A_ SCHEME_V->args);
5348    
5349     /* Check number of arguments */
5350 root 1.10 if (ecb_expect_false (n < pcd->min_arity))
5351 root 1.1 {
5352     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5353 root 1.20 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5354 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5355     continue;
5356 root 1.1 }
5357 root 1.20 else if (ecb_expect_false (n > pcd->max_arity && pcd->max_arity != INF_ARG))
5358 root 1.1 {
5359     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5360 root 1.20 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5361 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5362     continue;
5363 root 1.1 }
5364 root 1.20 else
5365 root 1.1 {
5366 root 1.20 if (*pcd->arg_tests_encoding) /* literal 0 and TST_NONE treated the same */
5367 root 1.1 {
5368     int i = 0;
5369     int j;
5370     const char *t = pcd->arg_tests_encoding;
5371     pointer arglist = SCHEME_V->args;
5372    
5373     do
5374     {
5375     pointer arg = car (arglist);
5376    
5377 root 1.18 j = t[0];
5378 root 1.1
5379 root 1.26 /*TODO: tst_is_list has different prototype - fix if other tests acquire same prototype */
5380     if (j == TST_LIST[0])
5381     {
5382     if (!tst_is_list (SCHEME_A_ arg))
5383     break;
5384     }
5385     else
5386     {
5387     if (!tests[j - 1].fct (arg))
5388     break;
5389     }
5390 root 1.1
5391 root 1.28 if (t < pcd->arg_tests_encoding + sizeof (pcd->arg_tests_encoding) - 1 && t[1]) /* last test is replicated as necessary */
5392 root 1.2 t++;
5393 root 1.1
5394     arglist = cdr (arglist);
5395     i++;
5396     }
5397     while (i < n);
5398    
5399     if (i < n)
5400     {
5401 root 1.20 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", opname (SCHEME_V->op), i + 1, tests[j].kind);
5402 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5403     continue;
5404 root 1.1 }
5405     }
5406     }
5407     }
5408 root 1.4 #endif
5409 root 1.1
5410     ok_to_freely_gc (SCHEME_A);
5411    
5412 root 1.20 static const dispatch_func dispatch_funcs[] = {
5413     opexe_0,
5414     opexe_1,
5415     opexe_2,
5416     opexe_3,
5417     opexe_4,
5418     opexe_5,
5419     opexe_6,
5420     };
5421    
5422     if (ecb_expect_false (dispatch_funcs [pcd->func] (SCHEME_A_ SCHEME_V->op) != 0))
5423 root 1.1 return;
5424    
5425 root 1.5 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5426 root 1.1 {
5427     xwrstr ("No memory!\n");
5428     return;
5429     }
5430     }
5431     }
5432    
5433     /* ========== Initialization of internal keywords ========== */
5434    
5435     static void
5436 root 1.2 assign_syntax (SCHEME_P_ const char *name)
5437 root 1.1 {
5438     pointer x = oblist_add_by_name (SCHEME_A_ name);
5439     set_typeflag (x, typeflag (x) | T_SYNTAX);
5440     }
5441    
5442     static void
5443 root 1.2 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5444 root 1.1 {
5445     pointer x = mk_symbol (SCHEME_A_ name);
5446     pointer y = mk_proc (SCHEME_A_ op);
5447     new_slot_in_env (SCHEME_A_ x, y);
5448     }
5449    
5450     static pointer
5451     mk_proc (SCHEME_P_ enum scheme_opcodes op)
5452     {
5453     pointer y = get_cell (SCHEME_A_ NIL, NIL);
5454     set_typeflag (y, (T_PROC | T_ATOM));
5455 root 1.2 ivalue_unchecked (y) = op;
5456 root 1.1 return y;
5457     }
5458    
5459     /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5460     static int
5461     syntaxnum (pointer p)
5462     {
5463     const char *s = strvalue (car (p));
5464    
5465     switch (strlength (car (p)))
5466     {
5467     case 2:
5468     if (s[0] == 'i')
5469     return OP_IF0; /* if */
5470     else
5471     return OP_OR0; /* or */
5472    
5473     case 3:
5474     if (s[0] == 'a')
5475     return OP_AND0; /* and */
5476     else
5477     return OP_LET0; /* let */
5478    
5479     case 4:
5480     switch (s[3])
5481     {
5482     case 'e':
5483     return OP_CASE0; /* case */
5484    
5485     case 'd':
5486     return OP_COND0; /* cond */
5487    
5488     case '*':
5489 root 1.10 return OP_LET0AST;/* let* */
5490 root 1.1
5491     default:
5492     return OP_SET0; /* set! */
5493     }
5494    
5495     case 5:
5496     switch (s[2])
5497     {
5498     case 'g':
5499     return OP_BEGIN; /* begin */
5500    
5501     case 'l':
5502     return OP_DELAY; /* delay */
5503    
5504     case 'c':
5505     return OP_MACRO0; /* macro */
5506    
5507     default:
5508     return OP_QUOTE; /* quote */
5509     }
5510    
5511     case 6:
5512     switch (s[2])
5513     {
5514     case 'm':
5515     return OP_LAMBDA; /* lambda */
5516    
5517     case 'f':
5518     return OP_DEF0; /* define */
5519    
5520     default:
5521 root 1.10 return OP_LET0REC;/* letrec */
5522 root 1.1 }
5523    
5524     default:
5525     return OP_C0STREAM; /* cons-stream */
5526     }
5527     }
5528    
5529     #if USE_MULTIPLICITY
5530 root 1.23 ecb_cold scheme *
5531 root 1.1 scheme_init_new ()
5532     {
5533     scheme *sc = malloc (sizeof (scheme));
5534    
5535     if (!scheme_init (SCHEME_A))
5536     {
5537     free (SCHEME_A);
5538     return 0;
5539     }
5540     else
5541     return sc;
5542     }
5543     #endif
5544    
5545 root 1.23 ecb_cold int
5546 root 1.1 scheme_init (SCHEME_P)
5547     {
5548     int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5549     pointer x;
5550    
5551     num_set_fixnum (num_zero, 1);
5552     num_set_ivalue (num_zero, 0);
5553     num_set_fixnum (num_one, 1);
5554     num_set_ivalue (num_one, 1);
5555    
5556     #if USE_INTERFACE
5557     SCHEME_V->vptr = &vtbl;
5558     #endif
5559     SCHEME_V->gensym_cnt = 0;
5560     SCHEME_V->last_cell_seg = -1;
5561     SCHEME_V->free_cell = NIL;
5562     SCHEME_V->fcells = 0;
5563     SCHEME_V->no_memory = 0;
5564     SCHEME_V->inport = NIL;
5565     SCHEME_V->outport = NIL;
5566     SCHEME_V->save_inport = NIL;
5567     SCHEME_V->loadport = NIL;
5568     SCHEME_V->nesting = 0;
5569     SCHEME_V->interactive_repl = 0;
5570    
5571     if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5572     {
5573     #if USE_ERROR_CHECKING
5574     SCHEME_V->no_memory = 1;
5575     return 0;
5576     #endif
5577     }
5578    
5579     SCHEME_V->gc_verbose = 0;
5580     dump_stack_initialize (SCHEME_A);
5581     SCHEME_V->code = NIL;
5582 root 1.2 SCHEME_V->args = NIL;
5583     SCHEME_V->envir = NIL;
5584 root 1.1 SCHEME_V->tracing = 0;
5585    
5586     /* init NIL */
5587 root 1.2 set_typeflag (NIL, T_ATOM | T_MARK);
5588 root 1.1 set_car (NIL, NIL);
5589     set_cdr (NIL, NIL);
5590     /* init T */
5591 root 1.2 set_typeflag (S_T, T_ATOM | T_MARK);
5592 root 1.1 set_car (S_T, S_T);
5593     set_cdr (S_T, S_T);
5594     /* init F */
5595 root 1.2 set_typeflag (S_F, T_ATOM | T_MARK);
5596 root 1.1 set_car (S_F, S_F);
5597     set_cdr (S_F, S_F);
5598 root 1.7 /* init EOF_OBJ */
5599     set_typeflag (S_EOF, T_ATOM | T_MARK);
5600     set_car (S_EOF, S_EOF);
5601     set_cdr (S_EOF, S_EOF);
5602 root 1.1 /* init sink */
5603 root 1.2 set_typeflag (S_SINK, T_PAIR | T_MARK);
5604 root 1.1 set_car (S_SINK, NIL);
5605 root 1.7
5606 root 1.1 /* init c_nest */
5607     SCHEME_V->c_nest = NIL;
5608    
5609     SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5610     /* init global_env */
5611     new_frame_in_env (SCHEME_A_ NIL);
5612     SCHEME_V->global_env = SCHEME_V->envir;
5613     /* init else */
5614     x = mk_symbol (SCHEME_A_ "else");
5615     new_slot_in_env (SCHEME_A_ x, S_T);
5616    
5617 root 1.2 {
5618     static const char *syntax_names[] = {
5619     "lambda", "quote", "define", "if", "begin", "set!",
5620     "let", "let*", "letrec", "cond", "delay", "and",
5621     "or", "cons-stream", "macro", "case"
5622     };
5623    
5624     for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5625     assign_syntax (SCHEME_A_ syntax_names[i]);
5626     }
5627 root 1.1
5628 root 1.20 // TODO: should iterate via strlen, to avoid n² complexity
5629 root 1.1 for (i = 0; i < n; i++)
5630 root 1.20 if (dispatch_table[i].builtin)
5631     assign_proc (SCHEME_A_ i, opname (i));
5632 root 1.1
5633     /* initialization of global pointers to special symbols */
5634 root 1.6 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5635     SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5636     SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5637     SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5638     SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5639     SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5640     SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5641     SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5642     SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5643 root 1.1 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5644    
5645     return !SCHEME_V->no_memory;
5646     }
5647    
5648     #if USE_PORTS
5649     void
5650     scheme_set_input_port_file (SCHEME_P_ int fin)
5651     {
5652     SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5653     }
5654    
5655     void
5656     scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5657     {
5658     SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5659     }
5660    
5661     void
5662     scheme_set_output_port_file (SCHEME_P_ int fout)
5663     {
5664     SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5665     }
5666    
5667     void
5668     scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5669     {
5670     SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5671     }
5672     #endif
5673    
5674     void
5675     scheme_set_external_data (SCHEME_P_ void *p)
5676     {
5677     SCHEME_V->ext_data = p;
5678     }
5679    
5680 root 1.23 ecb_cold void
5681 root 1.1 scheme_deinit (SCHEME_P)
5682     {
5683     int i;
5684    
5685     #if SHOW_ERROR_LINE
5686     char *fname;
5687     #endif
5688    
5689     SCHEME_V->oblist = NIL;
5690     SCHEME_V->global_env = NIL;
5691     dump_stack_free (SCHEME_A);
5692     SCHEME_V->envir = NIL;
5693     SCHEME_V->code = NIL;
5694     SCHEME_V->args = NIL;
5695     SCHEME_V->value = NIL;
5696    
5697     if (is_port (SCHEME_V->inport))
5698     set_typeflag (SCHEME_V->inport, T_ATOM);
5699    
5700     SCHEME_V->inport = NIL;
5701     SCHEME_V->outport = NIL;
5702    
5703     if (is_port (SCHEME_V->save_inport))
5704     set_typeflag (SCHEME_V->save_inport, T_ATOM);
5705    
5706     SCHEME_V->save_inport = NIL;
5707    
5708     if (is_port (SCHEME_V->loadport))
5709     set_typeflag (SCHEME_V->loadport, T_ATOM);
5710    
5711     SCHEME_V->loadport = NIL;
5712     SCHEME_V->gc_verbose = 0;
5713     gc (SCHEME_A_ NIL, NIL);
5714    
5715     for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5716     free (SCHEME_V->alloc_seg[i]);
5717    
5718     #if SHOW_ERROR_LINE
5719     for (i = 0; i <= SCHEME_V->file_i; i++)
5720     {
5721     if (SCHEME_V->load_stack[i].kind & port_file)
5722     {
5723     fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5724    
5725     if (fname)
5726     free (fname);
5727     }
5728     }
5729     #endif
5730     }
5731    
5732     void
5733     scheme_load_file (SCHEME_P_ int fin)
5734     {
5735     scheme_load_named_file (SCHEME_A_ fin, 0);
5736     }
5737    
5738     void
5739     scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5740     {
5741     dump_stack_reset (SCHEME_A);
5742     SCHEME_V->envir = SCHEME_V->global_env;
5743     SCHEME_V->file_i = 0;
5744     SCHEME_V->load_stack[0].unget = -1;
5745     SCHEME_V->load_stack[0].kind = port_input | port_file;
5746     SCHEME_V->load_stack[0].rep.stdio.file = fin;
5747     #if USE_PORTS
5748     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5749     #endif
5750     SCHEME_V->retcode = 0;
5751    
5752     #if USE_PORTS
5753     if (fin == STDIN_FILENO)
5754     SCHEME_V->interactive_repl = 1;
5755     #endif
5756    
5757     #if USE_PORTS
5758     #if SHOW_ERROR_LINE
5759     SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5760    
5761     if (fin != STDIN_FILENO && filename)
5762     SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5763     #endif
5764     #endif
5765    
5766     SCHEME_V->inport = SCHEME_V->loadport;
5767     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5768     Eval_Cycle (SCHEME_A_ OP_T0LVL);
5769     set_typeflag (SCHEME_V->loadport, T_ATOM);
5770    
5771     if (SCHEME_V->retcode == 0)
5772     SCHEME_V->retcode = SCHEME_V->nesting != 0;
5773     }
5774    
5775     void
5776     scheme_load_string (SCHEME_P_ const char *cmd)
5777     {
5778     dump_stack_reset (SCHEME_A);
5779     SCHEME_V->envir = SCHEME_V->global_env;
5780     SCHEME_V->file_i = 0;
5781     SCHEME_V->load_stack[0].kind = port_input | port_string;
5782 root 1.17 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
5783     SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
5784     SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
5785 root 1.1 #if USE_PORTS
5786     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5787     #endif
5788     SCHEME_V->retcode = 0;
5789     SCHEME_V->interactive_repl = 0;
5790     SCHEME_V->inport = SCHEME_V->loadport;
5791     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5792     Eval_Cycle (SCHEME_A_ OP_T0LVL);
5793     set_typeflag (SCHEME_V->loadport, T_ATOM);
5794    
5795     if (SCHEME_V->retcode == 0)
5796     SCHEME_V->retcode = SCHEME_V->nesting != 0;
5797     }
5798    
5799     void
5800     scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
5801     {
5802     pointer x;
5803    
5804     x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
5805    
5806     if (x != NIL)
5807 root 1.2 set_slot_in_env (SCHEME_A_ x, value);
5808 root 1.1 else
5809 root 1.2 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
5810 root 1.1 }
5811    
5812     #if !STANDALONE
5813 root 1.2
5814 root 1.1 void
5815     scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
5816     {
5817     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
5818     }
5819    
5820     void
5821     scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
5822     {
5823     int i;
5824    
5825     for (i = 0; i < count; i++)
5826 root 1.2 scheme_register_foreign_func (SCHEME_A_ list + i);
5827 root 1.1 }
5828    
5829     pointer
5830     scheme_apply0 (SCHEME_P_ const char *procname)
5831     {
5832     return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
5833     }
5834    
5835     void
5836     save_from_C_call (SCHEME_P)
5837     {
5838     pointer saved_data = cons (car (S_SINK),
5839     cons (SCHEME_V->envir,
5840     SCHEME_V->dump));
5841    
5842     /* Push */
5843     SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
5844     /* Truncate the dump stack so TS will return here when done, not
5845     directly resume pre-C-call operations. */
5846     dump_stack_reset (SCHEME_A);
5847     }
5848    
5849     void
5850     restore_from_C_call (SCHEME_P)
5851     {
5852     set_car (S_SINK, caar (SCHEME_V->c_nest));
5853     SCHEME_V->envir = cadar (SCHEME_V->c_nest);
5854     SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
5855     /* Pop */
5856     SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
5857     }
5858    
5859     /* "func" and "args" are assumed to be already eval'ed. */
5860     pointer
5861     scheme_call (SCHEME_P_ pointer func, pointer args)
5862     {
5863     int old_repl = SCHEME_V->interactive_repl;
5864    
5865     SCHEME_V->interactive_repl = 0;
5866     save_from_C_call (SCHEME_A);
5867     SCHEME_V->envir = SCHEME_V->global_env;
5868     SCHEME_V->args = args;
5869     SCHEME_V->code = func;
5870     SCHEME_V->retcode = 0;
5871     Eval_Cycle (SCHEME_A_ OP_APPLY);
5872     SCHEME_V->interactive_repl = old_repl;
5873     restore_from_C_call (SCHEME_A);
5874     return SCHEME_V->value;
5875     }
5876    
5877     pointer
5878     scheme_eval (SCHEME_P_ pointer obj)
5879     {
5880     int old_repl = SCHEME_V->interactive_repl;
5881    
5882     SCHEME_V->interactive_repl = 0;
5883     save_from_C_call (SCHEME_A);
5884     SCHEME_V->args = NIL;
5885     SCHEME_V->code = obj;
5886     SCHEME_V->retcode = 0;
5887     Eval_Cycle (SCHEME_A_ OP_EVAL);
5888     SCHEME_V->interactive_repl = old_repl;
5889     restore_from_C_call (SCHEME_A);
5890     return SCHEME_V->value;
5891     }
5892    
5893     #endif
5894    
5895     /* ========== Main ========== */
5896    
5897     #if STANDALONE
5898    
5899     int
5900     main (int argc, char **argv)
5901     {
5902     # if USE_MULTIPLICITY
5903     scheme ssc;
5904 root 1.2 scheme *const SCHEME_V = &ssc;
5905 root 1.1 # else
5906     # endif
5907     int fin;
5908     char *file_name = InitFile;
5909     int retcode;
5910     int isfile = 1;
5911    
5912     if (argc == 2 && strcmp (argv[1], "-?") == 0)
5913     {
5914     xwrstr ("Usage: tinyscheme -?\n");
5915     xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
5916     xwrstr ("followed by\n");
5917     xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
5918     xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5919     xwrstr ("assuming that the executable is named tinyscheme.\n");
5920     xwrstr ("Use - as filename for stdin.\n");
5921     return 1;
5922     }
5923    
5924     if (!scheme_init (SCHEME_A))
5925     {
5926     xwrstr ("Could not initialize!\n");
5927     return 2;
5928     }
5929    
5930     # if USE_PORTS
5931     scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
5932     scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
5933     # endif
5934    
5935     argv++;
5936    
5937     #if 0
5938     if (access (file_name, 0) != 0)
5939     {
5940     char *p = getenv ("TINYSCHEMEINIT");
5941    
5942     if (p != 0)
5943 root 1.2 file_name = p;
5944 root 1.1 }
5945     #endif
5946    
5947     do
5948     {
5949     #if USE_PORTS
5950     if (strcmp (file_name, "-") == 0)
5951     fin = STDIN_FILENO;
5952     else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
5953     {
5954     pointer args = NIL;
5955    
5956     isfile = file_name[1] == '1';
5957     file_name = *argv++;
5958    
5959     if (strcmp (file_name, "-") == 0)
5960     fin = STDIN_FILENO;
5961     else if (isfile)
5962     fin = open (file_name, O_RDONLY);
5963    
5964     for (; *argv; argv++)
5965     {
5966     pointer value = mk_string (SCHEME_A_ * argv);
5967    
5968     args = cons (value, args);
5969     }
5970    
5971     args = reverse_in_place (SCHEME_A_ NIL, args);
5972     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
5973    
5974     }
5975     else
5976     fin = open (file_name, O_RDONLY);
5977     #endif
5978    
5979     if (isfile && fin < 0)
5980     {
5981     xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
5982     }
5983     else
5984     {
5985     if (isfile)
5986     scheme_load_named_file (SCHEME_A_ fin, file_name);
5987     else
5988     scheme_load_string (SCHEME_A_ file_name);
5989    
5990     #if USE_PORTS
5991     if (!isfile || fin != STDIN_FILENO)
5992     {
5993     if (SCHEME_V->retcode != 0)
5994     {
5995     xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
5996     }
5997    
5998     if (isfile)
5999     close (fin);
6000     }
6001     #endif
6002     }
6003    
6004     file_name = *argv++;
6005     }
6006     while (file_name != 0);
6007    
6008     if (argc == 1)
6009     scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6010    
6011     retcode = SCHEME_V->retcode;
6012     scheme_deinit (SCHEME_A);
6013    
6014     return retcode;
6015     }
6016    
6017     #endif
6018    
6019     /*
6020     Local variables:
6021     c-file-style: "k&r"
6022     End:
6023     */