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