ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.34
Committed: Sat Nov 28 22:14:49 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.33: +15 -23 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 root 1.31 return strvalue (car (p));
397 root 1.1 }
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 root 1.34 static pointer
1085     generate_symbol (SCHEME_P_ const char *name)
1086     {
1087     pointer x = mk_string (SCHEME_A_ name);
1088     setimmutable (x);
1089     x = immutable_cons (x, NIL);
1090     set_typeflag (x, T_SYMBOL);
1091     return x;
1092     }
1093    
1094 root 1.1 #ifndef USE_OBJECT_LIST
1095    
1096 root 1.33 static int
1097     hash_fn (const char *key, int table_size)
1098     {
1099     const unsigned char *p = key;
1100     uint32_t hash = 2166136261;
1101    
1102     while (*p)
1103     hash = (hash ^ *p++) * 16777619;
1104    
1105     return hash % table_size;
1106     }
1107 root 1.1
1108     static pointer
1109     oblist_initial_value (SCHEME_P)
1110     {
1111     return mk_vector (SCHEME_A_ 461); /* probably should be bigger */
1112     }
1113    
1114     /* returns the new symbol */
1115     static pointer
1116     oblist_add_by_name (SCHEME_P_ const char *name)
1117     {
1118 root 1.34 pointer x = generate_symbol (SCHEME_A_ name);
1119     int location = hash_fn (name, veclength (SCHEME_V->oblist));
1120 root 1.28 vector_set (SCHEME_V->oblist, location, immutable_cons (x, vector_get (SCHEME_V->oblist, location)));
1121 root 1.1 return x;
1122     }
1123    
1124 root 1.23 ecb_inline pointer
1125 root 1.1 oblist_find_by_name (SCHEME_P_ const char *name)
1126     {
1127     int location;
1128     pointer x;
1129     char *s;
1130    
1131 root 1.7 location = hash_fn (name, veclength (SCHEME_V->oblist));
1132 root 1.1
1133 root 1.28 for (x = vector_get (SCHEME_V->oblist, location); x != NIL; x = cdr (x))
1134 root 1.1 {
1135     s = symname (car (x));
1136    
1137     /* case-insensitive, per R5RS section 2 */
1138     if (stricmp (name, s) == 0)
1139     return car (x);
1140     }
1141    
1142     return NIL;
1143     }
1144    
1145     static pointer
1146     oblist_all_symbols (SCHEME_P)
1147     {
1148     int i;
1149     pointer x;
1150     pointer ob_list = NIL;
1151    
1152 root 1.7 for (i = 0; i < veclength (SCHEME_V->oblist); i++)
1153 root 1.28 for (x = vector_get (SCHEME_V->oblist, i); x != NIL; x = cdr (x))
1154 root 1.1 ob_list = cons (x, ob_list);
1155    
1156     return ob_list;
1157     }
1158    
1159     #else
1160    
1161     static pointer
1162     oblist_initial_value (SCHEME_P)
1163     {
1164     return NIL;
1165     }
1166    
1167 root 1.23 ecb_inline pointer
1168 root 1.1 oblist_find_by_name (SCHEME_P_ const char *name)
1169     {
1170     pointer x;
1171     char *s;
1172    
1173     for (x = SCHEME_V->oblist; x != NIL; x = cdr (x))
1174     {
1175     s = symname (car (x));
1176    
1177     /* case-insensitive, per R5RS section 2 */
1178     if (stricmp (name, s) == 0)
1179     return car (x);
1180     }
1181    
1182     return NIL;
1183     }
1184    
1185     /* returns the new symbol */
1186     static pointer
1187     oblist_add_by_name (SCHEME_P_ const char *name)
1188     {
1189 root 1.31 pointer x = mk_string (SCHEME_A_ name);
1190 root 1.1 set_typeflag (x, T_SYMBOL);
1191 root 1.31 setimmutable (x);
1192 root 1.1 SCHEME_V->oblist = immutable_cons (x, SCHEME_V->oblist);
1193     return x;
1194     }
1195    
1196     static pointer
1197     oblist_all_symbols (SCHEME_P)
1198     {
1199     return SCHEME_V->oblist;
1200     }
1201    
1202     #endif
1203    
1204     #if USE_PORTS
1205     static pointer
1206     mk_port (SCHEME_P_ port *p)
1207     {
1208     pointer x = get_cell (SCHEME_A_ NIL, NIL);
1209    
1210     set_typeflag (x, T_PORT | T_ATOM);
1211     x->object.port = p;
1212    
1213     return x;
1214     }
1215     #endif
1216    
1217     pointer
1218     mk_foreign_func (SCHEME_P_ foreign_func f)
1219     {
1220     pointer x = get_cell (SCHEME_A_ NIL, NIL);
1221    
1222     set_typeflag (x, (T_FOREIGN | T_ATOM));
1223     x->object.ff = f;
1224    
1225     return x;
1226     }
1227    
1228     INTERFACE pointer
1229     mk_character (SCHEME_P_ int c)
1230     {
1231     pointer x = get_cell (SCHEME_A_ NIL, NIL);
1232    
1233     set_typeflag (x, (T_CHARACTER | T_ATOM));
1234 root 1.26 set_ivalue (x, c & 0xff);
1235    
1236 root 1.1 return x;
1237     }
1238    
1239     /* get number atom (integer) */
1240     INTERFACE pointer
1241 root 1.26 mk_integer (SCHEME_P_ long n)
1242 root 1.1 {
1243     pointer x = get_cell (SCHEME_A_ NIL, NIL);
1244    
1245 root 1.26 set_typeflag (x, (T_INTEGER | T_ATOM));
1246     set_ivalue (x, n);
1247    
1248 root 1.1 return x;
1249     }
1250    
1251     INTERFACE pointer
1252     mk_real (SCHEME_P_ RVALUE n)
1253     {
1254 root 1.26 #if USE_REAL
1255 root 1.1 pointer x = get_cell (SCHEME_A_ NIL, NIL);
1256    
1257 root 1.26 set_typeflag (x, (T_REAL | T_ATOM));
1258     set_rvalue (x, n);
1259    
1260 root 1.1 return x;
1261 root 1.26 #else
1262     return mk_integer (SCHEME_A_ n);
1263     #endif
1264 root 1.1 }
1265    
1266     static pointer
1267 root 1.2 mk_number (SCHEME_P_ const num n)
1268 root 1.1 {
1269 root 1.26 #if USE_REAL
1270     return num_is_fixnum (n)
1271     ? mk_integer (SCHEME_A_ num_ivalue (n))
1272     : mk_real (SCHEME_A_ num_rvalue (n));
1273     #else
1274     return mk_integer (SCHEME_A_ num_ivalue (n));
1275     #endif
1276 root 1.1 }
1277    
1278     /* allocate name to string area */
1279     static char *
1280 root 1.3 store_string (SCHEME_P_ uint32_t len_str, const char *str, char fill)
1281 root 1.1 {
1282 root 1.2 char *q = malloc (len_str + 1);
1283 root 1.1
1284 root 1.2 if (q == 0 && USE_ERROR_CHECKING)
1285 root 1.1 {
1286     SCHEME_V->no_memory = 1;
1287     return SCHEME_V->strbuff;
1288     }
1289    
1290     if (str)
1291     {
1292     int l = strlen (str);
1293    
1294     if (l > len_str)
1295     l = len_str;
1296    
1297 root 1.2 memcpy (q, str, l);
1298     q[l] = 0;
1299 root 1.1 }
1300     else
1301     {
1302     memset (q, fill, len_str);
1303     q[len_str] = 0;
1304     }
1305    
1306     return q;
1307     }
1308    
1309     INTERFACE pointer
1310 root 1.8 mk_empty_string (SCHEME_P_ uint32_t len, char fill)
1311 root 1.1 {
1312 root 1.8 pointer x = get_cell (SCHEME_A_ NIL, NIL);
1313    
1314     set_typeflag (x, T_STRING | T_ATOM);
1315     strvalue (x) = store_string (SCHEME_A_ len, 0, fill);
1316     strlength (x) = len;
1317     return x;
1318 root 1.1 }
1319    
1320     INTERFACE pointer
1321 root 1.3 mk_counted_string (SCHEME_P_ const char *str, uint32_t len)
1322 root 1.1 {
1323     pointer x = get_cell (SCHEME_A_ NIL, NIL);
1324    
1325     set_typeflag (x, T_STRING | T_ATOM);
1326     strvalue (x) = store_string (SCHEME_A_ len, str, 0);
1327     strlength (x) = len;
1328     return x;
1329     }
1330    
1331     INTERFACE pointer
1332 root 1.8 mk_string (SCHEME_P_ const char *str)
1333 root 1.1 {
1334 root 1.8 return mk_counted_string (SCHEME_A_ str, strlen (str));
1335 root 1.1 }
1336    
1337     INTERFACE pointer
1338 root 1.3 mk_vector (SCHEME_P_ uint32_t len)
1339 root 1.1 {
1340     return get_vector_object (SCHEME_A_ len, NIL);
1341     }
1342    
1343     INTERFACE void
1344 root 1.28 fill_vector (pointer vec, uint32_t start, pointer obj)
1345 root 1.1 {
1346     int i;
1347    
1348 root 1.28 for (i = start; i < veclength (vec); i++)
1349 root 1.7 vecvalue (vec)[i] = obj;
1350 root 1.1 }
1351    
1352     INTERFACE pointer
1353 root 1.28 vector_get (pointer vec, uint32_t ielem)
1354 root 1.1 {
1355 root 1.7 return vecvalue(vec)[ielem];
1356 root 1.1 }
1357    
1358     INTERFACE void
1359 root 1.28 vector_set (pointer vec, uint32_t ielem, pointer a)
1360 root 1.1 {
1361 root 1.7 vecvalue(vec)[ielem] = a;
1362 root 1.1 }
1363    
1364     /* get new symbol */
1365     INTERFACE pointer
1366     mk_symbol (SCHEME_P_ const char *name)
1367     {
1368 root 1.2 /* first check oblist */
1369     pointer x = oblist_find_by_name (SCHEME_A_ name);
1370 root 1.1
1371 root 1.2 if (x == NIL)
1372     x = oblist_add_by_name (SCHEME_A_ name);
1373 root 1.1
1374 root 1.2 return x;
1375 root 1.1 }
1376    
1377     INTERFACE pointer
1378     gensym (SCHEME_P)
1379     {
1380     pointer x;
1381 root 1.34 char name[40] = "gensym-";
1382     xnum (name + 7, SCHEME_V->gensym_cnt);
1383 root 1.1
1384 root 1.34 return generate_symbol (SCHEME_A_ name);
1385 root 1.1 }
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     #ifndef USE_ALIST_ENV
2819    
2820     /*
2821     * In this implementation, each frame of the environment may be
2822     * a hash table: a vector of alists hashed by variable name.
2823     * In practice, we use a vector only for the initial frame;
2824     * subsequent frames are too small and transient for the lookup
2825     * speed to out-weigh the cost of making a new vector.
2826     */
2827    
2828     static void
2829     new_frame_in_env (SCHEME_P_ pointer old_env)
2830     {
2831     pointer new_frame;
2832    
2833     /* The interaction-environment has about 300 variables in it. */
2834     if (old_env == NIL)
2835     new_frame = mk_vector (SCHEME_A_ 461);
2836     else
2837     new_frame = NIL;
2838    
2839     SCHEME_V->envir = immutable_cons (new_frame, old_env);
2840     setenvironment (SCHEME_V->envir);
2841     }
2842    
2843 root 1.31 static uint32_t
2844     sym_hash (pointer sym, uint32_t size)
2845     {
2846     uintptr_t ptr = (uintptr_t)sym;
2847    
2848     #if 0
2849 root 1.33 /* table size is prime, so why mix */
2850 root 1.31 ptr += ptr >> 32;
2851     ptr += ptr >> 16;
2852     ptr += ptr >> 8;
2853     #endif
2854    
2855     return ptr % size;
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.31 int location = sym_hash (variable, veclength (car (env)));
2866 root 1.28 vector_set (car (env), location, immutable_cons (slot, vector_get (car (env), location)));
2867 root 1.1 }
2868     else
2869     set_car (env, immutable_cons (slot, car (env)));
2870     }
2871    
2872     static pointer
2873     find_slot_in_env (SCHEME_P_ pointer env, pointer hdl, int all)
2874     {
2875     pointer x, y;
2876    
2877     for (x = env; x != NIL; x = cdr (x))
2878     {
2879     if (is_vector (car (x)))
2880     {
2881 root 1.31 int location = sym_hash (hdl, veclength (car (x)));
2882 root 1.28 y = vector_get (car (x), location);
2883 root 1.1 }
2884     else
2885     y = car (x);
2886    
2887     for (; y != NIL; y = cdr (y))
2888     if (caar (y) == hdl)
2889     break;
2890    
2891     if (y != NIL)
2892 root 1.29 return car (y);
2893 root 1.1
2894     if (!all)
2895 root 1.29 break;
2896 root 1.1 }
2897    
2898     return NIL;
2899     }
2900    
2901     #else /* USE_ALIST_ENV */
2902    
2903 root 1.23 ecb_inline void
2904 root 1.1 new_frame_in_env (SCHEME_P_ pointer old_env)
2905     {
2906     SCHEME_V->envir = immutable_cons (NIL, old_env);
2907     setenvironment (SCHEME_V->envir);
2908     }
2909    
2910 root 1.23 ecb_inline void
2911 root 1.1 new_slot_spec_in_env (SCHEME_P_ pointer env, pointer variable, pointer value)
2912     {
2913     set_car (env, immutable_cons (immutable_cons (variable, value), car (env)));
2914     }
2915    
2916     static pointer
2917     find_slot_in_env (SCHEME_P_ pointer env, pointer hdl, int all)
2918     {
2919     pointer x, y;
2920    
2921     for (x = env; x != NIL; x = cdr (x))
2922     {
2923     for (y = car (x); y != NIL; y = cdr (y))
2924     if (caar (y) == hdl)
2925     break;
2926    
2927     if (y != NIL)
2928 root 1.32 return car (y);
2929 root 1.1 break;
2930    
2931     if (!all)
2932 root 1.32 break;
2933 root 1.1 }
2934    
2935     return NIL;
2936     }
2937    
2938     #endif /* USE_ALIST_ENV else */
2939    
2940 root 1.23 ecb_inline void
2941 root 1.1 new_slot_in_env (SCHEME_P_ pointer variable, pointer value)
2942     {
2943     new_slot_spec_in_env (SCHEME_A_ SCHEME_V->envir, variable, value);
2944     }
2945    
2946 root 1.23 ecb_inline void
2947 root 1.1 set_slot_in_env (SCHEME_P_ pointer slot, pointer value)
2948     {
2949     set_cdr (slot, value);
2950     }
2951    
2952 root 1.23 ecb_inline pointer
2953 root 1.1 slot_value_in_env (pointer slot)
2954     {
2955     return cdr (slot);
2956     }
2957    
2958     /* ========== Evaluation Cycle ========== */
2959    
2960 root 1.20 static int
2961 root 1.1 xError_1 (SCHEME_P_ const char *s, pointer a)
2962     {
2963     #if USE_ERROR_HOOK
2964     pointer x;
2965     pointer hdl = SCHEME_V->ERROR_HOOK;
2966     #endif
2967    
2968     #if USE_PRINTF
2969     #if SHOW_ERROR_LINE
2970     char sbuf[STRBUFFSIZE];
2971    
2972     /* make sure error is not in REPL */
2973     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)
2974     {
2975     int ln = SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line;
2976     const char *fname = SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.filename;
2977    
2978     /* should never happen */
2979     if (!fname)
2980     fname = "<unknown>";
2981    
2982     /* we started from 0 */
2983     ln++;
2984     snprintf (sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s);
2985    
2986     s = sbuf;
2987     }
2988     #endif
2989     #endif
2990    
2991     #if USE_ERROR_HOOK
2992     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, hdl, 1);
2993    
2994     if (x != NIL)
2995     {
2996 root 1.7 pointer code = a
2997     ? cons (cons (SCHEME_V->QUOTE, cons (a, NIL)), NIL)
2998     : NIL;
2999    
3000     code = cons (mk_string (SCHEME_A_ s), code);
3001     setimmutable (car (code));
3002     SCHEME_V->code = cons (slot_value_in_env (x), code);
3003 root 1.1 SCHEME_V->op = OP_EVAL;
3004    
3005 root 1.20 return 0;
3006 root 1.1 }
3007     #endif
3008    
3009     if (a)
3010     SCHEME_V->args = cons (a, NIL);
3011     else
3012     SCHEME_V->args = NIL;
3013    
3014     SCHEME_V->args = cons (mk_string (SCHEME_A_ s), SCHEME_V->args);
3015     setimmutable (car (SCHEME_V->args));
3016 root 1.2 SCHEME_V->op = OP_ERR0;
3017 root 1.20
3018     return 0;
3019 root 1.1 }
3020    
3021     #define Error_1(s, a) return xError_1(SCHEME_A_ USE_ERROR_CHECKING ? s : "", a)
3022     #define Error_0(s) Error_1 (s, 0)
3023    
3024     /* Too small to turn into function */
3025 root 1.2 #define BEGIN do {
3026     #define END } while (0)
3027     #define s_goto(a) BEGIN \
3028     SCHEME_V->op = a; \
3029 root 1.20 return 0; END
3030 root 1.1
3031 root 1.2 #define s_return(a) return xs_return (SCHEME_A_ a)
3032 root 1.1
3033     #ifndef USE_SCHEME_STACK
3034    
3035     /* this structure holds all the interpreter's registers */
3036     struct dump_stack_frame
3037     {
3038     enum scheme_opcodes op;
3039     pointer args;
3040     pointer envir;
3041     pointer code;
3042     };
3043    
3044     # define STACK_GROWTH 3
3045    
3046     static void
3047     s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3048     {
3049     int nframes = (uintptr_t)SCHEME_V->dump;
3050     struct dump_stack_frame *next_frame;
3051    
3052     /* enough room for the next frame? */
3053     if (nframes >= SCHEME_V->dump_size)
3054     {
3055     SCHEME_V->dump_size += STACK_GROWTH;
3056     SCHEME_V->dump_base = realloc (SCHEME_V->dump_base, sizeof (struct dump_stack_frame) * SCHEME_V->dump_size);
3057     }
3058    
3059     next_frame = SCHEME_V->dump_base + nframes;
3060 root 1.2
3061     next_frame->op = op;
3062     next_frame->args = args;
3063 root 1.1 next_frame->envir = SCHEME_V->envir;
3064 root 1.16 next_frame->code = code;
3065 root 1.2
3066 root 1.1 SCHEME_V->dump = (pointer)(uintptr_t)(nframes + 1);
3067     }
3068    
3069 root 1.20 static int
3070 root 1.1 xs_return (SCHEME_P_ pointer a)
3071     {
3072     int nframes = (uintptr_t)SCHEME_V->dump;
3073     struct dump_stack_frame *frame;
3074    
3075     SCHEME_V->value = a;
3076    
3077     if (nframes <= 0)
3078 root 1.20 return -1;
3079 root 1.1
3080 root 1.2 frame = &SCHEME_V->dump_base[--nframes];
3081     SCHEME_V->op = frame->op;
3082     SCHEME_V->args = frame->args;
3083 root 1.1 SCHEME_V->envir = frame->envir;
3084 root 1.2 SCHEME_V->code = frame->code;
3085     SCHEME_V->dump = (pointer)(uintptr_t)nframes;
3086 root 1.1
3087 root 1.20 return 0;
3088 root 1.1 }
3089    
3090 root 1.23 ecb_inline void
3091 root 1.1 dump_stack_reset (SCHEME_P)
3092     {
3093     /* in this implementation, SCHEME_V->dump is the number of frames on the stack */
3094 root 1.2 SCHEME_V->dump = (pointer)+0;
3095 root 1.1 }
3096    
3097 root 1.23 ecb_inline void
3098 root 1.1 dump_stack_initialize (SCHEME_P)
3099     {
3100     SCHEME_V->dump_size = 0;
3101 root 1.2 SCHEME_V->dump_base = 0;
3102 root 1.1 dump_stack_reset (SCHEME_A);
3103     }
3104    
3105     static void
3106     dump_stack_free (SCHEME_P)
3107     {
3108     free (SCHEME_V->dump_base);
3109 root 1.2 SCHEME_V->dump_base = 0;
3110 root 1.1 SCHEME_V->dump = (pointer)0;
3111     SCHEME_V->dump_size = 0;
3112     }
3113    
3114     static void
3115     dump_stack_mark (SCHEME_P)
3116     {
3117     int nframes = (uintptr_t)SCHEME_V->dump;
3118     int i;
3119    
3120     for (i = 0; i < nframes; i++)
3121     {
3122     struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3123    
3124     mark (frame->args);
3125     mark (frame->envir);
3126     mark (frame->code);
3127     }
3128     }
3129    
3130     static pointer
3131     ss_get_cont (SCHEME_P)
3132     {
3133     int nframes = (uintptr_t)SCHEME_V->dump;
3134     int i;
3135    
3136     pointer cont = NIL;
3137    
3138     for (i = nframes; i--; )
3139     {
3140     struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3141    
3142     cont = cons (mk_integer (SCHEME_A_ frame->op),
3143     cons (frame->args,
3144     cons (frame->envir,
3145     cons (frame->code,
3146     cont))));
3147     }
3148    
3149     return cont;
3150     }
3151    
3152     static void
3153     ss_set_cont (SCHEME_P_ pointer cont)
3154     {
3155     int i = 0;
3156     struct dump_stack_frame *frame = SCHEME_V->dump_base;
3157    
3158     while (cont != NIL)
3159     {
3160 root 1.26 frame->op = ivalue_unchecked (car (cont)); cont = cdr (cont);
3161     frame->args = car (cont) ; cont = cdr (cont);
3162     frame->envir = car (cont) ; cont = cdr (cont);
3163     frame->code = car (cont) ; cont = cdr (cont);
3164 root 1.1
3165     ++frame;
3166     ++i;
3167     }
3168    
3169     SCHEME_V->dump = (pointer)(uintptr_t)i;
3170     }
3171    
3172     #else
3173    
3174 root 1.23 ecb_inline void
3175 root 1.1 dump_stack_reset (SCHEME_P)
3176     {
3177     SCHEME_V->dump = NIL;
3178     }
3179    
3180 root 1.23 ecb_inline void
3181 root 1.1 dump_stack_initialize (SCHEME_P)
3182     {
3183     dump_stack_reset (SCHEME_A);
3184     }
3185    
3186     static void
3187     dump_stack_free (SCHEME_P)
3188     {
3189     SCHEME_V->dump = NIL;
3190     }
3191    
3192 root 1.20 static int
3193 root 1.1 xs_return (SCHEME_P_ pointer a)
3194     {
3195     pointer dump = SCHEME_V->dump;
3196    
3197     SCHEME_V->value = a;
3198    
3199     if (dump == NIL)
3200 root 1.20 return -1;
3201 root 1.1
3202 root 1.26 SCHEME_V->op = ivalue_unchecked (car (dump)); dump = cdr (dump);
3203     SCHEME_V->args = car (dump) ; dump = cdr (dump);
3204     SCHEME_V->envir = car (dump) ; dump = cdr (dump);
3205     SCHEME_V->code = car (dump) ; dump = cdr (dump);
3206 root 1.1
3207     SCHEME_V->dump = dump;
3208    
3209 root 1.20 return 0;
3210 root 1.1 }
3211    
3212     static void
3213     s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3214     {
3215     SCHEME_V->dump = cons (mk_integer (SCHEME_A_ op),
3216     cons (args,
3217     cons (SCHEME_V->envir,
3218     cons (code,
3219     SCHEME_V->dump))));
3220     }
3221    
3222     static void
3223     dump_stack_mark (SCHEME_P)
3224     {
3225     mark (SCHEME_V->dump);
3226     }
3227    
3228     static pointer
3229     ss_get_cont (SCHEME_P)
3230     {
3231     return SCHEME_V->dump;
3232     }
3233    
3234     static void
3235     ss_set_cont (SCHEME_P_ pointer cont)
3236     {
3237     SCHEME_V->dump = cont;
3238     }
3239    
3240     #endif
3241    
3242     #define s_retbool(tf) s_return ((tf) ? S_T : S_F)
3243    
3244 root 1.20 static int
3245 root 1.1 opexe_0 (SCHEME_P_ enum scheme_opcodes op)
3246     {
3247 root 1.16 pointer args = SCHEME_V->args;
3248 root 1.1 pointer x, y;
3249    
3250     switch (op)
3251     {
3252     case OP_LOAD: /* load */
3253     if (file_interactive (SCHEME_A))
3254     {
3255 root 1.16 xwrstr ("Loading "); xwrstr (strvalue (car (args))); xwrstr ("\n");
3256     //D fprintf (SCHEME_V->outport->object.port->rep.stdio.file, "Loading %s\n", strvalue (car (args)));
3257 root 1.1 }
3258    
3259 root 1.16 if (!file_push (SCHEME_A_ strvalue (car (args))))
3260     Error_1 ("unable to open", car (args));
3261 root 1.1 else
3262     {
3263     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
3264     s_goto (OP_T0LVL);
3265     }
3266    
3267     case OP_T0LVL: /* top level */
3268    
3269     /* If we reached the end of file, this loop is done. */
3270     if (SCHEME_V->loadport->object.port->kind & port_saw_EOF)
3271     {
3272     if (SCHEME_V->file_i == 0)
3273     {
3274     SCHEME_V->args = NIL;
3275     s_goto (OP_QUIT);
3276     }
3277     else
3278     {
3279     file_pop (SCHEME_A);
3280     s_return (SCHEME_V->value);
3281     }
3282    
3283     /* NOTREACHED */
3284     }
3285    
3286     /* If interactive, be nice to user. */
3287     if (file_interactive (SCHEME_A))
3288     {
3289     SCHEME_V->envir = SCHEME_V->global_env;
3290     dump_stack_reset (SCHEME_A);
3291     putstr (SCHEME_A_ "\n");
3292     putstr (SCHEME_A_ prompt);
3293     }
3294    
3295     /* Set up another iteration of REPL */
3296     SCHEME_V->nesting = 0;
3297     SCHEME_V->save_inport = SCHEME_V->inport;
3298     SCHEME_V->inport = SCHEME_V->loadport;
3299     s_save (SCHEME_A_ OP_T0LVL, NIL, NIL);
3300     s_save (SCHEME_A_ OP_VALUEPRINT, NIL, NIL);
3301     s_save (SCHEME_A_ OP_T1LVL, NIL, NIL);
3302     s_goto (OP_READ_INTERNAL);
3303    
3304     case OP_T1LVL: /* top level */
3305 root 1.7 SCHEME_V->code = SCHEME_V->value;
3306 root 1.1 SCHEME_V->inport = SCHEME_V->save_inport;
3307     s_goto (OP_EVAL);
3308    
3309     case OP_READ_INTERNAL: /* internal read */
3310     SCHEME_V->tok = token (SCHEME_A);
3311    
3312     if (SCHEME_V->tok == TOK_EOF)
3313 root 1.2 s_return (S_EOF);
3314 root 1.1
3315     s_goto (OP_RDSEXPR);
3316    
3317     case OP_GENSYM:
3318     s_return (gensym (SCHEME_A));
3319    
3320     case OP_VALUEPRINT: /* print evaluation result */
3321    
3322     /* OP_VALUEPRINT is always pushed, because when changing from
3323     non-interactive to interactive mode, it needs to be
3324     already on the stack */
3325     #if USE_TRACING
3326     if (SCHEME_V->tracing)
3327 root 1.2 putstr (SCHEME_A_ "\nGives: ");
3328 root 1.1 #endif
3329    
3330     if (file_interactive (SCHEME_A))
3331     {
3332     SCHEME_V->print_flag = 1;
3333     SCHEME_V->args = SCHEME_V->value;
3334     s_goto (OP_P0LIST);
3335     }
3336     else
3337 root 1.2 s_return (SCHEME_V->value);
3338 root 1.1
3339     case OP_EVAL: /* main part of evaluation */
3340     #if USE_TRACING
3341     if (SCHEME_V->tracing)
3342     {
3343     /*s_save(SCHEME_A_ OP_VALUEPRINT,NIL,NIL); */
3344 root 1.16 s_save (SCHEME_A_ OP_REAL_EVAL, args, SCHEME_V->code);
3345 root 1.1 SCHEME_V->args = SCHEME_V->code;
3346     putstr (SCHEME_A_ "\nEval: ");
3347     s_goto (OP_P0LIST);
3348     }
3349    
3350     /* fall through */
3351 root 1.2
3352 root 1.1 case OP_REAL_EVAL:
3353     #endif
3354     if (is_symbol (SCHEME_V->code)) /* symbol */
3355     {
3356     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3357    
3358     if (x != NIL)
3359     s_return (slot_value_in_env (x));
3360     else
3361     Error_1 ("eval: unbound variable:", SCHEME_V->code);
3362     }
3363     else if (is_pair (SCHEME_V->code))
3364     {
3365 root 1.7 x = car (SCHEME_V->code);
3366    
3367     if (is_syntax (x)) /* SYNTAX */
3368 root 1.1 {
3369     SCHEME_V->code = cdr (SCHEME_V->code);
3370     s_goto (syntaxnum (x));
3371     }
3372     else /* first, eval top element and eval arguments */
3373     {
3374     s_save (SCHEME_A_ OP_E0ARGS, NIL, SCHEME_V->code);
3375     /* If no macros => s_save(SCHEME_A_ OP_E1ARGS, NIL, cdr(SCHEME_V->code)); */
3376 root 1.7 SCHEME_V->code = x;
3377 root 1.1 s_goto (OP_EVAL);
3378     }
3379     }
3380     else
3381     s_return (SCHEME_V->code);
3382    
3383     case OP_E0ARGS: /* eval arguments */
3384     if (is_macro (SCHEME_V->value)) /* macro expansion */
3385     {
3386     s_save (SCHEME_A_ OP_DOMACRO, NIL, NIL);
3387     SCHEME_V->args = cons (SCHEME_V->code, NIL);
3388     SCHEME_V->code = SCHEME_V->value;
3389     s_goto (OP_APPLY);
3390     }
3391     else
3392     {
3393     SCHEME_V->code = cdr (SCHEME_V->code);
3394     s_goto (OP_E1ARGS);
3395     }
3396    
3397     case OP_E1ARGS: /* eval arguments */
3398 root 1.16 args = cons (SCHEME_V->value, args);
3399 root 1.1
3400     if (is_pair (SCHEME_V->code)) /* continue */
3401     {
3402 root 1.16 s_save (SCHEME_A_ OP_E1ARGS, args, cdr (SCHEME_V->code));
3403 root 1.1 SCHEME_V->code = car (SCHEME_V->code);
3404     SCHEME_V->args = NIL;
3405     s_goto (OP_EVAL);
3406     }
3407     else /* end */
3408     {
3409 root 1.16 args = reverse_in_place (SCHEME_A_ NIL, args);
3410     SCHEME_V->code = car (args);
3411     SCHEME_V->args = cdr (args);
3412 root 1.1 s_goto (OP_APPLY);
3413     }
3414    
3415     #if USE_TRACING
3416    
3417     case OP_TRACING:
3418     {
3419     int tr = SCHEME_V->tracing;
3420    
3421 root 1.26 SCHEME_V->tracing = ivalue_unchecked (car (args));
3422 root 1.1 s_return (mk_integer (SCHEME_A_ tr));
3423     }
3424    
3425     #endif
3426    
3427     case OP_APPLY: /* apply 'code' to 'args' */
3428     #if USE_TRACING
3429     if (SCHEME_V->tracing)
3430     {
3431 root 1.16 s_save (SCHEME_A_ OP_REAL_APPLY, args, SCHEME_V->code);
3432 root 1.1 SCHEME_V->print_flag = 1;
3433 root 1.16 /* args=cons(SCHEME_V->code,args); */
3434 root 1.1 putstr (SCHEME_A_ "\nApply to: ");
3435     s_goto (OP_P0LIST);
3436     }
3437    
3438     /* fall through */
3439 root 1.2
3440 root 1.1 case OP_REAL_APPLY:
3441     #endif
3442     if (is_proc (SCHEME_V->code))
3443 root 1.18 s_goto (procnum (SCHEME_V->code)); /* PROCEDURE */
3444 root 1.1 else if (is_foreign (SCHEME_V->code))
3445     {
3446     /* Keep nested calls from GC'ing the arglist */
3447 root 1.16 push_recent_alloc (SCHEME_A_ args, NIL);
3448     x = SCHEME_V->code->object.ff (SCHEME_A_ args);
3449 root 1.1
3450     s_return (x);
3451     }
3452     else if (is_closure (SCHEME_V->code) || is_macro (SCHEME_V->code) || is_promise (SCHEME_V->code)) /* CLOSURE */
3453     {
3454     /* Should not accept promise */
3455     /* make environment */
3456     new_frame_in_env (SCHEME_A_ closure_env (SCHEME_V->code));
3457    
3458 root 1.16 for (x = car (closure_code (SCHEME_V->code)), y = args; is_pair (x); x = cdr (x), y = cdr (y))
3459 root 1.1 {
3460     if (y == NIL)
3461 root 1.2 Error_0 ("not enough arguments");
3462 root 1.1 else
3463 root 1.2 new_slot_in_env (SCHEME_A_ car (x), car (y));
3464 root 1.1 }
3465    
3466     if (x == NIL)
3467     {
3468 root 1.2 /*--
3469     * if (y != NIL) {
3470     * Error_0("too many arguments");
3471     * }
3472     */
3473 root 1.1 }
3474     else if (is_symbol (x))
3475     new_slot_in_env (SCHEME_A_ x, y);
3476     else
3477 root 1.2 Error_1 ("syntax error in closure: not a symbol:", x);
3478 root 1.1
3479     SCHEME_V->code = cdr (closure_code (SCHEME_V->code));
3480     SCHEME_V->args = NIL;
3481     s_goto (OP_BEGIN);
3482     }
3483     else if (is_continuation (SCHEME_V->code)) /* CONTINUATION */
3484     {
3485     ss_set_cont (SCHEME_A_ cont_dump (SCHEME_V->code));
3486 root 1.16 s_return (args != NIL ? car (args) : NIL);
3487 root 1.1 }
3488     else
3489     Error_0 ("illegal function");
3490    
3491     case OP_DOMACRO: /* do macro */
3492     SCHEME_V->code = SCHEME_V->value;
3493     s_goto (OP_EVAL);
3494    
3495     #if 1
3496    
3497     case OP_LAMBDA: /* lambda */
3498     /* If the hook is defined, apply it to SCHEME_V->code, otherwise
3499     set SCHEME_V->value fall thru */
3500     {
3501     pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->COMPILE_HOOK, 1);
3502    
3503     if (f != NIL)
3504     {
3505 root 1.16 s_save (SCHEME_A_ OP_LAMBDA1, args, SCHEME_V->code);
3506 root 1.1 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3507     SCHEME_V->code = slot_value_in_env (f);
3508     s_goto (OP_APPLY);
3509     }
3510    
3511     SCHEME_V->value = SCHEME_V->code;
3512     /* Fallthru */
3513     }
3514    
3515     case OP_LAMBDA1:
3516     s_return (mk_closure (SCHEME_A_ SCHEME_V->value, SCHEME_V->envir));
3517    
3518     #else
3519    
3520     case OP_LAMBDA: /* lambda */
3521     s_return (mk_closure (SCHEME_A_ SCHEME_V->code, SCHEME_V->envir));
3522    
3523     #endif
3524    
3525     case OP_MKCLOSURE: /* make-closure */
3526 root 1.16 x = car (args);
3527 root 1.1
3528     if (car (x) == SCHEME_V->LAMBDA)
3529     x = cdr (x);
3530    
3531 root 1.16 if (cdr (args) == NIL)
3532 root 1.1 y = SCHEME_V->envir;
3533     else
3534 root 1.16 y = cadr (args);
3535 root 1.1
3536     s_return (mk_closure (SCHEME_A_ x, y));
3537    
3538     case OP_QUOTE: /* quote */
3539     s_return (car (SCHEME_V->code));
3540    
3541     case OP_DEF0: /* define */
3542     if (is_immutable (car (SCHEME_V->code)))
3543     Error_1 ("define: unable to alter immutable", car (SCHEME_V->code));
3544    
3545     if (is_pair (car (SCHEME_V->code)))
3546     {
3547     x = caar (SCHEME_V->code);
3548     SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3549     }
3550     else
3551     {
3552     x = car (SCHEME_V->code);
3553     SCHEME_V->code = cadr (SCHEME_V->code);
3554     }
3555    
3556     if (!is_symbol (x))
3557 root 1.2 Error_0 ("variable is not a symbol");
3558 root 1.1
3559     s_save (SCHEME_A_ OP_DEF1, NIL, x);
3560     s_goto (OP_EVAL);
3561    
3562     case OP_DEF1: /* define */
3563     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3564    
3565     if (x != NIL)
3566 root 1.2 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3567 root 1.1 else
3568 root 1.2 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3569 root 1.1
3570     s_return (SCHEME_V->code);
3571    
3572    
3573     case OP_DEFP: /* defined? */
3574     x = SCHEME_V->envir;
3575    
3576 root 1.16 if (cdr (args) != NIL)
3577     x = cadr (args);
3578 root 1.1
3579 root 1.16 s_retbool (find_slot_in_env (SCHEME_A_ x, car (args), 1) != NIL);
3580 root 1.1
3581     case OP_SET0: /* set! */
3582     if (is_immutable (car (SCHEME_V->code)))
3583     Error_1 ("set!: unable to alter immutable variable", car (SCHEME_V->code));
3584    
3585     s_save (SCHEME_A_ OP_SET1, NIL, car (SCHEME_V->code));
3586     SCHEME_V->code = cadr (SCHEME_V->code);
3587     s_goto (OP_EVAL);
3588    
3589     case OP_SET1: /* set! */
3590     y = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3591    
3592     if (y != NIL)
3593     {
3594     set_slot_in_env (SCHEME_A_ y, SCHEME_V->value);
3595     s_return (SCHEME_V->value);
3596     }
3597     else
3598 root 1.2 Error_1 ("set!: unbound variable:", SCHEME_V->code);
3599 root 1.1
3600    
3601     case OP_BEGIN: /* begin */
3602     if (!is_pair (SCHEME_V->code))
3603 root 1.2 s_return (SCHEME_V->code);
3604 root 1.1
3605     if (cdr (SCHEME_V->code) != NIL)
3606 root 1.2 s_save (SCHEME_A_ OP_BEGIN, NIL, cdr (SCHEME_V->code));
3607 root 1.1
3608     SCHEME_V->code = car (SCHEME_V->code);
3609     s_goto (OP_EVAL);
3610    
3611     case OP_IF0: /* if */
3612     s_save (SCHEME_A_ OP_IF1, NIL, cdr (SCHEME_V->code));
3613     SCHEME_V->code = car (SCHEME_V->code);
3614     s_goto (OP_EVAL);
3615    
3616     case OP_IF1: /* if */
3617     if (is_true (SCHEME_V->value))
3618     SCHEME_V->code = car (SCHEME_V->code);
3619     else
3620 root 1.18 SCHEME_V->code = cadr (SCHEME_V->code); /* (if #f 1) ==> () because * car(NIL) = NIL */
3621 root 1.1 s_goto (OP_EVAL);
3622    
3623     case OP_LET0: /* let */
3624     SCHEME_V->args = NIL;
3625     SCHEME_V->value = SCHEME_V->code;
3626     SCHEME_V->code = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code);
3627     s_goto (OP_LET1);
3628    
3629     case OP_LET1: /* let (calculate parameters) */
3630 root 1.16 args = cons (SCHEME_V->value, args);
3631 root 1.1
3632     if (is_pair (SCHEME_V->code)) /* continue */
3633     {
3634     if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3635 root 1.2 Error_1 ("Bad syntax of binding spec in let :", car (SCHEME_V->code));
3636 root 1.1
3637 root 1.16 s_save (SCHEME_A_ OP_LET1, args, cdr (SCHEME_V->code));
3638 root 1.1 SCHEME_V->code = cadar (SCHEME_V->code);
3639     SCHEME_V->args = NIL;
3640     s_goto (OP_EVAL);
3641     }
3642     else /* end */
3643     {
3644 root 1.16 args = reverse_in_place (SCHEME_A_ NIL, args);
3645     SCHEME_V->code = car (args);
3646     SCHEME_V->args = cdr (args);
3647 root 1.1 s_goto (OP_LET2);
3648     }
3649    
3650     case OP_LET2: /* let */
3651     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3652    
3653 root 1.16 for (x = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code), y = args;
3654 root 1.1 y != NIL; x = cdr (x), y = cdr (y))
3655 root 1.2 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3656 root 1.1
3657     if (is_symbol (car (SCHEME_V->code))) /* named let */
3658     {
3659 root 1.16 for (x = cadr (SCHEME_V->code), args = NIL; x != NIL; x = cdr (x))
3660 root 1.1 {
3661     if (!is_pair (x))
3662     Error_1 ("Bad syntax of binding in let :", x);
3663    
3664     if (!is_list (SCHEME_A_ car (x)))
3665     Error_1 ("Bad syntax of binding in let :", car (x));
3666    
3667 root 1.16 args = cons (caar (x), args);
3668 root 1.1 }
3669    
3670 root 1.16 x = mk_closure (SCHEME_A_ cons (reverse_in_place (SCHEME_A_ NIL, args), cddr (SCHEME_V->code)),
3671     SCHEME_V->envir);
3672 root 1.1 new_slot_in_env (SCHEME_A_ car (SCHEME_V->code), x);
3673     SCHEME_V->code = cddr (SCHEME_V->code);
3674     }
3675     else
3676     {
3677     SCHEME_V->code = cdr (SCHEME_V->code);
3678     }
3679    
3680 root 1.16 SCHEME_V->args = NIL;
3681 root 1.1 s_goto (OP_BEGIN);
3682    
3683     case OP_LET0AST: /* let* */
3684     if (car (SCHEME_V->code) == NIL)
3685     {
3686     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3687     SCHEME_V->code = cdr (SCHEME_V->code);
3688     s_goto (OP_BEGIN);
3689     }
3690    
3691     if (!is_pair (car (SCHEME_V->code)) || !is_pair (caar (SCHEME_V->code)) || !is_pair (cdaar (SCHEME_V->code)))
3692     Error_1 ("Bad syntax of binding spec in let* :", car (SCHEME_V->code));
3693    
3694     s_save (SCHEME_A_ OP_LET1AST, cdr (SCHEME_V->code), car (SCHEME_V->code));
3695     SCHEME_V->code = car (cdaar (SCHEME_V->code));
3696     s_goto (OP_EVAL);
3697    
3698     case OP_LET1AST: /* let* (make new frame) */
3699     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3700     s_goto (OP_LET2AST);
3701    
3702     case OP_LET2AST: /* let* (calculate parameters) */
3703     new_slot_in_env (SCHEME_A_ caar (SCHEME_V->code), SCHEME_V->value);
3704     SCHEME_V->code = cdr (SCHEME_V->code);
3705    
3706     if (is_pair (SCHEME_V->code)) /* continue */
3707     {
3708 root 1.16 s_save (SCHEME_A_ OP_LET2AST, args, SCHEME_V->code);
3709 root 1.1 SCHEME_V->code = cadar (SCHEME_V->code);
3710     SCHEME_V->args = NIL;
3711     s_goto (OP_EVAL);
3712     }
3713     else /* end */
3714     {
3715 root 1.16 SCHEME_V->code = args;
3716 root 1.1 SCHEME_V->args = NIL;
3717     s_goto (OP_BEGIN);
3718     }
3719    
3720     case OP_LET0REC: /* letrec */
3721     new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3722     SCHEME_V->args = NIL;
3723     SCHEME_V->value = SCHEME_V->code;
3724     SCHEME_V->code = car (SCHEME_V->code);
3725     s_goto (OP_LET1REC);
3726    
3727     case OP_LET1REC: /* letrec (calculate parameters) */
3728 root 1.16 args = cons (SCHEME_V->value, args);
3729 root 1.1
3730     if (is_pair (SCHEME_V->code)) /* continue */
3731     {
3732     if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3733 root 1.2 Error_1 ("Bad syntax of binding spec in letrec :", car (SCHEME_V->code));
3734 root 1.1
3735 root 1.16 s_save (SCHEME_A_ OP_LET1REC, args, cdr (SCHEME_V->code));
3736 root 1.1 SCHEME_V->code = cadar (SCHEME_V->code);
3737     SCHEME_V->args = NIL;
3738     s_goto (OP_EVAL);
3739     }
3740     else /* end */
3741     {
3742 root 1.16 args = reverse_in_place (SCHEME_A_ NIL, args);
3743     SCHEME_V->code = car (args);
3744     SCHEME_V->args = cdr (args);
3745 root 1.1 s_goto (OP_LET2REC);
3746     }
3747    
3748     case OP_LET2REC: /* letrec */
3749 root 1.16 for (x = car (SCHEME_V->code), y = args; y != NIL; x = cdr (x), y = cdr (y))
3750 root 1.2 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3751 root 1.1
3752     SCHEME_V->code = cdr (SCHEME_V->code);
3753     SCHEME_V->args = NIL;
3754     s_goto (OP_BEGIN);
3755    
3756     case OP_COND0: /* cond */
3757     if (!is_pair (SCHEME_V->code))
3758 root 1.2 Error_0 ("syntax error in cond");
3759 root 1.1
3760     s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3761     SCHEME_V->code = caar (SCHEME_V->code);
3762     s_goto (OP_EVAL);
3763    
3764     case OP_COND1: /* cond */
3765     if (is_true (SCHEME_V->value))
3766     {
3767     if ((SCHEME_V->code = cdar (SCHEME_V->code)) == NIL)
3768 root 1.2 s_return (SCHEME_V->value);
3769 root 1.1
3770     if (car (SCHEME_V->code) == SCHEME_V->FEED_TO)
3771     {
3772     if (!is_pair (cdr (SCHEME_V->code)))
3773 root 1.2 Error_0 ("syntax error in cond");
3774 root 1.1
3775     x = cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL));
3776     SCHEME_V->code = cons (cadr (SCHEME_V->code), cons (x, NIL));
3777     s_goto (OP_EVAL);
3778     }
3779    
3780     s_goto (OP_BEGIN);
3781     }
3782     else
3783     {
3784     if ((SCHEME_V->code = cdr (SCHEME_V->code)) == NIL)
3785 root 1.2 s_return (NIL);
3786 root 1.1 else
3787     {
3788     s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3789     SCHEME_V->code = caar (SCHEME_V->code);
3790     s_goto (OP_EVAL);
3791     }
3792     }
3793    
3794     case OP_DELAY: /* delay */
3795     x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3796     set_typeflag (x, T_PROMISE);
3797     s_return (x);
3798    
3799     case OP_AND0: /* and */
3800     if (SCHEME_V->code == NIL)
3801 root 1.2 s_return (S_T);
3802 root 1.1
3803     s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3804     SCHEME_V->code = car (SCHEME_V->code);
3805     s_goto (OP_EVAL);
3806    
3807     case OP_AND1: /* and */
3808     if (is_false (SCHEME_V->value))
3809 root 1.2 s_return (SCHEME_V->value);
3810 root 1.1 else if (SCHEME_V->code == NIL)
3811 root 1.2 s_return (SCHEME_V->value);
3812 root 1.1 else
3813     {
3814     s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3815     SCHEME_V->code = car (SCHEME_V->code);
3816     s_goto (OP_EVAL);
3817     }
3818    
3819     case OP_OR0: /* or */
3820     if (SCHEME_V->code == NIL)
3821 root 1.2 s_return (S_F);
3822 root 1.1
3823     s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3824     SCHEME_V->code = car (SCHEME_V->code);
3825     s_goto (OP_EVAL);
3826    
3827     case OP_OR1: /* or */
3828     if (is_true (SCHEME_V->value))
3829 root 1.2 s_return (SCHEME_V->value);
3830 root 1.1 else if (SCHEME_V->code == NIL)
3831 root 1.2 s_return (SCHEME_V->value);
3832 root 1.1 else
3833     {
3834     s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3835     SCHEME_V->code = car (SCHEME_V->code);
3836     s_goto (OP_EVAL);
3837     }
3838    
3839     case OP_C0STREAM: /* cons-stream */
3840     s_save (SCHEME_A_ OP_C1STREAM, NIL, cdr (SCHEME_V->code));
3841     SCHEME_V->code = car (SCHEME_V->code);
3842     s_goto (OP_EVAL);
3843    
3844     case OP_C1STREAM: /* cons-stream */
3845 root 1.16 SCHEME_V->args = SCHEME_V->value; /* save SCHEME_V->value to register args for gc */
3846 root 1.1 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3847     set_typeflag (x, T_PROMISE);
3848 root 1.16 s_return (cons (args, x));
3849 root 1.1
3850     case OP_MACRO0: /* macro */
3851     if (is_pair (car (SCHEME_V->code)))
3852     {
3853     x = caar (SCHEME_V->code);
3854     SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3855     }
3856     else
3857     {
3858     x = car (SCHEME_V->code);
3859     SCHEME_V->code = cadr (SCHEME_V->code);
3860     }
3861    
3862     if (!is_symbol (x))
3863 root 1.2 Error_0 ("variable is not a symbol");
3864 root 1.1
3865     s_save (SCHEME_A_ OP_MACRO1, NIL, x);
3866     s_goto (OP_EVAL);
3867    
3868     case OP_MACRO1: /* macro */
3869     set_typeflag (SCHEME_V->value, T_MACRO);
3870     x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3871    
3872     if (x != NIL)
3873 root 1.2 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3874 root 1.1 else
3875 root 1.2 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3876 root 1.1
3877     s_return (SCHEME_V->code);
3878    
3879     case OP_CASE0: /* case */
3880     s_save (SCHEME_A_ OP_CASE1, NIL, cdr (SCHEME_V->code));
3881     SCHEME_V->code = car (SCHEME_V->code);
3882     s_goto (OP_EVAL);
3883    
3884     case OP_CASE1: /* case */
3885     for (x = SCHEME_V->code; x != NIL; x = cdr (x))
3886     {
3887     if (!is_pair (y = caar (x)))
3888 root 1.2 break;
3889 root 1.1
3890     for (; y != NIL; y = cdr (y))
3891 root 1.16 if (eqv (car (y), SCHEME_V->value))
3892 root 1.2 break;
3893 root 1.1
3894     if (y != NIL)
3895 root 1.2 break;
3896 root 1.1 }
3897    
3898     if (x != NIL)
3899     {
3900     if (is_pair (caar (x)))
3901     {
3902     SCHEME_V->code = cdar (x);
3903     s_goto (OP_BEGIN);
3904     }
3905     else /* else */
3906     {
3907     s_save (SCHEME_A_ OP_CASE2, NIL, cdar (x));
3908     SCHEME_V->code = caar (x);
3909     s_goto (OP_EVAL);
3910     }
3911     }
3912     else
3913 root 1.2 s_return (NIL);
3914 root 1.1
3915     case OP_CASE2: /* case */
3916     if (is_true (SCHEME_V->value))
3917 root 1.2 s_goto (OP_BEGIN);
3918 root 1.1 else
3919 root 1.2 s_return (NIL);
3920 root 1.1
3921     case OP_PAPPLY: /* apply */
3922 root 1.16 SCHEME_V->code = car (args);
3923     SCHEME_V->args = list_star (SCHEME_A_ cdr (args));
3924     /*SCHEME_V->args = cadr(args); */
3925 root 1.1 s_goto (OP_APPLY);
3926    
3927     case OP_PEVAL: /* eval */
3928 root 1.16 if (cdr (args) != NIL)
3929     SCHEME_V->envir = cadr (args);
3930 root 1.1
3931 root 1.16 SCHEME_V->code = car (args);
3932 root 1.1 s_goto (OP_EVAL);
3933    
3934     case OP_CONTINUATION: /* call-with-current-continuation */
3935 root 1.16 SCHEME_V->code = car (args);
3936 root 1.7 SCHEME_V->args = cons (mk_continuation (SCHEME_A_ ss_get_cont (SCHEME_A)), NIL);
3937 root 1.1 s_goto (OP_APPLY);
3938     }
3939    
3940 root 1.24 if (USE_ERROR_CHECKING) abort ();
3941 root 1.1 }
3942    
3943 root 1.20 static int
3944     opexe_1 (SCHEME_P_ enum scheme_opcodes op)
3945 root 1.1 {
3946 root 1.16 pointer args = SCHEME_V->args;
3947     pointer x = car (args);
3948 root 1.1 num v;
3949    
3950     switch (op)
3951     {
3952     #if USE_MATH
3953     case OP_INEX2EX: /* inexact->exact */
3954 root 1.26 {
3955     if (is_integer (x))
3956     s_return (x);
3957    
3958     RVALUE r = rvalue_unchecked (x);
3959    
3960     if (r == (RVALUE)(IVALUE)r)
3961     s_return (mk_integer (SCHEME_A_ rvalue_unchecked (x)));
3962     else
3963     Error_1 ("inexact->exact: not integral:", x);
3964     }
3965 root 1.1
3966 root 1.16 case OP_EXP: s_return (mk_real (SCHEME_A_ exp (rvalue (x))));
3967     case OP_LOG: s_return (mk_real (SCHEME_A_ log (rvalue (x))));
3968     case OP_SIN: s_return (mk_real (SCHEME_A_ sin (rvalue (x))));
3969     case OP_COS: s_return (mk_real (SCHEME_A_ cos (rvalue (x))));
3970     case OP_TAN: s_return (mk_real (SCHEME_A_ tan (rvalue (x))));
3971     case OP_ASIN: s_return (mk_real (SCHEME_A_ asin (rvalue (x))));
3972     case OP_ACOS: s_return (mk_real (SCHEME_A_ acos (rvalue (x))));
3973 root 1.1
3974     case OP_ATAN:
3975 root 1.16 if (cdr (args) == NIL)
3976 root 1.2 s_return (mk_real (SCHEME_A_ atan (rvalue (x))));
3977 root 1.1 else
3978     {
3979 root 1.16 pointer y = cadr (args);
3980 root 1.1 s_return (mk_real (SCHEME_A_ atan2 (rvalue (x), rvalue (y))));
3981     }
3982    
3983     case OP_SQRT:
3984     s_return (mk_real (SCHEME_A_ sqrt (rvalue (x))));
3985    
3986     case OP_EXPT:
3987     {
3988     RVALUE result;
3989     int real_result = 1;
3990 root 1.16 pointer y = cadr (args);
3991 root 1.1
3992 root 1.25 if (is_integer (x) && is_integer (y))
3993 root 1.1 real_result = 0;
3994    
3995     /* This 'if' is an R5RS compatibility fix. */
3996     /* NOTE: Remove this 'if' fix for R6RS. */
3997     if (rvalue (x) == 0 && rvalue (y) < 0)
3998 root 1.16 result = 0;
3999 root 1.1 else
4000 root 1.2 result = pow (rvalue (x), rvalue (y));
4001 root 1.1
4002     /* Before returning integer result make sure we can. */
4003     /* If the test fails, result is too big for integer. */
4004     if (!real_result)
4005     {
4006 root 1.16 long result_as_long = result;
4007 root 1.1
4008 root 1.26 if (result != result_as_long)
4009 root 1.1 real_result = 1;
4010     }
4011    
4012     if (real_result)
4013 root 1.2 s_return (mk_real (SCHEME_A_ result));
4014 root 1.1 else
4015 root 1.2 s_return (mk_integer (SCHEME_A_ result));
4016 root 1.1 }
4017    
4018 root 1.16 case OP_FLOOR: s_return (mk_real (SCHEME_A_ floor (rvalue (x))));
4019     case OP_CEILING: s_return (mk_real (SCHEME_A_ ceil (rvalue (x))));
4020 root 1.1
4021     case OP_TRUNCATE:
4022     {
4023 root 1.26 RVALUE n = rvalue (x);
4024     s_return (mk_real (SCHEME_A_ n > 0 ? floor (n) : ceil (n)));
4025 root 1.1 }
4026    
4027     case OP_ROUND:
4028 root 1.26 if (is_integer (x))
4029 root 1.1 s_return (x);
4030    
4031     s_return (mk_real (SCHEME_A_ round_per_R5RS (rvalue (x))));
4032     #endif
4033    
4034     case OP_ADD: /* + */
4035     v = num_zero;
4036    
4037 root 1.16 for (x = args; x != NIL; x = cdr (x))
4038 root 1.23 v = num_op (NUM_ADD, v, nvalue (car (x)));
4039 root 1.1
4040     s_return (mk_number (SCHEME_A_ v));
4041    
4042     case OP_MUL: /* * */
4043     v = num_one;
4044    
4045 root 1.16 for (x = args; x != NIL; x = cdr (x))
4046 root 1.23 v = num_op (NUM_MUL, v, nvalue (car (x)));
4047 root 1.1
4048     s_return (mk_number (SCHEME_A_ v));
4049    
4050     case OP_SUB: /* - */
4051 root 1.16 if (cdr (args) == NIL)
4052 root 1.1 {
4053 root 1.16 x = args;
4054 root 1.1 v = num_zero;
4055     }
4056     else
4057     {
4058 root 1.16 x = cdr (args);
4059     v = nvalue (car (args));
4060 root 1.1 }
4061    
4062     for (; x != NIL; x = cdr (x))
4063 root 1.23 v = num_op (NUM_SUB, v, nvalue (car (x)));
4064 root 1.1
4065     s_return (mk_number (SCHEME_A_ v));
4066    
4067     case OP_DIV: /* / */
4068 root 1.16 if (cdr (args) == NIL)
4069 root 1.1 {
4070 root 1.16 x = args;
4071 root 1.1 v = num_one;
4072     }
4073     else
4074     {
4075 root 1.16 x = cdr (args);
4076     v = nvalue (car (args));
4077 root 1.1 }
4078    
4079     for (; x != NIL; x = cdr (x))
4080 root 1.23 if (!is_zero_rvalue (rvalue (car (x))))
4081     v = num_div (v, nvalue (car (x)));
4082     else
4083     Error_0 ("/: division by zero");
4084 root 1.1
4085     s_return (mk_number (SCHEME_A_ v));
4086    
4087     case OP_INTDIV: /* quotient */
4088 root 1.16 if (cdr (args) == NIL)
4089 root 1.1 {
4090 root 1.16 x = args;
4091 root 1.1 v = num_one;
4092     }
4093     else
4094     {
4095 root 1.16 x = cdr (args);
4096     v = nvalue (car (args));
4097 root 1.1 }
4098    
4099     for (; x != NIL; x = cdr (x))
4100     {
4101     if (ivalue (car (x)) != 0)
4102 root 1.23 v = num_op (NUM_INTDIV, v, nvalue (car (x)));
4103 root 1.1 else
4104     Error_0 ("quotient: division by zero");
4105     }
4106    
4107     s_return (mk_number (SCHEME_A_ v));
4108    
4109     case OP_REM: /* remainder */
4110 root 1.16 v = nvalue (x);
4111 root 1.1
4112 root 1.16 if (ivalue (cadr (args)) != 0)
4113     v = num_rem (v, nvalue (cadr (args)));
4114 root 1.1 else
4115     Error_0 ("remainder: division by zero");
4116    
4117     s_return (mk_number (SCHEME_A_ v));
4118    
4119     case OP_MOD: /* modulo */
4120 root 1.16 v = nvalue (x);
4121 root 1.1
4122 root 1.16 if (ivalue (cadr (args)) != 0)
4123     v = num_mod (v, nvalue (cadr (args)));
4124 root 1.1 else
4125     Error_0 ("modulo: division by zero");
4126    
4127     s_return (mk_number (SCHEME_A_ v));
4128    
4129     case OP_CAR: /* car */
4130 root 1.16 s_return (caar (args));
4131 root 1.1
4132     case OP_CDR: /* cdr */
4133 root 1.16 s_return (cdar (args));
4134 root 1.1
4135     case OP_CONS: /* cons */
4136 root 1.16 set_cdr (args, cadr (args));
4137     s_return (args);
4138 root 1.1
4139     case OP_SETCAR: /* set-car! */
4140 root 1.16 if (!is_immutable (x))
4141 root 1.1 {
4142 root 1.16 set_car (x, cadr (args));
4143     s_return (car (args));
4144 root 1.1 }
4145     else
4146     Error_0 ("set-car!: unable to alter immutable pair");
4147    
4148     case OP_SETCDR: /* set-cdr! */
4149 root 1.16 if (!is_immutable (x))
4150 root 1.1 {
4151 root 1.16 set_cdr (x, cadr (args));
4152     s_return (car (args));
4153 root 1.1 }
4154     else
4155     Error_0 ("set-cdr!: unable to alter immutable pair");
4156    
4157     case OP_CHAR2INT: /* char->integer */
4158 root 1.26 s_return (mk_integer (SCHEME_A_ ivalue_unchecked (x)));
4159 root 1.1
4160     case OP_INT2CHAR: /* integer->char */
4161 root 1.26 s_return (mk_character (SCHEME_A_ ivalue_unchecked (x)));
4162 root 1.1
4163     case OP_CHARUPCASE:
4164     {
4165 root 1.26 unsigned char c = ivalue_unchecked (x);
4166 root 1.1 c = toupper (c);
4167 root 1.2 s_return (mk_character (SCHEME_A_ c));
4168 root 1.1 }
4169    
4170     case OP_CHARDNCASE:
4171     {
4172 root 1.26 unsigned char c = ivalue_unchecked (x);
4173 root 1.1 c = tolower (c);
4174 root 1.2 s_return (mk_character (SCHEME_A_ c));
4175 root 1.1 }
4176    
4177     case OP_STR2SYM: /* string->symbol */
4178 root 1.16 s_return (mk_symbol (SCHEME_A_ strvalue (x)));
4179 root 1.1
4180     case OP_STR2ATOM: /* string->atom */
4181     {
4182 root 1.16 char *s = strvalue (x);
4183 root 1.1 long pf = 0;
4184    
4185 root 1.16 if (cdr (args) != NIL)
4186 root 1.1 {
4187 root 1.16 /* we know cadr(args) is a natural number */
4188 root 1.1 /* see if it is 2, 8, 10, or 16, or error */
4189 root 1.16 pf = ivalue_unchecked (cadr (args));
4190 root 1.1
4191     if (pf == 16 || pf == 10 || pf == 8 || pf == 2)
4192     {
4193     /* base is OK */
4194     }
4195     else
4196 root 1.2 pf = -1;
4197 root 1.1 }
4198    
4199     if (pf < 0)
4200 root 1.16 Error_1 ("string->atom: bad base:", cadr (args));
4201 root 1.1 else if (*s == '#') /* no use of base! */
4202 root 1.2 s_return (mk_sharp_const (SCHEME_A_ s + 1));
4203 root 1.1 else
4204     {
4205     if (pf == 0 || pf == 10)
4206 root 1.2 s_return (mk_atom (SCHEME_A_ s));
4207 root 1.1 else
4208     {
4209     char *ep;
4210     long iv = strtol (s, &ep, (int) pf);
4211    
4212     if (*ep == 0)
4213 root 1.2 s_return (mk_integer (SCHEME_A_ iv));
4214 root 1.1 else
4215 root 1.2 s_return (S_F);
4216 root 1.1 }
4217     }
4218     }
4219    
4220     case OP_SYM2STR: /* symbol->string */
4221 root 1.16 x = mk_string (SCHEME_A_ symname (x));
4222 root 1.1 setimmutable (x);
4223     s_return (x);
4224    
4225     case OP_ATOM2STR: /* atom->string */
4226     {
4227     long pf = 0;
4228    
4229 root 1.16 if (cdr (args) != NIL)
4230 root 1.1 {
4231 root 1.16 /* we know cadr(args) is a natural number */
4232 root 1.1 /* see if it is 2, 8, 10, or 16, or error */
4233 root 1.16 pf = ivalue_unchecked (cadr (args));
4234 root 1.1
4235     if (is_number (x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2))
4236     {
4237     /* base is OK */
4238     }
4239     else
4240 root 1.2 pf = -1;
4241 root 1.1 }
4242    
4243     if (pf < 0)
4244 root 1.16 Error_1 ("atom->string: bad base:", cadr (args));
4245 root 1.1 else if (is_number (x) || is_character (x) || is_string (x) || is_symbol (x))
4246     {
4247     char *p;
4248     int len;
4249    
4250 root 1.2 atom2str (SCHEME_A_ x, pf, &p, &len);
4251 root 1.1 s_return (mk_counted_string (SCHEME_A_ p, len));
4252     }
4253     else
4254 root 1.2 Error_1 ("atom->string: not an atom:", x);
4255 root 1.1 }
4256    
4257     case OP_MKSTRING: /* make-string */
4258     {
4259 root 1.26 int fill = cdr (args) != NIL ? charvalue (cadr (args)) : ' ';
4260     int len = ivalue_unchecked (x);
4261 root 1.1
4262 root 1.17 s_return (mk_empty_string (SCHEME_A_ len, fill));
4263 root 1.1 }
4264    
4265     case OP_STRLEN: /* string-length */
4266 root 1.16 s_return (mk_integer (SCHEME_A_ strlength (x)));
4267 root 1.1
4268     case OP_STRREF: /* string-ref */
4269     {
4270 root 1.26 char *str = strvalue (x);
4271     int index = ivalue_unchecked (cadr (args));
4272 root 1.1
4273 root 1.16 if (index >= strlength (x))
4274     Error_1 ("string-ref: out of bounds:", cadr (args));
4275 root 1.1
4276 root 1.17 s_return (mk_character (SCHEME_A_ ((unsigned char *)str)[index]));
4277 root 1.1 }
4278    
4279     case OP_STRSET: /* string-set! */
4280     {
4281 root 1.26 char *str = strvalue (x);
4282     int index = ivalue_unchecked (cadr (args));
4283 root 1.1 int c;
4284    
4285 root 1.16 if (is_immutable (x))
4286     Error_1 ("string-set!: unable to alter immutable string:", x);
4287 root 1.1
4288 root 1.16 if (index >= strlength (x))
4289     Error_1 ("string-set!: out of bounds:", cadr (args));
4290 root 1.1
4291 root 1.16 c = charvalue (caddr (args));
4292 root 1.1
4293 root 1.17 str[index] = c;
4294 root 1.16 s_return (car (args));
4295 root 1.1 }
4296    
4297     case OP_STRAPPEND: /* string-append */
4298     {
4299     /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4300     int len = 0;
4301     pointer newstr;
4302     char *pos;
4303    
4304     /* compute needed length for new string */
4305 root 1.16 for (x = args; x != NIL; x = cdr (x))
4306 root 1.2 len += strlength (car (x));
4307 root 1.1
4308     newstr = mk_empty_string (SCHEME_A_ len, ' ');
4309    
4310     /* store the contents of the argument strings into the new string */
4311 root 1.16 for (pos = strvalue (newstr), x = args; x != NIL; pos += strlength (car (x)), x = cdr (x))
4312 root 1.2 memcpy (pos, strvalue (car (x)), strlength (car (x)));
4313 root 1.1
4314     s_return (newstr);
4315     }
4316    
4317     case OP_SUBSTR: /* substring */
4318     {
4319 root 1.26 char *str = strvalue (x);
4320     int index0 = ivalue_unchecked (cadr (args));
4321 root 1.1 int index1;
4322     int len;
4323    
4324 root 1.16 if (index0 > strlength (x))
4325     Error_1 ("substring: start out of bounds:", cadr (args));
4326 root 1.1
4327 root 1.16 if (cddr (args) != NIL)
4328 root 1.1 {
4329 root 1.26 index1 = ivalue_unchecked (caddr (args));
4330 root 1.1
4331 root 1.16 if (index1 > strlength (x) || index1 < index0)
4332     Error_1 ("substring: end out of bounds:", caddr (args));
4333 root 1.1 }
4334     else
4335 root 1.16 index1 = strlength (x);
4336 root 1.1
4337     len = index1 - index0;
4338     x = mk_empty_string (SCHEME_A_ len, ' ');
4339     memcpy (strvalue (x), str + index0, len);
4340     strvalue (x)[len] = 0;
4341    
4342     s_return (x);
4343     }
4344    
4345     case OP_VECTOR: /* vector */
4346     {
4347     int i;
4348     pointer vec;
4349 root 1.16 int len = list_length (SCHEME_A_ args);
4350 root 1.1
4351     if (len < 0)
4352 root 1.16 Error_1 ("vector: not a proper list:", args);
4353 root 1.1
4354     vec = mk_vector (SCHEME_A_ len);
4355    
4356     #if USE_ERROR_CHECKING
4357     if (SCHEME_V->no_memory)
4358     s_return (S_SINK);
4359     #endif
4360    
4361 root 1.16 for (x = args, i = 0; is_pair (x); x = cdr (x), i++)
4362 root 1.28 vector_set (vec, i, car (x));
4363 root 1.1
4364     s_return (vec);
4365     }
4366    
4367     case OP_MKVECTOR: /* make-vector */
4368     {
4369     pointer fill = NIL;
4370     pointer vec;
4371 root 1.26 int len = ivalue_unchecked (x);
4372 root 1.1
4373 root 1.16 if (cdr (args) != NIL)
4374     fill = cadr (args);
4375 root 1.1
4376     vec = mk_vector (SCHEME_A_ len);
4377    
4378     #if USE_ERROR_CHECKING
4379     if (SCHEME_V->no_memory)
4380     s_return (S_SINK);
4381     #endif
4382    
4383     if (fill != NIL)
4384 root 1.28 fill_vector (vec, 0, fill);
4385 root 1.1
4386     s_return (vec);
4387     }
4388    
4389     case OP_VECLEN: /* vector-length */
4390 root 1.16 s_return (mk_integer (SCHEME_A_ veclength (x)));
4391 root 1.1
4392     case OP_VECREF: /* vector-ref */
4393     {
4394 root 1.26 int index = ivalue_unchecked (cadr (args));
4395 root 1.1
4396 root 1.16 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4397     Error_1 ("vector-ref: out of bounds:", cadr (args));
4398 root 1.1
4399 root 1.28 s_return (vector_get (x, index));
4400 root 1.1 }
4401    
4402     case OP_VECSET: /* vector-set! */
4403     {
4404 root 1.26 int index = ivalue_unchecked (cadr (args));
4405 root 1.1
4406 root 1.16 if (is_immutable (x))
4407     Error_1 ("vector-set!: unable to alter immutable vector:", x);
4408 root 1.1
4409 root 1.16 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4410     Error_1 ("vector-set!: out of bounds:", cadr (args));
4411 root 1.1
4412 root 1.28 vector_set (x, index, caddr (args));
4413 root 1.16 s_return (x);
4414 root 1.1 }
4415     }
4416    
4417 root 1.24 if (USE_ERROR_CHECKING) abort ();
4418 root 1.1 }
4419    
4420 root 1.20 static int
4421     opexe_2 (SCHEME_P_ enum scheme_opcodes op)
4422 root 1.1 {
4423 root 1.14 pointer x = SCHEME_V->args;
4424 root 1.1
4425 root 1.14 for (;;)
4426 root 1.1 {
4427 root 1.14 num v = nvalue (car (x));
4428     x = cdr (x);
4429 root 1.1
4430 root 1.14 if (x == NIL)
4431     break;
4432 root 1.1
4433 root 1.14 int r = num_cmp (v, nvalue (car (x)));
4434 root 1.1
4435 root 1.14 switch (op)
4436     {
4437     case OP_NUMEQ: r = r == 0; break;
4438     case OP_LESS: r = r < 0; break;
4439     case OP_GRE: r = r > 0; break;
4440     case OP_LEQ: r = r <= 0; break;
4441     case OP_GEQ: r = r >= 0; break;
4442     }
4443 root 1.1
4444 root 1.14 if (!r)
4445     s_return (S_F);
4446     }
4447 root 1.1
4448 root 1.14 s_return (S_T);
4449     }
4450 root 1.1
4451 root 1.20 static int
4452 root 1.14 opexe_3 (SCHEME_P_ enum scheme_opcodes op)
4453     {
4454 root 1.16 pointer args = SCHEME_V->args;
4455     pointer a = car (args);
4456     pointer d = cdr (args);
4457 root 1.14 int r;
4458 root 1.1
4459 root 1.14 switch (op)
4460     {
4461 root 1.15 case OP_NOT: /* not */ r = is_false (a) ; break;
4462     case OP_BOOLP: /* boolean? */ r = a == S_F || a == S_T; break;
4463     case OP_EOFOBJP: /* eof-object? */ r = a == S_EOF ; break;
4464     case OP_NULLP: /* null? */ r = a == NIL ; break;
4465     case OP_SYMBOLP: /* symbol? */ r = is_symbol (a) ; break;
4466     case OP_NUMBERP: /* number? */ r = is_number (a) ; break;
4467     case OP_STRINGP: /* string? */ r = is_string (a) ; break;
4468     case OP_INTEGERP: /* integer? */ r = is_integer (a) ; break;
4469     case OP_REALP: /* real? */ r = is_number (a) ; break; /* all numbers are real */
4470     case OP_CHARP: /* char? */ r = is_character (a) ; break;
4471 root 1.14
4472 root 1.1 #if USE_CHAR_CLASSIFIERS
4473 root 1.26 case OP_CHARAP: /* char-alphabetic? */ r = Cisalpha (ivalue_unchecked (a)); break;
4474     case OP_CHARNP: /* char-numeric? */ r = Cisdigit (ivalue_unchecked (a)); break;
4475     case OP_CHARWP: /* char-whitespace? */ r = Cisspace (ivalue_unchecked (a)); break;
4476     case OP_CHARUP: /* char-upper-case? */ r = Cisupper (ivalue_unchecked (a)); break;
4477     case OP_CHARLP: /* char-lower-case? */ r = Cislower (ivalue_unchecked (a)); break;
4478 root 1.1 #endif
4479 root 1.14
4480 root 1.1 #if USE_PORTS
4481 root 1.15 case OP_PORTP: /* port? */ r = is_port (a) ; break;
4482     case OP_INPORTP: /* input-port? */ r = is_inport (a) ; break;
4483     case OP_OUTPORTP: /* output-port? */ r = is_outport (a); break;
4484 root 1.1 #endif
4485    
4486     case OP_PROCP: /* procedure? */
4487    
4488 root 1.14 /*--
4489     * continuation should be procedure by the example
4490     * (call-with-current-continuation procedure?) ==> #t
4491     * in R^3 report sec. 6.9
4492     */
4493     r = is_proc (a) || is_closure (a) || is_continuation (a) || is_foreign (a);
4494     break;
4495 root 1.1
4496 root 1.15 case OP_PAIRP: /* pair? */ r = is_pair (a) ; break;
4497     case OP_LISTP: /* list? */ r = list_length (SCHEME_A_ a) >= 0; break;
4498     case OP_ENVP: /* environment? */ r = is_environment (a) ; break;
4499     case OP_VECTORP: /* vector? */ r = is_vector (a) ; break;
4500 root 1.16 case OP_EQ: /* eq? */ r = a == cadr (args) ; break;
4501     case OP_EQV: /* eqv? */ r = eqv (a, cadr (args)) ; break;
4502 root 1.1 }
4503    
4504 root 1.14 s_retbool (r);
4505 root 1.1 }
4506    
4507 root 1.20 static int
4508 root 1.1 opexe_4 (SCHEME_P_ enum scheme_opcodes op)
4509     {
4510 root 1.16 pointer args = SCHEME_V->args;
4511     pointer a = car (args);
4512 root 1.1 pointer x, y;
4513    
4514     switch (op)
4515     {
4516     case OP_FORCE: /* force */
4517 root 1.16 SCHEME_V->code = a;
4518 root 1.1
4519     if (is_promise (SCHEME_V->code))
4520     {
4521     /* Should change type to closure here */
4522     s_save (SCHEME_A_ OP_SAVE_FORCED, NIL, SCHEME_V->code);
4523     SCHEME_V->args = NIL;
4524     s_goto (OP_APPLY);
4525     }
4526     else
4527 root 1.2 s_return (SCHEME_V->code);
4528 root 1.1
4529     case OP_SAVE_FORCED: /* Save forced value replacing promise */
4530     memcpy (SCHEME_V->code, SCHEME_V->value, sizeof (struct cell));
4531     s_return (SCHEME_V->value);
4532    
4533     #if USE_PORTS
4534    
4535     case OP_WRITE: /* write */
4536     case OP_DISPLAY: /* display */
4537     case OP_WRITE_CHAR: /* write-char */
4538     if (is_pair (cdr (SCHEME_V->args)))
4539     {
4540     if (cadr (SCHEME_V->args) != SCHEME_V->outport)
4541     {
4542     x = cons (SCHEME_V->outport, NIL);
4543     s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4544     SCHEME_V->outport = cadr (SCHEME_V->args);
4545     }
4546     }
4547    
4548 root 1.16 SCHEME_V->args = a;
4549 root 1.1
4550     if (op == OP_WRITE)
4551     SCHEME_V->print_flag = 1;
4552     else
4553     SCHEME_V->print_flag = 0;
4554    
4555     s_goto (OP_P0LIST);
4556    
4557     case OP_NEWLINE: /* newline */
4558 root 1.16 if (is_pair (args))
4559 root 1.1 {
4560 root 1.16 if (a != SCHEME_V->outport)
4561 root 1.1 {
4562     x = cons (SCHEME_V->outport, NIL);
4563     s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4564 root 1.16 SCHEME_V->outport = a;
4565 root 1.1 }
4566     }
4567    
4568     putstr (SCHEME_A_ "\n");
4569     s_return (S_T);
4570     #endif
4571    
4572     case OP_ERR0: /* error */
4573     SCHEME_V->retcode = -1;
4574    
4575 root 1.16 if (!is_string (a))
4576 root 1.1 {
4577 root 1.16 args = cons (mk_string (SCHEME_A_ " -- "), args);
4578     setimmutable (car (args));
4579 root 1.1 }
4580    
4581     putstr (SCHEME_A_ "Error: ");
4582 root 1.16 putstr (SCHEME_A_ strvalue (car (args)));
4583     SCHEME_V->args = cdr (args);
4584 root 1.1 s_goto (OP_ERR1);
4585    
4586     case OP_ERR1: /* error */
4587     putstr (SCHEME_A_ " ");
4588    
4589 root 1.16 if (args != NIL)
4590 root 1.1 {
4591 root 1.16 s_save (SCHEME_A_ OP_ERR1, cdr (args), NIL);
4592     SCHEME_V->args = a;
4593 root 1.1 SCHEME_V->print_flag = 1;
4594     s_goto (OP_P0LIST);
4595     }
4596     else
4597     {
4598     putstr (SCHEME_A_ "\n");
4599    
4600     if (SCHEME_V->interactive_repl)
4601 root 1.2 s_goto (OP_T0LVL);
4602 root 1.1 else
4603 root 1.20 return -1;
4604 root 1.1 }
4605    
4606     case OP_REVERSE: /* reverse */
4607 root 1.16 s_return (reverse (SCHEME_A_ a));
4608 root 1.1
4609     case OP_LIST_STAR: /* list* */
4610     s_return (list_star (SCHEME_A_ SCHEME_V->args));
4611    
4612     case OP_APPEND: /* append */
4613     x = NIL;
4614 root 1.16 y = args;
4615 root 1.1
4616     if (y == x)
4617     s_return (x);
4618    
4619     /* cdr() in the while condition is not a typo. If car() */
4620     /* is used (append '() 'a) will return the wrong result. */
4621     while (cdr (y) != NIL)
4622     {
4623     x = revappend (SCHEME_A_ x, car (y));
4624     y = cdr (y);
4625    
4626     if (x == S_F)
4627     Error_0 ("non-list argument to append");
4628     }
4629    
4630     s_return (reverse_in_place (SCHEME_A_ car (y), x));
4631    
4632     #if USE_PLIST
4633    
4634     case OP_PUT: /* put */
4635 root 1.16 if (!hasprop (a) || !hasprop (cadr (args)))
4636 root 1.2 Error_0 ("illegal use of put");
4637 root 1.1
4638 root 1.16 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4639 root 1.1 {
4640     if (caar (x) == y)
4641 root 1.2 break;
4642 root 1.1 }
4643    
4644     if (x != NIL)
4645 root 1.16 cdar (x) = caddr (args);
4646 root 1.1 else
4647 root 1.16 symprop (a) = cons (cons (y, caddr (args)), symprop (a));
4648 root 1.1
4649     s_return (S_T);
4650    
4651     case OP_GET: /* get */
4652 root 1.16 if (!hasprop (a) || !hasprop (cadr (args)))
4653 root 1.1 Error_0 ("illegal use of get");
4654    
4655 root 1.16 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4656 root 1.1 if (caar (x) == y)
4657     break;
4658    
4659     if (x != NIL)
4660     s_return (cdar (x));
4661     else
4662     s_return (NIL);
4663    
4664     #endif /* USE_PLIST */
4665    
4666     case OP_QUIT: /* quit */
4667 root 1.16 if (is_pair (args))
4668     SCHEME_V->retcode = ivalue (a);
4669 root 1.1
4670 root 1.20 return -1;
4671 root 1.1
4672     case OP_GC: /* gc */
4673     gc (SCHEME_A_ NIL, NIL);
4674     s_return (S_T);
4675    
4676     case OP_GCVERB: /* gc-verbose */
4677     {
4678     int was = SCHEME_V->gc_verbose;
4679    
4680 root 1.16 SCHEME_V->gc_verbose = (a != S_F);
4681 root 1.1 s_retbool (was);
4682     }
4683    
4684     case OP_NEWSEGMENT: /* new-segment */
4685 root 1.16 if (!is_pair (args) || !is_number (a))
4686 root 1.1 Error_0 ("new-segment: argument must be a number");
4687    
4688 root 1.26 alloc_cellseg (SCHEME_A_ ivalue (a));
4689 root 1.1
4690     s_return (S_T);
4691    
4692     case OP_OBLIST: /* oblist */
4693     s_return (oblist_all_symbols (SCHEME_A));
4694    
4695     #if USE_PORTS
4696    
4697     case OP_CURR_INPORT: /* current-input-port */
4698     s_return (SCHEME_V->inport);
4699    
4700     case OP_CURR_OUTPORT: /* current-output-port */
4701     s_return (SCHEME_V->outport);
4702    
4703     case OP_OPEN_INFILE: /* open-input-file */
4704     case OP_OPEN_OUTFILE: /* open-output-file */
4705     case OP_OPEN_INOUTFILE: /* open-input-output-file */
4706     {
4707     int prop = 0;
4708     pointer p;
4709    
4710     switch (op)
4711     {
4712     case OP_OPEN_INFILE:
4713     prop = port_input;
4714     break;
4715    
4716     case OP_OPEN_OUTFILE:
4717     prop = port_output;
4718     break;
4719    
4720     case OP_OPEN_INOUTFILE:
4721     prop = port_input | port_output;
4722     break;
4723     }
4724    
4725 root 1.16 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
4726 root 1.1
4727 root 1.23 s_return (p == NIL ? S_F : p);
4728 root 1.1 }
4729    
4730     # if USE_STRING_PORTS
4731    
4732     case OP_OPEN_INSTRING: /* open-input-string */
4733     case OP_OPEN_INOUTSTRING: /* open-input-output-string */
4734     {
4735     int prop = 0;
4736     pointer p;
4737    
4738     switch (op)
4739     {
4740     case OP_OPEN_INSTRING:
4741     prop = port_input;
4742     break;
4743    
4744     case OP_OPEN_INOUTSTRING:
4745     prop = port_input | port_output;
4746     break;
4747     }
4748    
4749 root 1.16 p = port_from_string (SCHEME_A_ strvalue (a),
4750     strvalue (a) + strlength (a), prop);
4751 root 1.1
4752 root 1.23 s_return (p == NIL ? S_F : p);
4753 root 1.1 }
4754    
4755     case OP_OPEN_OUTSTRING: /* open-output-string */
4756     {
4757     pointer p;
4758    
4759 root 1.16 if (a == NIL)
4760 root 1.23 p = port_from_scratch (SCHEME_A);
4761 root 1.1 else
4762 root 1.23 p = port_from_string (SCHEME_A_ strvalue (a),
4763     strvalue (a) + strlength (a), port_output);
4764 root 1.1
4765 root 1.23 s_return (p == NIL ? S_F : p);
4766 root 1.1 }
4767    
4768     case OP_GET_OUTSTRING: /* get-output-string */
4769     {
4770     port *p;
4771    
4772 root 1.16 if ((p = a->object.port)->kind & port_string)
4773 root 1.1 {
4774     off_t size;
4775     char *str;
4776    
4777     size = p->rep.string.curr - p->rep.string.start + 1;
4778     str = malloc (size);
4779    
4780     if (str != NULL)
4781     {
4782     pointer s;
4783    
4784     memcpy (str, p->rep.string.start, size - 1);
4785     str[size - 1] = '\0';
4786     s = mk_string (SCHEME_A_ str);
4787     free (str);
4788     s_return (s);
4789     }
4790     }
4791    
4792     s_return (S_F);
4793     }
4794    
4795     # endif
4796    
4797     case OP_CLOSE_INPORT: /* close-input-port */
4798 root 1.16 port_close (SCHEME_A_ a, port_input);
4799 root 1.1 s_return (S_T);
4800    
4801     case OP_CLOSE_OUTPORT: /* close-output-port */
4802 root 1.16 port_close (SCHEME_A_ a, port_output);
4803 root 1.1 s_return (S_T);
4804     #endif
4805    
4806     case OP_INT_ENV: /* interaction-environment */
4807     s_return (SCHEME_V->global_env);
4808    
4809     case OP_CURR_ENV: /* current-environment */
4810     s_return (SCHEME_V->envir);
4811    
4812     }
4813    
4814 root 1.24 if (USE_ERROR_CHECKING) abort ();
4815 root 1.1 }
4816    
4817 root 1.20 static int
4818 root 1.1 opexe_5 (SCHEME_P_ enum scheme_opcodes op)
4819     {
4820 root 1.18 pointer args = SCHEME_V->args;
4821 root 1.1 pointer x;
4822    
4823     if (SCHEME_V->nesting != 0)
4824     {
4825     int n = SCHEME_V->nesting;
4826    
4827     SCHEME_V->nesting = 0;
4828     SCHEME_V->retcode = -1;
4829     Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
4830     }
4831    
4832     switch (op)
4833     {
4834     /* ========== reading part ========== */
4835     #if USE_PORTS
4836     case OP_READ:
4837 root 1.18 if (!is_pair (args))
4838 root 1.2 s_goto (OP_READ_INTERNAL);
4839 root 1.1
4840 root 1.18 if (!is_inport (car (args)))
4841     Error_1 ("read: not an input port:", car (args));
4842 root 1.1
4843 root 1.18 if (car (args) == SCHEME_V->inport)
4844 root 1.2 s_goto (OP_READ_INTERNAL);
4845 root 1.1
4846     x = SCHEME_V->inport;
4847 root 1.18 SCHEME_V->inport = car (args);
4848 root 1.1 x = cons (x, NIL);
4849     s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4850     s_goto (OP_READ_INTERNAL);
4851    
4852     case OP_READ_CHAR: /* read-char */
4853     case OP_PEEK_CHAR: /* peek-char */
4854     {
4855     int c;
4856    
4857 root 1.18 if (is_pair (args))
4858 root 1.1 {
4859 root 1.18 if (car (args) != SCHEME_V->inport)
4860 root 1.1 {
4861     x = SCHEME_V->inport;
4862     x = cons (x, NIL);
4863     s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4864 root 1.18 SCHEME_V->inport = car (args);
4865 root 1.1 }
4866     }
4867    
4868     c = inchar (SCHEME_A);
4869    
4870     if (c == EOF)
4871     s_return (S_EOF);
4872    
4873     if (SCHEME_V->op == OP_PEEK_CHAR)
4874     backchar (SCHEME_A_ c);
4875    
4876     s_return (mk_character (SCHEME_A_ c));
4877     }
4878    
4879     case OP_CHAR_READY: /* char-ready? */
4880     {
4881     pointer p = SCHEME_V->inport;
4882     int res;
4883    
4884 root 1.18 if (is_pair (args))
4885     p = car (args);
4886 root 1.1
4887     res = p->object.port->kind & port_string;
4888    
4889     s_retbool (res);
4890     }
4891    
4892     case OP_SET_INPORT: /* set-input-port */
4893 root 1.18 SCHEME_V->inport = car (args);
4894 root 1.1 s_return (SCHEME_V->value);
4895    
4896     case OP_SET_OUTPORT: /* set-output-port */
4897 root 1.18 SCHEME_V->outport = car (args);
4898 root 1.1 s_return (SCHEME_V->value);
4899     #endif
4900    
4901     case OP_RDSEXPR:
4902     switch (SCHEME_V->tok)
4903     {
4904     case TOK_EOF:
4905     s_return (S_EOF);
4906     /* NOTREACHED */
4907    
4908     case TOK_VEC:
4909     s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
4910 root 1.2 /* fall through */
4911 root 1.1
4912     case TOK_LPAREN:
4913     SCHEME_V->tok = token (SCHEME_A);
4914    
4915     if (SCHEME_V->tok == TOK_RPAREN)
4916     s_return (NIL);
4917     else if (SCHEME_V->tok == TOK_DOT)
4918     Error_0 ("syntax error: illegal dot expression");
4919     else
4920     {
4921     SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
4922     s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
4923     s_goto (OP_RDSEXPR);
4924     }
4925    
4926     case TOK_QUOTE:
4927     s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
4928     SCHEME_V->tok = token (SCHEME_A);
4929     s_goto (OP_RDSEXPR);
4930    
4931     case TOK_BQUOTE:
4932     SCHEME_V->tok = token (SCHEME_A);
4933    
4934     if (SCHEME_V->tok == TOK_VEC)
4935     {
4936     s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
4937     SCHEME_V->tok = TOK_LPAREN;
4938     s_goto (OP_RDSEXPR);
4939     }
4940     else
4941 root 1.2 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
4942 root 1.1
4943     s_goto (OP_RDSEXPR);
4944    
4945     case TOK_COMMA:
4946     s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
4947     SCHEME_V->tok = token (SCHEME_A);
4948     s_goto (OP_RDSEXPR);
4949    
4950     case TOK_ATMARK:
4951     s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
4952     SCHEME_V->tok = token (SCHEME_A);
4953     s_goto (OP_RDSEXPR);
4954    
4955     case TOK_ATOM:
4956     s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS)));
4957    
4958     case TOK_DQUOTE:
4959     x = readstrexp (SCHEME_A);
4960    
4961     if (x == S_F)
4962     Error_0 ("Error reading string");
4963    
4964     setimmutable (x);
4965     s_return (x);
4966    
4967     case TOK_SHARP:
4968     {
4969     pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
4970    
4971     if (f == NIL)
4972     Error_0 ("undefined sharp expression");
4973     else
4974     {
4975     SCHEME_V->code = cons (slot_value_in_env (f), NIL);
4976     s_goto (OP_EVAL);
4977     }
4978     }
4979    
4980     case TOK_SHARP_CONST:
4981     if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS))) == NIL)
4982     Error_0 ("undefined sharp expression");
4983     else
4984     s_return (x);
4985    
4986     default:
4987     Error_0 ("syntax error: illegal token");
4988     }
4989    
4990     break;
4991    
4992     case OP_RDLIST:
4993 root 1.18 SCHEME_V->args = cons (SCHEME_V->value, args);
4994 root 1.2 SCHEME_V->tok = token (SCHEME_A);
4995 root 1.1
4996 root 1.2 switch (SCHEME_V->tok)
4997     {
4998     case TOK_EOF:
4999     s_return (S_EOF);
5000 root 1.1
5001 root 1.2 case TOK_RPAREN:
5002     {
5003     int c = inchar (SCHEME_A);
5004 root 1.1
5005 root 1.2 if (c != '\n')
5006     backchar (SCHEME_A_ c);
5007 root 1.1 #if SHOW_ERROR_LINE
5008 root 1.2 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5009     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5010     #endif
5011 root 1.1
5012 root 1.2 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5013     s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5014     }
5015    
5016     case TOK_DOT:
5017 root 1.1 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5018     SCHEME_V->tok = token (SCHEME_A);
5019     s_goto (OP_RDSEXPR);
5020 root 1.2
5021     default:
5022     s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5023 root 1.1 s_goto (OP_RDSEXPR);
5024 root 1.2 }
5025 root 1.1
5026     case OP_RDDOT:
5027     if (token (SCHEME_A) != TOK_RPAREN)
5028     Error_0 ("syntax error: illegal dot expression");
5029 root 1.2
5030     SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5031 root 1.18 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5032 root 1.1
5033     case OP_RDQUOTE:
5034     s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5035    
5036     case OP_RDQQUOTE:
5037     s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5038    
5039     case OP_RDQQUOTEVEC:
5040     s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5041     cons (mk_symbol (SCHEME_A_ "vector"),
5042     cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5043    
5044     case OP_RDUNQUOTE:
5045     s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5046    
5047     case OP_RDUQTSP:
5048     s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5049    
5050     case OP_RDVEC:
5051     /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5052     s_goto(OP_EVAL); Cannot be quoted */
5053     /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5054     s_return(x); Cannot be part of pairs */
5055     /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5056     SCHEME_V->args=SCHEME_V->value;
5057     s_goto(OP_APPLY); */
5058     SCHEME_V->args = SCHEME_V->value;
5059     s_goto (OP_VECTOR);
5060    
5061     /* ========== printing part ========== */
5062     case OP_P0LIST:
5063 root 1.18 if (is_vector (args))
5064 root 1.1 {
5065     putstr (SCHEME_A_ "#(");
5066 root 1.18 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5067 root 1.1 s_goto (OP_PVECFROM);
5068     }
5069 root 1.18 else if (is_environment (args))
5070 root 1.1 {
5071     putstr (SCHEME_A_ "#<ENVIRONMENT>");
5072     s_return (S_T);
5073     }
5074 root 1.18 else if (!is_pair (args))
5075 root 1.1 {
5076 root 1.18 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5077 root 1.1 s_return (S_T);
5078     }
5079     else
5080     {
5081 root 1.18 pointer a = car (args);
5082     pointer b = cdr (args);
5083     int ok_abbr = ok_abbrev (b);
5084     SCHEME_V->args = car (b);
5085    
5086     if (a == SCHEME_V->QUOTE && ok_abbr)
5087     putstr (SCHEME_A_ "'");
5088     else if (a == SCHEME_V->QQUOTE && ok_abbr)
5089     putstr (SCHEME_A_ "`");
5090     else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5091     putstr (SCHEME_A_ ",");
5092     else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5093     putstr (SCHEME_A_ ",@");
5094     else
5095     {
5096     putstr (SCHEME_A_ "(");
5097     s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5098     SCHEME_V->args = a;
5099     }
5100    
5101 root 1.1 s_goto (OP_P0LIST);
5102     }
5103    
5104     case OP_P1LIST:
5105 root 1.18 if (is_pair (args))
5106 root 1.1 {
5107 root 1.18 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5108 root 1.1 putstr (SCHEME_A_ " ");
5109 root 1.18 SCHEME_V->args = car (args);
5110 root 1.1 s_goto (OP_P0LIST);
5111     }
5112 root 1.18 else if (is_vector (args))
5113 root 1.1 {
5114     s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5115     putstr (SCHEME_A_ " . ");
5116     s_goto (OP_P0LIST);
5117     }
5118     else
5119     {
5120 root 1.18 if (args != NIL)
5121 root 1.1 {
5122     putstr (SCHEME_A_ " . ");
5123 root 1.18 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5124 root 1.1 }
5125    
5126     putstr (SCHEME_A_ ")");
5127     s_return (S_T);
5128     }
5129    
5130     case OP_PVECFROM:
5131     {
5132 root 1.18 int i = ivalue_unchecked (cdr (args));
5133     pointer vec = car (args);
5134 root 1.7 int len = veclength (vec);
5135 root 1.1
5136     if (i == len)
5137     {
5138     putstr (SCHEME_A_ ")");
5139     s_return (S_T);
5140     }
5141     else
5142     {
5143 root 1.28 pointer elem = vector_get (vec, i);
5144 root 1.1
5145 root 1.18 ivalue_unchecked (cdr (args)) = i + 1;
5146     s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5147 root 1.1 SCHEME_V->args = elem;
5148    
5149     if (i > 0)
5150     putstr (SCHEME_A_ " ");
5151    
5152     s_goto (OP_P0LIST);
5153     }
5154     }
5155     }
5156    
5157 root 1.24 if (USE_ERROR_CHECKING) abort ();
5158 root 1.1 }
5159    
5160 root 1.20 static int
5161 root 1.1 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5162     {
5163 root 1.18 pointer args = SCHEME_V->args;
5164     pointer a = car (args);
5165 root 1.1 pointer x, y;
5166    
5167     switch (op)
5168     {
5169     case OP_LIST_LENGTH: /* length *//* a.k */
5170     {
5171 root 1.18 long v = list_length (SCHEME_A_ a);
5172 root 1.1
5173     if (v < 0)
5174 root 1.18 Error_1 ("length: not a list:", a);
5175 root 1.1
5176     s_return (mk_integer (SCHEME_A_ v));
5177     }
5178    
5179     case OP_ASSQ: /* assq *//* a.k */
5180 root 1.18 x = a;
5181 root 1.1
5182 root 1.18 for (y = cadr (args); is_pair (y); y = cdr (y))
5183 root 1.1 {
5184     if (!is_pair (car (y)))
5185     Error_0 ("unable to handle non pair element");
5186    
5187     if (x == caar (y))
5188     break;
5189     }
5190    
5191     if (is_pair (y))
5192     s_return (car (y));
5193     else
5194     s_return (S_F);
5195    
5196    
5197     case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5198 root 1.18 SCHEME_V->args = a;
5199 root 1.1
5200     if (SCHEME_V->args == NIL)
5201     s_return (S_F);
5202     else if (is_closure (SCHEME_V->args))
5203     s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5204     else if (is_macro (SCHEME_V->args))
5205     s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5206     else
5207     s_return (S_F);
5208    
5209     case OP_CLOSUREP: /* closure? */
5210     /*
5211     * Note, macro object is also a closure.
5212     * Therefore, (closure? <#MACRO>) ==> #t
5213     */
5214 root 1.18 s_retbool (is_closure (a));
5215 root 1.1
5216     case OP_MACROP: /* macro? */
5217 root 1.18 s_retbool (is_macro (a));
5218 root 1.1 }
5219    
5220 root 1.24 if (USE_ERROR_CHECKING) abort ();
5221 root 1.1 }
5222    
5223 root 1.20 /* dispatch functions (opexe_x) return new opcode, or 0 for same opcode, or -1 to stop */
5224     typedef int (*dispatch_func)(SCHEME_P_ enum scheme_opcodes);
5225 root 1.1
5226 root 1.19 typedef int (*test_predicate)(pointer);
5227 root 1.1 static int
5228 root 1.26 tst_any (pointer p)
5229 root 1.1 {
5230     return 1;
5231     }
5232    
5233     static int
5234 root 1.26 tst_inonneg (pointer p)
5235 root 1.1 {
5236 root 1.26 return is_integer (p) && ivalue_unchecked (p) >= 0;
5237 root 1.1 }
5238    
5239 root 1.19 static int
5240 root 1.26 tst_is_list (SCHEME_P_ pointer p)
5241 root 1.19 {
5242     return p == NIL || is_pair (p);
5243     }
5244    
5245 root 1.1 /* Correspond carefully with following defines! */
5246     static struct
5247     {
5248     test_predicate fct;
5249     const char *kind;
5250 root 1.26 } tests[] = {
5251     { tst_any , 0 },
5252     { is_string , "string" },
5253     { is_symbol , "symbol" },
5254     { is_port , "port" },
5255     { is_inport , "input port" },
5256     { is_outport , "output port" },
5257 root 1.19 { is_environment, "environment" },
5258 root 1.26 { is_pair , "pair" },
5259     { 0 , "pair or '()" },
5260     { is_character , "character" },
5261     { is_vector , "vector" },
5262     { is_number , "number" },
5263     { is_integer , "integer" },
5264     { tst_inonneg , "non-negative integer" }
5265 root 1.1 };
5266    
5267 root 1.20 #define TST_NONE 0 /* TST_NONE used for built-ins, 0 for internal ops */
5268 root 1.18 #define TST_ANY "\001"
5269     #define TST_STRING "\002"
5270     #define TST_SYMBOL "\003"
5271     #define TST_PORT "\004"
5272     #define TST_INPORT "\005"
5273     #define TST_OUTPORT "\006"
5274 root 1.1 #define TST_ENVIRONMENT "\007"
5275 root 1.18 #define TST_PAIR "\010"
5276     #define TST_LIST "\011"
5277     #define TST_CHAR "\012"
5278     #define TST_VECTOR "\013"
5279     #define TST_NUMBER "\014"
5280     #define TST_INTEGER "\015"
5281     #define TST_NATURAL "\016"
5282 root 1.1
5283 root 1.20 #define INF_ARG 0xff
5284     #define UNNAMED_OP ""
5285    
5286     static const char opnames[] =
5287     #define OP_DEF(func,name,minarity,maxarity,argtest,op) name "\x00"
5288     #include "opdefines.h"
5289     #undef OP_DEF
5290     ;
5291    
5292     static const char *
5293     opname (int idx)
5294     {
5295     const char *name = opnames;
5296    
5297     /* should do this at compile time, but would require external program, right? */
5298     while (idx--)
5299     name += strlen (name) + 1;
5300    
5301     return *name ? name : "ILLEGAL";
5302     }
5303    
5304     static const char *
5305     procname (pointer x)
5306     {
5307     return opname (procnum (x));
5308     }
5309    
5310 root 1.1 typedef struct
5311     {
5312 root 1.20 uint8_t func;
5313     /*dispatch_func func;*//*TODO: maybe optionally keep the pointer, for speed? */
5314     uint8_t builtin;
5315 root 1.26 #if USE_ERROR_CHECKING
5316 root 1.20 uint8_t min_arity;
5317     uint8_t max_arity;
5318 root 1.18 char arg_tests_encoding[3];
5319 root 1.26 #endif
5320 root 1.1 } op_code_info;
5321    
5322 root 1.20 static const op_code_info dispatch_table[] = {
5323 root 1.26 #if USE_ERROR_CHECKING
5324 root 1.20 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1, minarity, maxarity, argtest },
5325 root 1.26 #else
5326     #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1 },
5327     #endif
5328 root 1.1 #include "opdefines.h"
5329 root 1.18 #undef OP_DEF
5330 root 1.1 {0}
5331     };
5332    
5333     /* kernel of this interpreter */
5334 root 1.23 static void ecb_hot
5335 root 1.1 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5336     {
5337     SCHEME_V->op = op;
5338    
5339     for (;;)
5340     {
5341 root 1.20 const op_code_info *pcd = dispatch_table + SCHEME_V->op;
5342 root 1.1
5343 root 1.4 #if USE_ERROR_CHECKING
5344 root 1.20 if (pcd->builtin) /* if built-in function, check arguments */
5345 root 1.1 {
5346     char msg[STRBUFFSIZE];
5347     int n = list_length (SCHEME_A_ SCHEME_V->args);
5348    
5349     /* Check number of arguments */
5350 root 1.10 if (ecb_expect_false (n < pcd->min_arity))
5351 root 1.1 {
5352     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5353 root 1.20 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5354 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5355     continue;
5356 root 1.1 }
5357 root 1.20 else if (ecb_expect_false (n > pcd->max_arity && pcd->max_arity != INF_ARG))
5358 root 1.1 {
5359     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5360 root 1.20 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5361 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5362     continue;
5363 root 1.1 }
5364 root 1.20 else
5365 root 1.1 {
5366 root 1.20 if (*pcd->arg_tests_encoding) /* literal 0 and TST_NONE treated the same */
5367 root 1.1 {
5368     int i = 0;
5369     int j;
5370     const char *t = pcd->arg_tests_encoding;
5371     pointer arglist = SCHEME_V->args;
5372    
5373     do
5374     {
5375     pointer arg = car (arglist);
5376    
5377 root 1.18 j = t[0];
5378 root 1.1
5379 root 1.26 /*TODO: tst_is_list has different prototype - fix if other tests acquire same prototype */
5380     if (j == TST_LIST[0])
5381     {
5382     if (!tst_is_list (SCHEME_A_ arg))
5383     break;
5384     }
5385     else
5386     {
5387     if (!tests[j - 1].fct (arg))
5388     break;
5389     }
5390 root 1.1
5391 root 1.28 if (t < pcd->arg_tests_encoding + sizeof (pcd->arg_tests_encoding) - 1 && t[1]) /* last test is replicated as necessary */
5392 root 1.2 t++;
5393 root 1.1
5394     arglist = cdr (arglist);
5395     i++;
5396     }
5397     while (i < n);
5398    
5399     if (i < n)
5400     {
5401 root 1.20 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", opname (SCHEME_V->op), i + 1, tests[j].kind);
5402 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5403     continue;
5404 root 1.1 }
5405     }
5406     }
5407     }
5408 root 1.4 #endif
5409 root 1.1
5410     ok_to_freely_gc (SCHEME_A);
5411    
5412 root 1.20 static const dispatch_func dispatch_funcs[] = {
5413     opexe_0,
5414     opexe_1,
5415     opexe_2,
5416     opexe_3,
5417     opexe_4,
5418     opexe_5,
5419     opexe_6,
5420     };
5421    
5422     if (ecb_expect_false (dispatch_funcs [pcd->func] (SCHEME_A_ SCHEME_V->op) != 0))
5423 root 1.1 return;
5424    
5425 root 1.5 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5426 root 1.1 {
5427     xwrstr ("No memory!\n");
5428     return;
5429     }
5430     }
5431     }
5432    
5433     /* ========== Initialization of internal keywords ========== */
5434    
5435     static void
5436 root 1.2 assign_syntax (SCHEME_P_ const char *name)
5437 root 1.1 {
5438     pointer x = oblist_add_by_name (SCHEME_A_ name);
5439     set_typeflag (x, typeflag (x) | T_SYNTAX);
5440     }
5441    
5442     static void
5443 root 1.2 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5444 root 1.1 {
5445     pointer x = mk_symbol (SCHEME_A_ name);
5446     pointer y = mk_proc (SCHEME_A_ op);
5447     new_slot_in_env (SCHEME_A_ x, y);
5448     }
5449    
5450     static pointer
5451     mk_proc (SCHEME_P_ enum scheme_opcodes op)
5452     {
5453     pointer y = get_cell (SCHEME_A_ NIL, NIL);
5454     set_typeflag (y, (T_PROC | T_ATOM));
5455 root 1.2 ivalue_unchecked (y) = op;
5456 root 1.1 return y;
5457     }
5458    
5459     /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5460     static int
5461     syntaxnum (pointer p)
5462     {
5463     const char *s = strvalue (car (p));
5464    
5465     switch (strlength (car (p)))
5466     {
5467     case 2:
5468     if (s[0] == 'i')
5469     return OP_IF0; /* if */
5470     else
5471     return OP_OR0; /* or */
5472    
5473     case 3:
5474     if (s[0] == 'a')
5475     return OP_AND0; /* and */
5476     else
5477     return OP_LET0; /* let */
5478    
5479     case 4:
5480     switch (s[3])
5481     {
5482     case 'e':
5483     return OP_CASE0; /* case */
5484    
5485     case 'd':
5486     return OP_COND0; /* cond */
5487    
5488     case '*':
5489 root 1.10 return OP_LET0AST;/* let* */
5490 root 1.1
5491     default:
5492     return OP_SET0; /* set! */
5493     }
5494    
5495     case 5:
5496     switch (s[2])
5497     {
5498     case 'g':
5499     return OP_BEGIN; /* begin */
5500    
5501     case 'l':
5502     return OP_DELAY; /* delay */
5503    
5504     case 'c':
5505     return OP_MACRO0; /* macro */
5506    
5507     default:
5508     return OP_QUOTE; /* quote */
5509     }
5510    
5511     case 6:
5512     switch (s[2])
5513     {
5514     case 'm':
5515     return OP_LAMBDA; /* lambda */
5516    
5517     case 'f':
5518     return OP_DEF0; /* define */
5519    
5520     default:
5521 root 1.10 return OP_LET0REC;/* letrec */
5522 root 1.1 }
5523    
5524     default:
5525     return OP_C0STREAM; /* cons-stream */
5526     }
5527     }
5528    
5529     #if USE_MULTIPLICITY
5530 root 1.23 ecb_cold scheme *
5531 root 1.1 scheme_init_new ()
5532     {
5533     scheme *sc = malloc (sizeof (scheme));
5534    
5535     if (!scheme_init (SCHEME_A))
5536     {
5537     free (SCHEME_A);
5538     return 0;
5539     }
5540     else
5541     return sc;
5542     }
5543     #endif
5544    
5545 root 1.23 ecb_cold int
5546 root 1.1 scheme_init (SCHEME_P)
5547     {
5548     int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5549     pointer x;
5550    
5551     num_set_fixnum (num_zero, 1);
5552     num_set_ivalue (num_zero, 0);
5553     num_set_fixnum (num_one, 1);
5554     num_set_ivalue (num_one, 1);
5555    
5556     #if USE_INTERFACE
5557     SCHEME_V->vptr = &vtbl;
5558     #endif
5559     SCHEME_V->gensym_cnt = 0;
5560     SCHEME_V->last_cell_seg = -1;
5561     SCHEME_V->free_cell = NIL;
5562     SCHEME_V->fcells = 0;
5563     SCHEME_V->no_memory = 0;
5564     SCHEME_V->inport = NIL;
5565     SCHEME_V->outport = NIL;
5566     SCHEME_V->save_inport = NIL;
5567     SCHEME_V->loadport = NIL;
5568     SCHEME_V->nesting = 0;
5569     SCHEME_V->interactive_repl = 0;
5570    
5571     if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5572     {
5573     #if USE_ERROR_CHECKING
5574     SCHEME_V->no_memory = 1;
5575     return 0;
5576     #endif
5577     }
5578    
5579     SCHEME_V->gc_verbose = 0;
5580     dump_stack_initialize (SCHEME_A);
5581     SCHEME_V->code = NIL;
5582 root 1.2 SCHEME_V->args = NIL;
5583     SCHEME_V->envir = NIL;
5584 root 1.1 SCHEME_V->tracing = 0;
5585    
5586     /* init NIL */
5587 root 1.2 set_typeflag (NIL, T_ATOM | T_MARK);
5588 root 1.1 set_car (NIL, NIL);
5589     set_cdr (NIL, NIL);
5590     /* init T */
5591 root 1.2 set_typeflag (S_T, T_ATOM | T_MARK);
5592 root 1.1 set_car (S_T, S_T);
5593     set_cdr (S_T, S_T);
5594     /* init F */
5595 root 1.2 set_typeflag (S_F, T_ATOM | T_MARK);
5596 root 1.1 set_car (S_F, S_F);
5597     set_cdr (S_F, S_F);
5598 root 1.7 /* init EOF_OBJ */
5599     set_typeflag (S_EOF, T_ATOM | T_MARK);
5600     set_car (S_EOF, S_EOF);
5601     set_cdr (S_EOF, S_EOF);
5602 root 1.1 /* init sink */
5603 root 1.2 set_typeflag (S_SINK, T_PAIR | T_MARK);
5604 root 1.1 set_car (S_SINK, NIL);
5605 root 1.7
5606 root 1.1 /* init c_nest */
5607     SCHEME_V->c_nest = NIL;
5608    
5609     SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5610     /* init global_env */
5611     new_frame_in_env (SCHEME_A_ NIL);
5612     SCHEME_V->global_env = SCHEME_V->envir;
5613     /* init else */
5614     x = mk_symbol (SCHEME_A_ "else");
5615     new_slot_in_env (SCHEME_A_ x, S_T);
5616    
5617 root 1.2 {
5618     static const char *syntax_names[] = {
5619     "lambda", "quote", "define", "if", "begin", "set!",
5620     "let", "let*", "letrec", "cond", "delay", "and",
5621     "or", "cons-stream", "macro", "case"
5622     };
5623    
5624     for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5625     assign_syntax (SCHEME_A_ syntax_names[i]);
5626     }
5627 root 1.1
5628 root 1.20 // TODO: should iterate via strlen, to avoid n² complexity
5629 root 1.1 for (i = 0; i < n; i++)
5630 root 1.20 if (dispatch_table[i].builtin)
5631     assign_proc (SCHEME_A_ i, opname (i));
5632 root 1.1
5633     /* initialization of global pointers to special symbols */
5634 root 1.6 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5635     SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5636     SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5637     SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5638     SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5639     SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5640     SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5641     SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5642     SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5643 root 1.1 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5644    
5645     return !SCHEME_V->no_memory;
5646     }
5647    
5648     #if USE_PORTS
5649     void
5650     scheme_set_input_port_file (SCHEME_P_ int fin)
5651     {
5652     SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5653     }
5654    
5655     void
5656     scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5657     {
5658     SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5659     }
5660    
5661     void
5662     scheme_set_output_port_file (SCHEME_P_ int fout)
5663     {
5664     SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5665     }
5666    
5667     void
5668     scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5669     {
5670     SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5671     }
5672     #endif
5673    
5674     void
5675     scheme_set_external_data (SCHEME_P_ void *p)
5676     {
5677     SCHEME_V->ext_data = p;
5678     }
5679    
5680 root 1.23 ecb_cold void
5681 root 1.1 scheme_deinit (SCHEME_P)
5682     {
5683     int i;
5684    
5685     #if SHOW_ERROR_LINE
5686     char *fname;
5687     #endif
5688    
5689     SCHEME_V->oblist = NIL;
5690     SCHEME_V->global_env = NIL;
5691     dump_stack_free (SCHEME_A);
5692     SCHEME_V->envir = NIL;
5693     SCHEME_V->code = NIL;
5694     SCHEME_V->args = NIL;
5695     SCHEME_V->value = NIL;
5696    
5697     if (is_port (SCHEME_V->inport))
5698     set_typeflag (SCHEME_V->inport, T_ATOM);
5699    
5700     SCHEME_V->inport = NIL;
5701     SCHEME_V->outport = NIL;
5702    
5703     if (is_port (SCHEME_V->save_inport))
5704     set_typeflag (SCHEME_V->save_inport, T_ATOM);
5705    
5706     SCHEME_V->save_inport = NIL;
5707    
5708     if (is_port (SCHEME_V->loadport))
5709     set_typeflag (SCHEME_V->loadport, T_ATOM);
5710    
5711     SCHEME_V->loadport = NIL;
5712     SCHEME_V->gc_verbose = 0;
5713     gc (SCHEME_A_ NIL, NIL);
5714    
5715     for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5716     free (SCHEME_V->alloc_seg[i]);
5717    
5718     #if SHOW_ERROR_LINE
5719     for (i = 0; i <= SCHEME_V->file_i; i++)
5720     {
5721     if (SCHEME_V->load_stack[i].kind & port_file)
5722     {
5723     fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5724    
5725     if (fname)
5726     free (fname);
5727     }
5728     }
5729     #endif
5730     }
5731    
5732     void
5733     scheme_load_file (SCHEME_P_ int fin)
5734     {
5735     scheme_load_named_file (SCHEME_A_ fin, 0);
5736     }
5737    
5738     void
5739     scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5740     {
5741     dump_stack_reset (SCHEME_A);
5742     SCHEME_V->envir = SCHEME_V->global_env;
5743     SCHEME_V->file_i = 0;
5744     SCHEME_V->load_stack[0].unget = -1;
5745     SCHEME_V->load_stack[0].kind = port_input | port_file;
5746     SCHEME_V->load_stack[0].rep.stdio.file = fin;
5747     #if USE_PORTS
5748     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5749     #endif
5750     SCHEME_V->retcode = 0;
5751    
5752     #if USE_PORTS
5753     if (fin == STDIN_FILENO)
5754     SCHEME_V->interactive_repl = 1;
5755     #endif
5756    
5757     #if USE_PORTS
5758     #if SHOW_ERROR_LINE
5759     SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5760    
5761     if (fin != STDIN_FILENO && filename)
5762     SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5763     #endif
5764     #endif
5765    
5766     SCHEME_V->inport = SCHEME_V->loadport;
5767     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5768     Eval_Cycle (SCHEME_A_ OP_T0LVL);
5769     set_typeflag (SCHEME_V->loadport, T_ATOM);
5770    
5771     if (SCHEME_V->retcode == 0)
5772     SCHEME_V->retcode = SCHEME_V->nesting != 0;
5773     }
5774    
5775     void
5776     scheme_load_string (SCHEME_P_ const char *cmd)
5777     {
5778     dump_stack_reset (SCHEME_A);
5779     SCHEME_V->envir = SCHEME_V->global_env;
5780     SCHEME_V->file_i = 0;
5781     SCHEME_V->load_stack[0].kind = port_input | port_string;
5782 root 1.17 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
5783     SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
5784     SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
5785 root 1.1 #if USE_PORTS
5786     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5787     #endif
5788     SCHEME_V->retcode = 0;
5789     SCHEME_V->interactive_repl = 0;
5790     SCHEME_V->inport = SCHEME_V->loadport;
5791     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5792     Eval_Cycle (SCHEME_A_ OP_T0LVL);
5793     set_typeflag (SCHEME_V->loadport, T_ATOM);
5794    
5795     if (SCHEME_V->retcode == 0)
5796     SCHEME_V->retcode = SCHEME_V->nesting != 0;
5797     }
5798    
5799     void
5800     scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
5801     {
5802     pointer x;
5803    
5804     x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
5805    
5806     if (x != NIL)
5807 root 1.2 set_slot_in_env (SCHEME_A_ x, value);
5808 root 1.1 else
5809 root 1.2 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
5810 root 1.1 }
5811    
5812     #if !STANDALONE
5813 root 1.2
5814 root 1.1 void
5815     scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
5816     {
5817     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
5818     }
5819    
5820     void
5821     scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
5822     {
5823     int i;
5824    
5825     for (i = 0; i < count; i++)
5826 root 1.2 scheme_register_foreign_func (SCHEME_A_ list + i);
5827 root 1.1 }
5828    
5829     pointer
5830     scheme_apply0 (SCHEME_P_ const char *procname)
5831     {
5832     return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
5833     }
5834    
5835     void
5836     save_from_C_call (SCHEME_P)
5837     {
5838     pointer saved_data = cons (car (S_SINK),
5839     cons (SCHEME_V->envir,
5840     SCHEME_V->dump));
5841    
5842     /* Push */
5843     SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
5844     /* Truncate the dump stack so TS will return here when done, not
5845     directly resume pre-C-call operations. */
5846     dump_stack_reset (SCHEME_A);
5847     }
5848    
5849     void
5850     restore_from_C_call (SCHEME_P)
5851     {
5852     set_car (S_SINK, caar (SCHEME_V->c_nest));
5853     SCHEME_V->envir = cadar (SCHEME_V->c_nest);
5854     SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
5855     /* Pop */
5856     SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
5857     }
5858    
5859     /* "func" and "args" are assumed to be already eval'ed. */
5860     pointer
5861     scheme_call (SCHEME_P_ pointer func, pointer args)
5862     {
5863     int old_repl = SCHEME_V->interactive_repl;
5864    
5865     SCHEME_V->interactive_repl = 0;
5866     save_from_C_call (SCHEME_A);
5867     SCHEME_V->envir = SCHEME_V->global_env;
5868     SCHEME_V->args = args;
5869     SCHEME_V->code = func;
5870     SCHEME_V->retcode = 0;
5871     Eval_Cycle (SCHEME_A_ OP_APPLY);
5872     SCHEME_V->interactive_repl = old_repl;
5873     restore_from_C_call (SCHEME_A);
5874     return SCHEME_V->value;
5875     }
5876    
5877     pointer
5878     scheme_eval (SCHEME_P_ pointer obj)
5879     {
5880     int old_repl = SCHEME_V->interactive_repl;
5881    
5882     SCHEME_V->interactive_repl = 0;
5883     save_from_C_call (SCHEME_A);
5884     SCHEME_V->args = NIL;
5885     SCHEME_V->code = obj;
5886     SCHEME_V->retcode = 0;
5887     Eval_Cycle (SCHEME_A_ OP_EVAL);
5888     SCHEME_V->interactive_repl = old_repl;
5889     restore_from_C_call (SCHEME_A);
5890     return SCHEME_V->value;
5891     }
5892    
5893     #endif
5894    
5895     /* ========== Main ========== */
5896    
5897     #if STANDALONE
5898    
5899     int
5900     main (int argc, char **argv)
5901     {
5902     # if USE_MULTIPLICITY
5903     scheme ssc;
5904 root 1.2 scheme *const SCHEME_V = &ssc;
5905 root 1.1 # else
5906     # endif
5907     int fin;
5908     char *file_name = InitFile;
5909     int retcode;
5910     int isfile = 1;
5911    
5912     if (argc == 2 && strcmp (argv[1], "-?") == 0)
5913     {
5914     xwrstr ("Usage: tinyscheme -?\n");
5915     xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
5916     xwrstr ("followed by\n");
5917     xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
5918     xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5919     xwrstr ("assuming that the executable is named tinyscheme.\n");
5920     xwrstr ("Use - as filename for stdin.\n");
5921     return 1;
5922     }
5923    
5924     if (!scheme_init (SCHEME_A))
5925     {
5926     xwrstr ("Could not initialize!\n");
5927     return 2;
5928     }
5929    
5930     # if USE_PORTS
5931     scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
5932     scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
5933     # endif
5934    
5935     argv++;
5936    
5937     #if 0
5938     if (access (file_name, 0) != 0)
5939     {
5940     char *p = getenv ("TINYSCHEMEINIT");
5941    
5942     if (p != 0)
5943 root 1.2 file_name = p;
5944 root 1.1 }
5945     #endif
5946    
5947     do
5948     {
5949     #if USE_PORTS
5950     if (strcmp (file_name, "-") == 0)
5951     fin = STDIN_FILENO;
5952     else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
5953     {
5954     pointer args = NIL;
5955    
5956     isfile = file_name[1] == '1';
5957     file_name = *argv++;
5958    
5959     if (strcmp (file_name, "-") == 0)
5960     fin = STDIN_FILENO;
5961     else if (isfile)
5962     fin = open (file_name, O_RDONLY);
5963    
5964     for (; *argv; argv++)
5965     {
5966     pointer value = mk_string (SCHEME_A_ * argv);
5967    
5968     args = cons (value, args);
5969     }
5970    
5971     args = reverse_in_place (SCHEME_A_ NIL, args);
5972     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
5973    
5974     }
5975     else
5976     fin = open (file_name, O_RDONLY);
5977     #endif
5978    
5979     if (isfile && fin < 0)
5980     {
5981     xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
5982     }
5983     else
5984     {
5985     if (isfile)
5986     scheme_load_named_file (SCHEME_A_ fin, file_name);
5987     else
5988     scheme_load_string (SCHEME_A_ file_name);
5989    
5990     #if USE_PORTS
5991     if (!isfile || fin != STDIN_FILENO)
5992     {
5993     if (SCHEME_V->retcode != 0)
5994     {
5995     xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
5996     }
5997    
5998     if (isfile)
5999     close (fin);
6000     }
6001     #endif
6002     }
6003    
6004     file_name = *argv++;
6005     }
6006     while (file_name != 0);
6007    
6008     if (argc == 1)
6009     scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6010    
6011     retcode = SCHEME_V->retcode;
6012     scheme_deinit (SCHEME_A);
6013    
6014     return retcode;
6015     }
6016    
6017     #endif
6018    
6019     /*
6020     Local variables:
6021     c-file-style: "k&r"
6022     End:
6023     */