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