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