ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.45
Committed: Mon Nov 30 07:44:23 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.44: +5 -2 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.45 const int min_to_be_recovered = SCHEME_V->cell_segsize [SCHEME_V->last_cell_seg] >> 2;
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     case OP_CAR: /* car */
4205 root 1.16 s_return (caar (args));
4206 root 1.1
4207     case OP_CDR: /* cdr */
4208 root 1.16 s_return (cdar (args));
4209 root 1.1
4210     case OP_CONS: /* cons */
4211 root 1.16 set_cdr (args, cadr (args));
4212     s_return (args);
4213 root 1.1
4214     case OP_SETCAR: /* set-car! */
4215 root 1.16 if (!is_immutable (x))
4216 root 1.1 {
4217 root 1.16 set_car (x, cadr (args));
4218     s_return (car (args));
4219 root 1.1 }
4220     else
4221     Error_0 ("set-car!: unable to alter immutable pair");
4222    
4223     case OP_SETCDR: /* set-cdr! */
4224 root 1.16 if (!is_immutable (x))
4225 root 1.1 {
4226 root 1.16 set_cdr (x, cadr (args));
4227     s_return (car (args));
4228 root 1.1 }
4229     else
4230     Error_0 ("set-cdr!: unable to alter immutable pair");
4231    
4232     case OP_CHAR2INT: /* char->integer */
4233 root 1.26 s_return (mk_integer (SCHEME_A_ ivalue_unchecked (x)));
4234 root 1.1
4235     case OP_INT2CHAR: /* integer->char */
4236 root 1.26 s_return (mk_character (SCHEME_A_ ivalue_unchecked (x)));
4237 root 1.1
4238     case OP_CHARUPCASE:
4239     {
4240 root 1.26 unsigned char c = ivalue_unchecked (x);
4241 root 1.1 c = toupper (c);
4242 root 1.2 s_return (mk_character (SCHEME_A_ c));
4243 root 1.1 }
4244    
4245     case OP_CHARDNCASE:
4246     {
4247 root 1.26 unsigned char c = ivalue_unchecked (x);
4248 root 1.1 c = tolower (c);
4249 root 1.2 s_return (mk_character (SCHEME_A_ c));
4250 root 1.1 }
4251    
4252     case OP_STR2SYM: /* string->symbol */
4253 root 1.16 s_return (mk_symbol (SCHEME_A_ strvalue (x)));
4254 root 1.1
4255     case OP_STR2ATOM: /* string->atom */
4256     {
4257 root 1.16 char *s = strvalue (x);
4258 root 1.1 long pf = 0;
4259    
4260 root 1.16 if (cdr (args) != NIL)
4261 root 1.1 {
4262 root 1.16 /* we know cadr(args) is a natural number */
4263 root 1.1 /* see if it is 2, 8, 10, or 16, or error */
4264 root 1.16 pf = ivalue_unchecked (cadr (args));
4265 root 1.1
4266     if (pf == 16 || pf == 10 || pf == 8 || pf == 2)
4267     {
4268     /* base is OK */
4269     }
4270     else
4271 root 1.2 pf = -1;
4272 root 1.1 }
4273    
4274     if (pf < 0)
4275 root 1.16 Error_1 ("string->atom: bad base:", cadr (args));
4276 root 1.1 else if (*s == '#') /* no use of base! */
4277 root 1.2 s_return (mk_sharp_const (SCHEME_A_ s + 1));
4278 root 1.1 else
4279     {
4280     if (pf == 0 || pf == 10)
4281 root 1.2 s_return (mk_atom (SCHEME_A_ s));
4282 root 1.1 else
4283     {
4284     char *ep;
4285     long iv = strtol (s, &ep, (int) pf);
4286    
4287     if (*ep == 0)
4288 root 1.2 s_return (mk_integer (SCHEME_A_ iv));
4289 root 1.1 else
4290 root 1.2 s_return (S_F);
4291 root 1.1 }
4292     }
4293     }
4294    
4295     case OP_SYM2STR: /* symbol->string */
4296 root 1.16 x = mk_string (SCHEME_A_ symname (x));
4297 root 1.1 setimmutable (x);
4298     s_return (x);
4299    
4300     case OP_ATOM2STR: /* atom->string */
4301     {
4302     long pf = 0;
4303    
4304 root 1.16 if (cdr (args) != NIL)
4305 root 1.1 {
4306 root 1.16 /* we know cadr(args) is a natural number */
4307 root 1.1 /* see if it is 2, 8, 10, or 16, or error */
4308 root 1.16 pf = ivalue_unchecked (cadr (args));
4309 root 1.1
4310     if (is_number (x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2))
4311     {
4312     /* base is OK */
4313     }
4314     else
4315 root 1.2 pf = -1;
4316 root 1.1 }
4317    
4318     if (pf < 0)
4319 root 1.16 Error_1 ("atom->string: bad base:", cadr (args));
4320 root 1.1 else if (is_number (x) || is_character (x) || is_string (x) || is_symbol (x))
4321     {
4322     char *p;
4323     int len;
4324    
4325 root 1.2 atom2str (SCHEME_A_ x, pf, &p, &len);
4326 root 1.1 s_return (mk_counted_string (SCHEME_A_ p, len));
4327     }
4328     else
4329 root 1.2 Error_1 ("atom->string: not an atom:", x);
4330 root 1.1 }
4331    
4332     case OP_MKSTRING: /* make-string */
4333     {
4334 root 1.26 int fill = cdr (args) != NIL ? charvalue (cadr (args)) : ' ';
4335     int len = ivalue_unchecked (x);
4336 root 1.1
4337 root 1.17 s_return (mk_empty_string (SCHEME_A_ len, fill));
4338 root 1.1 }
4339    
4340     case OP_STRLEN: /* string-length */
4341 root 1.16 s_return (mk_integer (SCHEME_A_ strlength (x)));
4342 root 1.1
4343     case OP_STRREF: /* string-ref */
4344     {
4345 root 1.26 char *str = strvalue (x);
4346     int index = ivalue_unchecked (cadr (args));
4347 root 1.1
4348 root 1.16 if (index >= strlength (x))
4349     Error_1 ("string-ref: out of bounds:", cadr (args));
4350 root 1.1
4351 root 1.17 s_return (mk_character (SCHEME_A_ ((unsigned char *)str)[index]));
4352 root 1.1 }
4353    
4354     case OP_STRSET: /* string-set! */
4355     {
4356 root 1.26 char *str = strvalue (x);
4357     int index = ivalue_unchecked (cadr (args));
4358 root 1.1 int c;
4359    
4360 root 1.16 if (is_immutable (x))
4361     Error_1 ("string-set!: unable to alter immutable string:", x);
4362 root 1.1
4363 root 1.16 if (index >= strlength (x))
4364     Error_1 ("string-set!: out of bounds:", cadr (args));
4365 root 1.1
4366 root 1.16 c = charvalue (caddr (args));
4367 root 1.1
4368 root 1.17 str[index] = c;
4369 root 1.16 s_return (car (args));
4370 root 1.1 }
4371    
4372     case OP_STRAPPEND: /* string-append */
4373     {
4374     /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4375     int len = 0;
4376     pointer newstr;
4377     char *pos;
4378    
4379     /* compute needed length for new string */
4380 root 1.16 for (x = args; x != NIL; x = cdr (x))
4381 root 1.2 len += strlength (car (x));
4382 root 1.1
4383     newstr = mk_empty_string (SCHEME_A_ len, ' ');
4384    
4385     /* store the contents of the argument strings into the new string */
4386 root 1.16 for (pos = strvalue (newstr), x = args; x != NIL; pos += strlength (car (x)), x = cdr (x))
4387 root 1.2 memcpy (pos, strvalue (car (x)), strlength (car (x)));
4388 root 1.1
4389     s_return (newstr);
4390     }
4391    
4392     case OP_SUBSTR: /* substring */
4393     {
4394 root 1.26 char *str = strvalue (x);
4395     int index0 = ivalue_unchecked (cadr (args));
4396 root 1.1 int index1;
4397     int len;
4398    
4399 root 1.16 if (index0 > strlength (x))
4400     Error_1 ("substring: start out of bounds:", cadr (args));
4401 root 1.1
4402 root 1.16 if (cddr (args) != NIL)
4403 root 1.1 {
4404 root 1.26 index1 = ivalue_unchecked (caddr (args));
4405 root 1.1
4406 root 1.16 if (index1 > strlength (x) || index1 < index0)
4407     Error_1 ("substring: end out of bounds:", caddr (args));
4408 root 1.1 }
4409     else
4410 root 1.16 index1 = strlength (x);
4411 root 1.1
4412     len = index1 - index0;
4413     x = mk_empty_string (SCHEME_A_ len, ' ');
4414     memcpy (strvalue (x), str + index0, len);
4415     strvalue (x)[len] = 0;
4416    
4417     s_return (x);
4418     }
4419    
4420     case OP_VECTOR: /* vector */
4421     {
4422     int i;
4423     pointer vec;
4424 root 1.16 int len = list_length (SCHEME_A_ args);
4425 root 1.1
4426     if (len < 0)
4427 root 1.16 Error_1 ("vector: not a proper list:", args);
4428 root 1.1
4429     vec = mk_vector (SCHEME_A_ len);
4430    
4431     #if USE_ERROR_CHECKING
4432     if (SCHEME_V->no_memory)
4433     s_return (S_SINK);
4434     #endif
4435    
4436 root 1.16 for (x = args, i = 0; is_pair (x); x = cdr (x), i++)
4437 root 1.28 vector_set (vec, i, car (x));
4438 root 1.1
4439     s_return (vec);
4440     }
4441    
4442     case OP_MKVECTOR: /* make-vector */
4443     {
4444     pointer fill = NIL;
4445     pointer vec;
4446 root 1.26 int len = ivalue_unchecked (x);
4447 root 1.1
4448 root 1.16 if (cdr (args) != NIL)
4449     fill = cadr (args);
4450 root 1.1
4451     vec = mk_vector (SCHEME_A_ len);
4452    
4453     #if USE_ERROR_CHECKING
4454     if (SCHEME_V->no_memory)
4455     s_return (S_SINK);
4456     #endif
4457    
4458     if (fill != NIL)
4459 root 1.28 fill_vector (vec, 0, fill);
4460 root 1.1
4461     s_return (vec);
4462     }
4463    
4464     case OP_VECLEN: /* vector-length */
4465 root 1.16 s_return (mk_integer (SCHEME_A_ veclength (x)));
4466 root 1.1
4467 root 1.37 case OP_VECRESIZE:
4468     vector_resize (x, ivalue_unchecked (cadr (args)), caddr (args));
4469     s_return (x);
4470    
4471 root 1.1 case OP_VECREF: /* vector-ref */
4472     {
4473 root 1.26 int index = ivalue_unchecked (cadr (args));
4474 root 1.1
4475 root 1.16 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4476     Error_1 ("vector-ref: out of bounds:", cadr (args));
4477 root 1.1
4478 root 1.28 s_return (vector_get (x, index));
4479 root 1.1 }
4480    
4481     case OP_VECSET: /* vector-set! */
4482     {
4483 root 1.26 int index = ivalue_unchecked (cadr (args));
4484 root 1.1
4485 root 1.16 if (is_immutable (x))
4486     Error_1 ("vector-set!: unable to alter immutable vector:", x);
4487 root 1.1
4488 root 1.16 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4489     Error_1 ("vector-set!: out of bounds:", cadr (args));
4490 root 1.1
4491 root 1.28 vector_set (x, index, caddr (args));
4492 root 1.16 s_return (x);
4493 root 1.1 }
4494     }
4495    
4496 root 1.24 if (USE_ERROR_CHECKING) abort ();
4497 root 1.1 }
4498    
4499 root 1.20 static int
4500     opexe_2 (SCHEME_P_ enum scheme_opcodes op)
4501 root 1.1 {
4502 root 1.14 pointer x = SCHEME_V->args;
4503 root 1.1
4504 root 1.14 for (;;)
4505 root 1.1 {
4506 root 1.14 num v = nvalue (car (x));
4507     x = cdr (x);
4508 root 1.1
4509 root 1.14 if (x == NIL)
4510     break;
4511 root 1.1
4512 root 1.14 int r = num_cmp (v, nvalue (car (x)));
4513 root 1.1
4514 root 1.14 switch (op)
4515     {
4516     case OP_NUMEQ: r = r == 0; break;
4517     case OP_LESS: r = r < 0; break;
4518     case OP_GRE: r = r > 0; break;
4519     case OP_LEQ: r = r <= 0; break;
4520     case OP_GEQ: r = r >= 0; break;
4521     }
4522 root 1.1
4523 root 1.14 if (!r)
4524     s_return (S_F);
4525     }
4526 root 1.1
4527 root 1.14 s_return (S_T);
4528     }
4529 root 1.1
4530 root 1.20 static int
4531 root 1.14 opexe_3 (SCHEME_P_ enum scheme_opcodes op)
4532     {
4533 root 1.16 pointer args = SCHEME_V->args;
4534     pointer a = car (args);
4535     pointer d = cdr (args);
4536 root 1.14 int r;
4537 root 1.1
4538 root 1.14 switch (op)
4539     {
4540 root 1.43 case OP_NOT: /* not */ r = is_false (a) ; break;
4541     case OP_BOOLP: /* boolean? */ r = a == S_F || a == S_T ; break;
4542     case OP_EOFOBJP: /* eof-object? */ r = a == S_EOF ; break;
4543     case OP_NULLP: /* null? */ r = a == NIL ; break;
4544     case OP_SYMBOLP: /* symbol? */ r = is_symbol (a) ; break;
4545     case OP_GENSYMP: /* gensym? */ r = is_gensym (SCHEME_A_ a); break;
4546     case OP_NUMBERP: /* number? */ r = is_number (a) ; break;
4547     case OP_STRINGP: /* string? */ r = is_string (a) ; break;
4548     case OP_INTEGERP: /* integer? */ r = is_integer (a) ; break;
4549     case OP_REALP: /* real? */ r = is_number (a) ; break; /* all numbers are real */
4550     case OP_CHARP: /* char? */ r = is_character (a) ; break;
4551 root 1.14
4552 root 1.1 #if USE_CHAR_CLASSIFIERS
4553 root 1.26 case OP_CHARAP: /* char-alphabetic? */ r = Cisalpha (ivalue_unchecked (a)); break;
4554     case OP_CHARNP: /* char-numeric? */ r = Cisdigit (ivalue_unchecked (a)); break;
4555     case OP_CHARWP: /* char-whitespace? */ r = Cisspace (ivalue_unchecked (a)); break;
4556     case OP_CHARUP: /* char-upper-case? */ r = Cisupper (ivalue_unchecked (a)); break;
4557     case OP_CHARLP: /* char-lower-case? */ r = Cislower (ivalue_unchecked (a)); break;
4558 root 1.1 #endif
4559 root 1.14
4560 root 1.1 #if USE_PORTS
4561 root 1.15 case OP_PORTP: /* port? */ r = is_port (a) ; break;
4562     case OP_INPORTP: /* input-port? */ r = is_inport (a) ; break;
4563     case OP_OUTPORTP: /* output-port? */ r = is_outport (a); break;
4564 root 1.1 #endif
4565    
4566     case OP_PROCP: /* procedure? */
4567    
4568 root 1.14 /*--
4569     * continuation should be procedure by the example
4570     * (call-with-current-continuation procedure?) ==> #t
4571     * in R^3 report sec. 6.9
4572     */
4573     r = is_proc (a) || is_closure (a) || is_continuation (a) || is_foreign (a);
4574     break;
4575 root 1.1
4576 root 1.15 case OP_PAIRP: /* pair? */ r = is_pair (a) ; break;
4577     case OP_LISTP: /* list? */ r = list_length (SCHEME_A_ a) >= 0; break;
4578     case OP_ENVP: /* environment? */ r = is_environment (a) ; break;
4579     case OP_VECTORP: /* vector? */ r = is_vector (a) ; break;
4580 root 1.16 case OP_EQ: /* eq? */ r = a == cadr (args) ; break;
4581     case OP_EQV: /* eqv? */ r = eqv (a, cadr (args)) ; break;
4582 root 1.1 }
4583    
4584 root 1.14 s_retbool (r);
4585 root 1.1 }
4586    
4587 root 1.20 static int
4588 root 1.1 opexe_4 (SCHEME_P_ enum scheme_opcodes op)
4589     {
4590 root 1.16 pointer args = SCHEME_V->args;
4591     pointer a = car (args);
4592 root 1.1 pointer x, y;
4593    
4594     switch (op)
4595     {
4596     case OP_FORCE: /* force */
4597 root 1.16 SCHEME_V->code = a;
4598 root 1.1
4599     if (is_promise (SCHEME_V->code))
4600     {
4601     /* Should change type to closure here */
4602     s_save (SCHEME_A_ OP_SAVE_FORCED, NIL, SCHEME_V->code);
4603     SCHEME_V->args = NIL;
4604     s_goto (OP_APPLY);
4605     }
4606     else
4607 root 1.2 s_return (SCHEME_V->code);
4608 root 1.1
4609     case OP_SAVE_FORCED: /* Save forced value replacing promise */
4610     memcpy (SCHEME_V->code, SCHEME_V->value, sizeof (struct cell));
4611     s_return (SCHEME_V->value);
4612    
4613     #if USE_PORTS
4614    
4615     case OP_WRITE: /* write */
4616     case OP_DISPLAY: /* display */
4617     case OP_WRITE_CHAR: /* write-char */
4618     if (is_pair (cdr (SCHEME_V->args)))
4619     {
4620     if (cadr (SCHEME_V->args) != SCHEME_V->outport)
4621     {
4622     x = cons (SCHEME_V->outport, NIL);
4623     s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4624     SCHEME_V->outport = cadr (SCHEME_V->args);
4625     }
4626     }
4627    
4628 root 1.16 SCHEME_V->args = a;
4629 root 1.1
4630     if (op == OP_WRITE)
4631     SCHEME_V->print_flag = 1;
4632     else
4633     SCHEME_V->print_flag = 0;
4634    
4635     s_goto (OP_P0LIST);
4636    
4637     case OP_NEWLINE: /* newline */
4638 root 1.16 if (is_pair (args))
4639 root 1.1 {
4640 root 1.16 if (a != SCHEME_V->outport)
4641 root 1.1 {
4642     x = cons (SCHEME_V->outport, NIL);
4643     s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4644 root 1.16 SCHEME_V->outport = a;
4645 root 1.1 }
4646     }
4647    
4648     putstr (SCHEME_A_ "\n");
4649     s_return (S_T);
4650     #endif
4651    
4652     case OP_ERR0: /* error */
4653     SCHEME_V->retcode = -1;
4654    
4655 root 1.16 if (!is_string (a))
4656 root 1.1 {
4657 root 1.16 args = cons (mk_string (SCHEME_A_ " -- "), args);
4658     setimmutable (car (args));
4659 root 1.1 }
4660    
4661     putstr (SCHEME_A_ "Error: ");
4662 root 1.16 putstr (SCHEME_A_ strvalue (car (args)));
4663     SCHEME_V->args = cdr (args);
4664 root 1.1 s_goto (OP_ERR1);
4665    
4666     case OP_ERR1: /* error */
4667     putstr (SCHEME_A_ " ");
4668    
4669 root 1.16 if (args != NIL)
4670 root 1.1 {
4671 root 1.16 s_save (SCHEME_A_ OP_ERR1, cdr (args), NIL);
4672     SCHEME_V->args = a;
4673 root 1.1 SCHEME_V->print_flag = 1;
4674     s_goto (OP_P0LIST);
4675     }
4676     else
4677     {
4678     putstr (SCHEME_A_ "\n");
4679    
4680     if (SCHEME_V->interactive_repl)
4681 root 1.2 s_goto (OP_T0LVL);
4682 root 1.1 else
4683 root 1.20 return -1;
4684 root 1.1 }
4685    
4686     case OP_REVERSE: /* reverse */
4687 root 1.16 s_return (reverse (SCHEME_A_ a));
4688 root 1.1
4689     case OP_LIST_STAR: /* list* */
4690     s_return (list_star (SCHEME_A_ SCHEME_V->args));
4691    
4692     case OP_APPEND: /* append */
4693     x = NIL;
4694 root 1.16 y = args;
4695 root 1.1
4696     if (y == x)
4697     s_return (x);
4698    
4699     /* cdr() in the while condition is not a typo. If car() */
4700     /* is used (append '() 'a) will return the wrong result. */
4701     while (cdr (y) != NIL)
4702     {
4703     x = revappend (SCHEME_A_ x, car (y));
4704     y = cdr (y);
4705    
4706     if (x == S_F)
4707     Error_0 ("non-list argument to append");
4708     }
4709    
4710     s_return (reverse_in_place (SCHEME_A_ car (y), x));
4711    
4712     #if USE_PLIST
4713    
4714     case OP_PUT: /* put */
4715 root 1.16 if (!hasprop (a) || !hasprop (cadr (args)))
4716 root 1.2 Error_0 ("illegal use of put");
4717 root 1.1
4718 root 1.16 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4719 root 1.1 {
4720     if (caar (x) == y)
4721 root 1.2 break;
4722 root 1.1 }
4723    
4724     if (x != NIL)
4725 root 1.16 cdar (x) = caddr (args);
4726 root 1.1 else
4727 root 1.16 symprop (a) = cons (cons (y, caddr (args)), symprop (a));
4728 root 1.1
4729     s_return (S_T);
4730    
4731     case OP_GET: /* get */
4732 root 1.16 if (!hasprop (a) || !hasprop (cadr (args)))
4733 root 1.1 Error_0 ("illegal use of get");
4734    
4735 root 1.16 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4736 root 1.1 if (caar (x) == y)
4737     break;
4738    
4739     if (x != NIL)
4740     s_return (cdar (x));
4741     else
4742     s_return (NIL);
4743    
4744     #endif /* USE_PLIST */
4745    
4746     case OP_QUIT: /* quit */
4747 root 1.16 if (is_pair (args))
4748     SCHEME_V->retcode = ivalue (a);
4749 root 1.1
4750 root 1.20 return -1;
4751 root 1.1
4752     case OP_GC: /* gc */
4753     gc (SCHEME_A_ NIL, NIL);
4754     s_return (S_T);
4755    
4756     case OP_GCVERB: /* gc-verbose */
4757     {
4758     int was = SCHEME_V->gc_verbose;
4759    
4760 root 1.16 SCHEME_V->gc_verbose = (a != S_F);
4761 root 1.1 s_retbool (was);
4762     }
4763    
4764     case OP_NEWSEGMENT: /* new-segment */
4765 root 1.16 if (!is_pair (args) || !is_number (a))
4766 root 1.1 Error_0 ("new-segment: argument must be a number");
4767    
4768 root 1.26 alloc_cellseg (SCHEME_A_ ivalue (a));
4769 root 1.1
4770     s_return (S_T);
4771    
4772     case OP_OBLIST: /* oblist */
4773     s_return (oblist_all_symbols (SCHEME_A));
4774    
4775     #if USE_PORTS
4776    
4777     case OP_CURR_INPORT: /* current-input-port */
4778     s_return (SCHEME_V->inport);
4779    
4780     case OP_CURR_OUTPORT: /* current-output-port */
4781     s_return (SCHEME_V->outport);
4782    
4783     case OP_OPEN_INFILE: /* open-input-file */
4784     case OP_OPEN_OUTFILE: /* open-output-file */
4785     case OP_OPEN_INOUTFILE: /* open-input-output-file */
4786     {
4787     int prop = 0;
4788     pointer p;
4789    
4790     switch (op)
4791     {
4792     case OP_OPEN_INFILE:
4793     prop = port_input;
4794     break;
4795    
4796     case OP_OPEN_OUTFILE:
4797     prop = port_output;
4798     break;
4799    
4800     case OP_OPEN_INOUTFILE:
4801     prop = port_input | port_output;
4802     break;
4803     }
4804    
4805 root 1.16 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
4806 root 1.1
4807 root 1.23 s_return (p == NIL ? S_F : p);
4808 root 1.1 }
4809    
4810     # if USE_STRING_PORTS
4811    
4812     case OP_OPEN_INSTRING: /* open-input-string */
4813     case OP_OPEN_INOUTSTRING: /* open-input-output-string */
4814     {
4815     int prop = 0;
4816     pointer p;
4817    
4818     switch (op)
4819     {
4820     case OP_OPEN_INSTRING:
4821     prop = port_input;
4822     break;
4823    
4824     case OP_OPEN_INOUTSTRING:
4825     prop = port_input | port_output;
4826     break;
4827     }
4828    
4829 root 1.16 p = port_from_string (SCHEME_A_ strvalue (a),
4830     strvalue (a) + strlength (a), prop);
4831 root 1.1
4832 root 1.23 s_return (p == NIL ? S_F : p);
4833 root 1.1 }
4834    
4835     case OP_OPEN_OUTSTRING: /* open-output-string */
4836     {
4837     pointer p;
4838    
4839 root 1.16 if (a == NIL)
4840 root 1.23 p = port_from_scratch (SCHEME_A);
4841 root 1.1 else
4842 root 1.23 p = port_from_string (SCHEME_A_ strvalue (a),
4843     strvalue (a) + strlength (a), port_output);
4844 root 1.1
4845 root 1.23 s_return (p == NIL ? S_F : p);
4846 root 1.1 }
4847    
4848     case OP_GET_OUTSTRING: /* get-output-string */
4849     {
4850     port *p;
4851    
4852 root 1.16 if ((p = a->object.port)->kind & port_string)
4853 root 1.1 {
4854     off_t size;
4855     char *str;
4856    
4857     size = p->rep.string.curr - p->rep.string.start + 1;
4858     str = malloc (size);
4859    
4860     if (str != NULL)
4861     {
4862     pointer s;
4863    
4864     memcpy (str, p->rep.string.start, size - 1);
4865     str[size - 1] = '\0';
4866     s = mk_string (SCHEME_A_ str);
4867     free (str);
4868     s_return (s);
4869     }
4870     }
4871    
4872     s_return (S_F);
4873     }
4874    
4875     # endif
4876    
4877     case OP_CLOSE_INPORT: /* close-input-port */
4878 root 1.16 port_close (SCHEME_A_ a, port_input);
4879 root 1.1 s_return (S_T);
4880    
4881     case OP_CLOSE_OUTPORT: /* close-output-port */
4882 root 1.16 port_close (SCHEME_A_ a, port_output);
4883 root 1.1 s_return (S_T);
4884     #endif
4885    
4886     case OP_INT_ENV: /* interaction-environment */
4887     s_return (SCHEME_V->global_env);
4888    
4889     case OP_CURR_ENV: /* current-environment */
4890     s_return (SCHEME_V->envir);
4891    
4892     }
4893    
4894 root 1.24 if (USE_ERROR_CHECKING) abort ();
4895 root 1.1 }
4896    
4897 root 1.20 static int
4898 root 1.1 opexe_5 (SCHEME_P_ enum scheme_opcodes op)
4899     {
4900 root 1.18 pointer args = SCHEME_V->args;
4901 root 1.1 pointer x;
4902    
4903     if (SCHEME_V->nesting != 0)
4904     {
4905     int n = SCHEME_V->nesting;
4906    
4907     SCHEME_V->nesting = 0;
4908     SCHEME_V->retcode = -1;
4909     Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
4910     }
4911    
4912     switch (op)
4913     {
4914     /* ========== reading part ========== */
4915     #if USE_PORTS
4916     case OP_READ:
4917 root 1.18 if (!is_pair (args))
4918 root 1.2 s_goto (OP_READ_INTERNAL);
4919 root 1.1
4920 root 1.18 if (!is_inport (car (args)))
4921     Error_1 ("read: not an input port:", car (args));
4922 root 1.1
4923 root 1.18 if (car (args) == SCHEME_V->inport)
4924 root 1.2 s_goto (OP_READ_INTERNAL);
4925 root 1.1
4926     x = SCHEME_V->inport;
4927 root 1.18 SCHEME_V->inport = car (args);
4928 root 1.1 x = cons (x, NIL);
4929     s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4930     s_goto (OP_READ_INTERNAL);
4931    
4932     case OP_READ_CHAR: /* read-char */
4933     case OP_PEEK_CHAR: /* peek-char */
4934     {
4935     int c;
4936    
4937 root 1.18 if (is_pair (args))
4938 root 1.1 {
4939 root 1.18 if (car (args) != SCHEME_V->inport)
4940 root 1.1 {
4941     x = SCHEME_V->inport;
4942     x = cons (x, NIL);
4943     s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4944 root 1.18 SCHEME_V->inport = car (args);
4945 root 1.1 }
4946     }
4947    
4948     c = inchar (SCHEME_A);
4949    
4950     if (c == EOF)
4951     s_return (S_EOF);
4952    
4953     if (SCHEME_V->op == OP_PEEK_CHAR)
4954     backchar (SCHEME_A_ c);
4955    
4956     s_return (mk_character (SCHEME_A_ c));
4957     }
4958    
4959     case OP_CHAR_READY: /* char-ready? */
4960     {
4961     pointer p = SCHEME_V->inport;
4962     int res;
4963    
4964 root 1.18 if (is_pair (args))
4965     p = car (args);
4966 root 1.1
4967     res = p->object.port->kind & port_string;
4968    
4969     s_retbool (res);
4970     }
4971    
4972     case OP_SET_INPORT: /* set-input-port */
4973 root 1.18 SCHEME_V->inport = car (args);
4974 root 1.1 s_return (SCHEME_V->value);
4975    
4976     case OP_SET_OUTPORT: /* set-output-port */
4977 root 1.18 SCHEME_V->outport = car (args);
4978 root 1.1 s_return (SCHEME_V->value);
4979     #endif
4980    
4981     case OP_RDSEXPR:
4982     switch (SCHEME_V->tok)
4983     {
4984     case TOK_EOF:
4985     s_return (S_EOF);
4986     /* NOTREACHED */
4987    
4988     case TOK_VEC:
4989     s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
4990 root 1.2 /* fall through */
4991 root 1.1
4992     case TOK_LPAREN:
4993     SCHEME_V->tok = token (SCHEME_A);
4994    
4995     if (SCHEME_V->tok == TOK_RPAREN)
4996     s_return (NIL);
4997     else if (SCHEME_V->tok == TOK_DOT)
4998     Error_0 ("syntax error: illegal dot expression");
4999     else
5000     {
5001     SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
5002     s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
5003     s_goto (OP_RDSEXPR);
5004     }
5005    
5006     case TOK_QUOTE:
5007     s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
5008     SCHEME_V->tok = token (SCHEME_A);
5009     s_goto (OP_RDSEXPR);
5010    
5011     case TOK_BQUOTE:
5012     SCHEME_V->tok = token (SCHEME_A);
5013    
5014     if (SCHEME_V->tok == TOK_VEC)
5015     {
5016     s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
5017     SCHEME_V->tok = TOK_LPAREN;
5018     s_goto (OP_RDSEXPR);
5019     }
5020     else
5021 root 1.2 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
5022 root 1.1
5023     s_goto (OP_RDSEXPR);
5024    
5025     case TOK_COMMA:
5026     s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
5027     SCHEME_V->tok = token (SCHEME_A);
5028     s_goto (OP_RDSEXPR);
5029    
5030     case TOK_ATMARK:
5031     s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
5032     SCHEME_V->tok = token (SCHEME_A);
5033     s_goto (OP_RDSEXPR);
5034    
5035     case TOK_ATOM:
5036 root 1.35 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS)));
5037    
5038     case TOK_DOTATOM:
5039     SCHEME_V->strbuff[0] = '.';
5040     s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ 1, DELIMITERS)));
5041 root 1.1
5042 root 1.36 case TOK_STRATOM:
5043     x = readstrexp (SCHEME_A_ '|');
5044     //TODO: haven't checked whether the garbage collector could interfere
5045     s_return (mk_atom (SCHEME_A_ strvalue (x)));
5046    
5047 root 1.1 case TOK_DQUOTE:
5048 root 1.35 x = readstrexp (SCHEME_A_ '"');
5049 root 1.1
5050     if (x == S_F)
5051     Error_0 ("Error reading string");
5052    
5053     setimmutable (x);
5054     s_return (x);
5055    
5056     case TOK_SHARP:
5057     {
5058     pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
5059    
5060     if (f == NIL)
5061     Error_0 ("undefined sharp expression");
5062     else
5063     {
5064     SCHEME_V->code = cons (slot_value_in_env (f), NIL);
5065     s_goto (OP_EVAL);
5066     }
5067     }
5068    
5069     case TOK_SHARP_CONST:
5070 root 1.35 if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS))) == NIL)
5071 root 1.1 Error_0 ("undefined sharp expression");
5072     else
5073     s_return (x);
5074    
5075     default:
5076     Error_0 ("syntax error: illegal token");
5077     }
5078    
5079     break;
5080    
5081     case OP_RDLIST:
5082 root 1.18 SCHEME_V->args = cons (SCHEME_V->value, args);
5083 root 1.2 SCHEME_V->tok = token (SCHEME_A);
5084 root 1.1
5085 root 1.2 switch (SCHEME_V->tok)
5086     {
5087     case TOK_EOF:
5088     s_return (S_EOF);
5089 root 1.1
5090 root 1.2 case TOK_RPAREN:
5091     {
5092     int c = inchar (SCHEME_A);
5093 root 1.1
5094 root 1.2 if (c != '\n')
5095     backchar (SCHEME_A_ c);
5096 root 1.1 #if SHOW_ERROR_LINE
5097 root 1.2 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5098     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5099     #endif
5100 root 1.1
5101 root 1.2 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5102     s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5103     }
5104    
5105     case TOK_DOT:
5106 root 1.1 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5107     SCHEME_V->tok = token (SCHEME_A);
5108     s_goto (OP_RDSEXPR);
5109 root 1.2
5110     default:
5111     s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5112 root 1.1 s_goto (OP_RDSEXPR);
5113 root 1.2 }
5114 root 1.1
5115     case OP_RDDOT:
5116     if (token (SCHEME_A) != TOK_RPAREN)
5117     Error_0 ("syntax error: illegal dot expression");
5118 root 1.2
5119     SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5120 root 1.18 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5121 root 1.1
5122     case OP_RDQUOTE:
5123     s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5124    
5125     case OP_RDQQUOTE:
5126     s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5127    
5128     case OP_RDQQUOTEVEC:
5129     s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5130     cons (mk_symbol (SCHEME_A_ "vector"),
5131     cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5132    
5133     case OP_RDUNQUOTE:
5134     s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5135    
5136     case OP_RDUQTSP:
5137     s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5138    
5139     case OP_RDVEC:
5140     /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5141     s_goto(OP_EVAL); Cannot be quoted */
5142     /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5143     s_return(x); Cannot be part of pairs */
5144     /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5145     SCHEME_V->args=SCHEME_V->value;
5146     s_goto(OP_APPLY); */
5147     SCHEME_V->args = SCHEME_V->value;
5148     s_goto (OP_VECTOR);
5149    
5150     /* ========== printing part ========== */
5151     case OP_P0LIST:
5152 root 1.18 if (is_vector (args))
5153 root 1.1 {
5154     putstr (SCHEME_A_ "#(");
5155 root 1.18 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5156 root 1.1 s_goto (OP_PVECFROM);
5157     }
5158 root 1.18 else if (is_environment (args))
5159 root 1.1 {
5160     putstr (SCHEME_A_ "#<ENVIRONMENT>");
5161     s_return (S_T);
5162     }
5163 root 1.18 else if (!is_pair (args))
5164 root 1.1 {
5165 root 1.18 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5166 root 1.1 s_return (S_T);
5167     }
5168     else
5169     {
5170 root 1.18 pointer a = car (args);
5171     pointer b = cdr (args);
5172     int ok_abbr = ok_abbrev (b);
5173     SCHEME_V->args = car (b);
5174    
5175     if (a == SCHEME_V->QUOTE && ok_abbr)
5176     putstr (SCHEME_A_ "'");
5177     else if (a == SCHEME_V->QQUOTE && ok_abbr)
5178     putstr (SCHEME_A_ "`");
5179     else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5180     putstr (SCHEME_A_ ",");
5181     else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5182     putstr (SCHEME_A_ ",@");
5183     else
5184     {
5185     putstr (SCHEME_A_ "(");
5186     s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5187     SCHEME_V->args = a;
5188     }
5189    
5190 root 1.1 s_goto (OP_P0LIST);
5191     }
5192    
5193     case OP_P1LIST:
5194 root 1.18 if (is_pair (args))
5195 root 1.1 {
5196 root 1.18 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5197 root 1.1 putstr (SCHEME_A_ " ");
5198 root 1.18 SCHEME_V->args = car (args);
5199 root 1.1 s_goto (OP_P0LIST);
5200     }
5201 root 1.18 else if (is_vector (args))
5202 root 1.1 {
5203     s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5204     putstr (SCHEME_A_ " . ");
5205     s_goto (OP_P0LIST);
5206     }
5207     else
5208     {
5209 root 1.18 if (args != NIL)
5210 root 1.1 {
5211     putstr (SCHEME_A_ " . ");
5212 root 1.18 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5213 root 1.1 }
5214    
5215     putstr (SCHEME_A_ ")");
5216     s_return (S_T);
5217     }
5218    
5219     case OP_PVECFROM:
5220     {
5221 root 1.18 int i = ivalue_unchecked (cdr (args));
5222     pointer vec = car (args);
5223 root 1.7 int len = veclength (vec);
5224 root 1.1
5225     if (i == len)
5226     {
5227     putstr (SCHEME_A_ ")");
5228     s_return (S_T);
5229     }
5230     else
5231     {
5232 root 1.28 pointer elem = vector_get (vec, i);
5233 root 1.1
5234 root 1.18 ivalue_unchecked (cdr (args)) = i + 1;
5235     s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5236 root 1.1 SCHEME_V->args = elem;
5237    
5238     if (i > 0)
5239     putstr (SCHEME_A_ " ");
5240    
5241     s_goto (OP_P0LIST);
5242     }
5243     }
5244     }
5245    
5246 root 1.24 if (USE_ERROR_CHECKING) abort ();
5247 root 1.1 }
5248    
5249 root 1.20 static int
5250 root 1.1 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5251     {
5252 root 1.18 pointer args = SCHEME_V->args;
5253     pointer a = car (args);
5254 root 1.1 pointer x, y;
5255    
5256     switch (op)
5257     {
5258     case OP_LIST_LENGTH: /* length *//* a.k */
5259     {
5260 root 1.18 long v = list_length (SCHEME_A_ a);
5261 root 1.1
5262     if (v < 0)
5263 root 1.18 Error_1 ("length: not a list:", a);
5264 root 1.1
5265     s_return (mk_integer (SCHEME_A_ v));
5266     }
5267    
5268     case OP_ASSQ: /* assq *//* a.k */
5269 root 1.18 x = a;
5270 root 1.1
5271 root 1.18 for (y = cadr (args); is_pair (y); y = cdr (y))
5272 root 1.1 {
5273     if (!is_pair (car (y)))
5274     Error_0 ("unable to handle non pair element");
5275    
5276     if (x == caar (y))
5277     break;
5278     }
5279    
5280     if (is_pair (y))
5281     s_return (car (y));
5282     else
5283     s_return (S_F);
5284    
5285    
5286     case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5287 root 1.18 SCHEME_V->args = a;
5288 root 1.1
5289     if (SCHEME_V->args == NIL)
5290     s_return (S_F);
5291     else if (is_closure (SCHEME_V->args))
5292     s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5293     else if (is_macro (SCHEME_V->args))
5294     s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5295     else
5296     s_return (S_F);
5297    
5298     case OP_CLOSUREP: /* closure? */
5299     /*
5300     * Note, macro object is also a closure.
5301     * Therefore, (closure? <#MACRO>) ==> #t
5302 root 1.38 * (schmorp) well, obviously not, fix? TODO
5303 root 1.1 */
5304 root 1.18 s_retbool (is_closure (a));
5305 root 1.1
5306     case OP_MACROP: /* macro? */
5307 root 1.18 s_retbool (is_macro (a));
5308 root 1.1 }
5309    
5310 root 1.24 if (USE_ERROR_CHECKING) abort ();
5311 root 1.1 }
5312    
5313 root 1.20 /* dispatch functions (opexe_x) return new opcode, or 0 for same opcode, or -1 to stop */
5314     typedef int (*dispatch_func)(SCHEME_P_ enum scheme_opcodes);
5315 root 1.1
5316 root 1.19 typedef int (*test_predicate)(pointer);
5317 root 1.1 static int
5318 root 1.26 tst_any (pointer p)
5319 root 1.1 {
5320     return 1;
5321     }
5322    
5323     static int
5324 root 1.26 tst_inonneg (pointer p)
5325 root 1.1 {
5326 root 1.26 return is_integer (p) && ivalue_unchecked (p) >= 0;
5327 root 1.1 }
5328    
5329 root 1.19 static int
5330 root 1.26 tst_is_list (SCHEME_P_ pointer p)
5331 root 1.19 {
5332     return p == NIL || is_pair (p);
5333     }
5334    
5335 root 1.1 /* Correspond carefully with following defines! */
5336     static struct
5337     {
5338     test_predicate fct;
5339     const char *kind;
5340 root 1.26 } tests[] = {
5341     { tst_any , 0 },
5342     { is_string , "string" },
5343     { is_symbol , "symbol" },
5344     { is_port , "port" },
5345     { is_inport , "input port" },
5346     { is_outport , "output port" },
5347 root 1.19 { is_environment, "environment" },
5348 root 1.26 { is_pair , "pair" },
5349     { 0 , "pair or '()" },
5350     { is_character , "character" },
5351     { is_vector , "vector" },
5352     { is_number , "number" },
5353     { is_integer , "integer" },
5354     { tst_inonneg , "non-negative integer" }
5355 root 1.1 };
5356    
5357 root 1.20 #define TST_NONE 0 /* TST_NONE used for built-ins, 0 for internal ops */
5358 root 1.18 #define TST_ANY "\001"
5359     #define TST_STRING "\002"
5360     #define TST_SYMBOL "\003"
5361     #define TST_PORT "\004"
5362     #define TST_INPORT "\005"
5363     #define TST_OUTPORT "\006"
5364 root 1.1 #define TST_ENVIRONMENT "\007"
5365 root 1.18 #define TST_PAIR "\010"
5366     #define TST_LIST "\011"
5367     #define TST_CHAR "\012"
5368     #define TST_VECTOR "\013"
5369     #define TST_NUMBER "\014"
5370     #define TST_INTEGER "\015"
5371     #define TST_NATURAL "\016"
5372 root 1.1
5373 root 1.20 #define INF_ARG 0xff
5374     #define UNNAMED_OP ""
5375    
5376     static const char opnames[] =
5377     #define OP_DEF(func,name,minarity,maxarity,argtest,op) name "\x00"
5378     #include "opdefines.h"
5379     #undef OP_DEF
5380     ;
5381    
5382     static const char *
5383     opname (int idx)
5384     {
5385     const char *name = opnames;
5386    
5387     /* should do this at compile time, but would require external program, right? */
5388     while (idx--)
5389     name += strlen (name) + 1;
5390    
5391     return *name ? name : "ILLEGAL";
5392     }
5393    
5394     static const char *
5395     procname (pointer x)
5396     {
5397     return opname (procnum (x));
5398     }
5399    
5400 root 1.1 typedef struct
5401     {
5402 root 1.20 uint8_t func;
5403     /*dispatch_func func;*//*TODO: maybe optionally keep the pointer, for speed? */
5404     uint8_t builtin;
5405 root 1.26 #if USE_ERROR_CHECKING
5406 root 1.20 uint8_t min_arity;
5407     uint8_t max_arity;
5408 root 1.18 char arg_tests_encoding[3];
5409 root 1.26 #endif
5410 root 1.1 } op_code_info;
5411    
5412 root 1.20 static const op_code_info dispatch_table[] = {
5413 root 1.26 #if USE_ERROR_CHECKING
5414 root 1.20 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1, minarity, maxarity, argtest },
5415 root 1.26 #else
5416     #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1 },
5417     #endif
5418 root 1.1 #include "opdefines.h"
5419 root 1.18 #undef OP_DEF
5420 root 1.1 {0}
5421     };
5422    
5423     /* kernel of this interpreter */
5424 root 1.23 static void ecb_hot
5425 root 1.1 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5426     {
5427     SCHEME_V->op = op;
5428    
5429     for (;;)
5430     {
5431 root 1.20 const op_code_info *pcd = dispatch_table + SCHEME_V->op;
5432 root 1.1
5433 root 1.4 #if USE_ERROR_CHECKING
5434 root 1.20 if (pcd->builtin) /* if built-in function, check arguments */
5435 root 1.1 {
5436     char msg[STRBUFFSIZE];
5437     int n = list_length (SCHEME_A_ SCHEME_V->args);
5438    
5439     /* Check number of arguments */
5440 root 1.10 if (ecb_expect_false (n < pcd->min_arity))
5441 root 1.1 {
5442     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5443 root 1.20 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5444 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5445     continue;
5446 root 1.1 }
5447 root 1.20 else if (ecb_expect_false (n > pcd->max_arity && pcd->max_arity != INF_ARG))
5448 root 1.1 {
5449     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5450 root 1.20 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5451 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5452     continue;
5453 root 1.1 }
5454 root 1.20 else
5455 root 1.1 {
5456 root 1.20 if (*pcd->arg_tests_encoding) /* literal 0 and TST_NONE treated the same */
5457 root 1.1 {
5458     int i = 0;
5459     int j;
5460     const char *t = pcd->arg_tests_encoding;
5461     pointer arglist = SCHEME_V->args;
5462    
5463     do
5464     {
5465     pointer arg = car (arglist);
5466    
5467 root 1.18 j = t[0];
5468 root 1.1
5469 root 1.26 /*TODO: tst_is_list has different prototype - fix if other tests acquire same prototype */
5470     if (j == TST_LIST[0])
5471     {
5472     if (!tst_is_list (SCHEME_A_ arg))
5473     break;
5474     }
5475     else
5476     {
5477     if (!tests[j - 1].fct (arg))
5478     break;
5479     }
5480 root 1.1
5481 root 1.28 if (t < pcd->arg_tests_encoding + sizeof (pcd->arg_tests_encoding) - 1 && t[1]) /* last test is replicated as necessary */
5482 root 1.2 t++;
5483 root 1.1
5484     arglist = cdr (arglist);
5485     i++;
5486     }
5487     while (i < n);
5488    
5489     if (i < n)
5490     {
5491 root 1.20 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", opname (SCHEME_V->op), i + 1, tests[j].kind);
5492 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5493     continue;
5494 root 1.1 }
5495     }
5496     }
5497     }
5498 root 1.4 #endif
5499 root 1.1
5500     ok_to_freely_gc (SCHEME_A);
5501    
5502 root 1.20 static const dispatch_func dispatch_funcs[] = {
5503     opexe_0,
5504     opexe_1,
5505     opexe_2,
5506     opexe_3,
5507     opexe_4,
5508     opexe_5,
5509     opexe_6,
5510     };
5511    
5512     if (ecb_expect_false (dispatch_funcs [pcd->func] (SCHEME_A_ SCHEME_V->op) != 0))
5513 root 1.1 return;
5514    
5515 root 1.5 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5516 root 1.1 {
5517     xwrstr ("No memory!\n");
5518     return;
5519     }
5520     }
5521     }
5522    
5523     /* ========== Initialization of internal keywords ========== */
5524    
5525     static void
5526 root 1.2 assign_syntax (SCHEME_P_ const char *name)
5527 root 1.1 {
5528     pointer x = oblist_add_by_name (SCHEME_A_ name);
5529     set_typeflag (x, typeflag (x) | T_SYNTAX);
5530     }
5531    
5532     static void
5533 root 1.2 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5534 root 1.1 {
5535     pointer x = mk_symbol (SCHEME_A_ name);
5536     pointer y = mk_proc (SCHEME_A_ op);
5537     new_slot_in_env (SCHEME_A_ x, y);
5538     }
5539    
5540     static pointer
5541     mk_proc (SCHEME_P_ enum scheme_opcodes op)
5542     {
5543     pointer y = get_cell (SCHEME_A_ NIL, NIL);
5544     set_typeflag (y, (T_PROC | T_ATOM));
5545 root 1.2 ivalue_unchecked (y) = op;
5546 root 1.1 return y;
5547     }
5548    
5549     /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5550     static int
5551     syntaxnum (pointer p)
5552     {
5553 root 1.38 const char *s = strvalue (p);
5554 root 1.1
5555 root 1.38 switch (strlength (p))
5556 root 1.1 {
5557     case 2:
5558     if (s[0] == 'i')
5559     return OP_IF0; /* if */
5560     else
5561     return OP_OR0; /* or */
5562    
5563     case 3:
5564     if (s[0] == 'a')
5565     return OP_AND0; /* and */
5566     else
5567     return OP_LET0; /* let */
5568    
5569     case 4:
5570     switch (s[3])
5571     {
5572     case 'e':
5573     return OP_CASE0; /* case */
5574    
5575     case 'd':
5576     return OP_COND0; /* cond */
5577    
5578     case '*':
5579 root 1.10 return OP_LET0AST;/* let* */
5580 root 1.1
5581     default:
5582     return OP_SET0; /* set! */
5583     }
5584    
5585     case 5:
5586     switch (s[2])
5587     {
5588     case 'g':
5589     return OP_BEGIN; /* begin */
5590    
5591     case 'l':
5592     return OP_DELAY; /* delay */
5593    
5594     case 'c':
5595     return OP_MACRO0; /* macro */
5596    
5597     default:
5598     return OP_QUOTE; /* quote */
5599     }
5600    
5601     case 6:
5602     switch (s[2])
5603     {
5604     case 'm':
5605     return OP_LAMBDA; /* lambda */
5606    
5607     case 'f':
5608     return OP_DEF0; /* define */
5609    
5610     default:
5611 root 1.10 return OP_LET0REC;/* letrec */
5612 root 1.1 }
5613    
5614     default:
5615     return OP_C0STREAM; /* cons-stream */
5616     }
5617     }
5618    
5619     #if USE_MULTIPLICITY
5620 root 1.23 ecb_cold scheme *
5621 root 1.1 scheme_init_new ()
5622     {
5623     scheme *sc = malloc (sizeof (scheme));
5624    
5625     if (!scheme_init (SCHEME_A))
5626     {
5627     free (SCHEME_A);
5628     return 0;
5629     }
5630     else
5631     return sc;
5632     }
5633     #endif
5634    
5635 root 1.23 ecb_cold int
5636 root 1.1 scheme_init (SCHEME_P)
5637     {
5638     int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5639     pointer x;
5640    
5641     num_set_fixnum (num_zero, 1);
5642     num_set_ivalue (num_zero, 0);
5643     num_set_fixnum (num_one, 1);
5644     num_set_ivalue (num_one, 1);
5645    
5646     #if USE_INTERFACE
5647     SCHEME_V->vptr = &vtbl;
5648     #endif
5649     SCHEME_V->gensym_cnt = 0;
5650     SCHEME_V->last_cell_seg = -1;
5651     SCHEME_V->free_cell = NIL;
5652     SCHEME_V->fcells = 0;
5653     SCHEME_V->no_memory = 0;
5654     SCHEME_V->inport = NIL;
5655     SCHEME_V->outport = NIL;
5656     SCHEME_V->save_inport = NIL;
5657     SCHEME_V->loadport = NIL;
5658     SCHEME_V->nesting = 0;
5659     SCHEME_V->interactive_repl = 0;
5660    
5661     if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5662     {
5663     #if USE_ERROR_CHECKING
5664     SCHEME_V->no_memory = 1;
5665     return 0;
5666     #endif
5667     }
5668    
5669     SCHEME_V->gc_verbose = 0;
5670     dump_stack_initialize (SCHEME_A);
5671     SCHEME_V->code = NIL;
5672 root 1.2 SCHEME_V->args = NIL;
5673     SCHEME_V->envir = NIL;
5674 root 1.1 SCHEME_V->tracing = 0;
5675    
5676     /* init NIL */
5677 root 1.2 set_typeflag (NIL, T_ATOM | T_MARK);
5678 root 1.1 set_car (NIL, NIL);
5679     set_cdr (NIL, NIL);
5680     /* init T */
5681 root 1.2 set_typeflag (S_T, T_ATOM | T_MARK);
5682 root 1.1 set_car (S_T, S_T);
5683     set_cdr (S_T, S_T);
5684     /* init F */
5685 root 1.2 set_typeflag (S_F, T_ATOM | T_MARK);
5686 root 1.1 set_car (S_F, S_F);
5687     set_cdr (S_F, S_F);
5688 root 1.7 /* init EOF_OBJ */
5689     set_typeflag (S_EOF, T_ATOM | T_MARK);
5690     set_car (S_EOF, S_EOF);
5691     set_cdr (S_EOF, S_EOF);
5692 root 1.1 /* init sink */
5693 root 1.2 set_typeflag (S_SINK, T_PAIR | T_MARK);
5694 root 1.1 set_car (S_SINK, NIL);
5695 root 1.7
5696 root 1.1 /* init c_nest */
5697     SCHEME_V->c_nest = NIL;
5698    
5699     SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5700     /* init global_env */
5701     new_frame_in_env (SCHEME_A_ NIL);
5702     SCHEME_V->global_env = SCHEME_V->envir;
5703     /* init else */
5704     x = mk_symbol (SCHEME_A_ "else");
5705     new_slot_in_env (SCHEME_A_ x, S_T);
5706    
5707 root 1.2 {
5708     static const char *syntax_names[] = {
5709     "lambda", "quote", "define", "if", "begin", "set!",
5710     "let", "let*", "letrec", "cond", "delay", "and",
5711     "or", "cons-stream", "macro", "case"
5712     };
5713    
5714     for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5715     assign_syntax (SCHEME_A_ syntax_names[i]);
5716     }
5717 root 1.1
5718 root 1.20 // TODO: should iterate via strlen, to avoid n² complexity
5719 root 1.1 for (i = 0; i < n; i++)
5720 root 1.20 if (dispatch_table[i].builtin)
5721     assign_proc (SCHEME_A_ i, opname (i));
5722 root 1.1
5723     /* initialization of global pointers to special symbols */
5724 root 1.6 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5725     SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5726     SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5727     SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5728     SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5729     SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5730     SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5731     SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5732     SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5733 root 1.1 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5734    
5735     return !SCHEME_V->no_memory;
5736     }
5737    
5738     #if USE_PORTS
5739     void
5740     scheme_set_input_port_file (SCHEME_P_ int fin)
5741     {
5742     SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5743     }
5744    
5745     void
5746     scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5747     {
5748     SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5749     }
5750    
5751     void
5752     scheme_set_output_port_file (SCHEME_P_ int fout)
5753     {
5754     SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5755     }
5756    
5757     void
5758     scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5759     {
5760     SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5761     }
5762     #endif
5763    
5764     void
5765     scheme_set_external_data (SCHEME_P_ void *p)
5766     {
5767     SCHEME_V->ext_data = p;
5768     }
5769    
5770 root 1.23 ecb_cold void
5771 root 1.1 scheme_deinit (SCHEME_P)
5772     {
5773     int i;
5774    
5775     #if SHOW_ERROR_LINE
5776     char *fname;
5777     #endif
5778    
5779     SCHEME_V->oblist = NIL;
5780     SCHEME_V->global_env = NIL;
5781     dump_stack_free (SCHEME_A);
5782     SCHEME_V->envir = NIL;
5783     SCHEME_V->code = NIL;
5784     SCHEME_V->args = NIL;
5785     SCHEME_V->value = NIL;
5786    
5787     if (is_port (SCHEME_V->inport))
5788     set_typeflag (SCHEME_V->inport, T_ATOM);
5789    
5790     SCHEME_V->inport = NIL;
5791     SCHEME_V->outport = NIL;
5792    
5793     if (is_port (SCHEME_V->save_inport))
5794     set_typeflag (SCHEME_V->save_inport, T_ATOM);
5795    
5796     SCHEME_V->save_inport = NIL;
5797    
5798     if (is_port (SCHEME_V->loadport))
5799     set_typeflag (SCHEME_V->loadport, T_ATOM);
5800    
5801     SCHEME_V->loadport = NIL;
5802     SCHEME_V->gc_verbose = 0;
5803     gc (SCHEME_A_ NIL, NIL);
5804    
5805     for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5806     free (SCHEME_V->alloc_seg[i]);
5807    
5808     #if SHOW_ERROR_LINE
5809     for (i = 0; i <= SCHEME_V->file_i; i++)
5810     {
5811     if (SCHEME_V->load_stack[i].kind & port_file)
5812     {
5813     fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5814    
5815     if (fname)
5816     free (fname);
5817     }
5818     }
5819     #endif
5820     }
5821    
5822     void
5823     scheme_load_file (SCHEME_P_ int fin)
5824     {
5825     scheme_load_named_file (SCHEME_A_ fin, 0);
5826     }
5827    
5828     void
5829     scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5830     {
5831     dump_stack_reset (SCHEME_A);
5832     SCHEME_V->envir = SCHEME_V->global_env;
5833     SCHEME_V->file_i = 0;
5834     SCHEME_V->load_stack[0].unget = -1;
5835     SCHEME_V->load_stack[0].kind = port_input | port_file;
5836     SCHEME_V->load_stack[0].rep.stdio.file = fin;
5837     #if USE_PORTS
5838     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5839     #endif
5840     SCHEME_V->retcode = 0;
5841    
5842     #if USE_PORTS
5843     if (fin == STDIN_FILENO)
5844     SCHEME_V->interactive_repl = 1;
5845     #endif
5846    
5847     #if USE_PORTS
5848     #if SHOW_ERROR_LINE
5849     SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5850    
5851     if (fin != STDIN_FILENO && filename)
5852     SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5853     #endif
5854     #endif
5855    
5856     SCHEME_V->inport = SCHEME_V->loadport;
5857     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5858     Eval_Cycle (SCHEME_A_ OP_T0LVL);
5859     set_typeflag (SCHEME_V->loadport, T_ATOM);
5860    
5861     if (SCHEME_V->retcode == 0)
5862     SCHEME_V->retcode = SCHEME_V->nesting != 0;
5863     }
5864    
5865     void
5866     scheme_load_string (SCHEME_P_ const char *cmd)
5867     {
5868     dump_stack_reset (SCHEME_A);
5869     SCHEME_V->envir = SCHEME_V->global_env;
5870     SCHEME_V->file_i = 0;
5871     SCHEME_V->load_stack[0].kind = port_input | port_string;
5872 root 1.17 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
5873     SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
5874     SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
5875 root 1.1 #if USE_PORTS
5876     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5877     #endif
5878     SCHEME_V->retcode = 0;
5879     SCHEME_V->interactive_repl = 0;
5880     SCHEME_V->inport = SCHEME_V->loadport;
5881     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5882     Eval_Cycle (SCHEME_A_ OP_T0LVL);
5883     set_typeflag (SCHEME_V->loadport, T_ATOM);
5884    
5885     if (SCHEME_V->retcode == 0)
5886     SCHEME_V->retcode = SCHEME_V->nesting != 0;
5887     }
5888    
5889     void
5890     scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
5891     {
5892     pointer x;
5893    
5894     x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
5895    
5896     if (x != NIL)
5897 root 1.2 set_slot_in_env (SCHEME_A_ x, value);
5898 root 1.1 else
5899 root 1.2 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
5900 root 1.1 }
5901    
5902     #if !STANDALONE
5903 root 1.2
5904 root 1.1 void
5905     scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
5906     {
5907     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
5908     }
5909    
5910     void
5911     scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
5912     {
5913     int i;
5914    
5915     for (i = 0; i < count; i++)
5916 root 1.2 scheme_register_foreign_func (SCHEME_A_ list + i);
5917 root 1.1 }
5918    
5919     pointer
5920     scheme_apply0 (SCHEME_P_ const char *procname)
5921     {
5922     return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
5923     }
5924    
5925     void
5926     save_from_C_call (SCHEME_P)
5927     {
5928     pointer saved_data = cons (car (S_SINK),
5929     cons (SCHEME_V->envir,
5930     SCHEME_V->dump));
5931    
5932     /* Push */
5933     SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
5934     /* Truncate the dump stack so TS will return here when done, not
5935     directly resume pre-C-call operations. */
5936     dump_stack_reset (SCHEME_A);
5937     }
5938    
5939     void
5940     restore_from_C_call (SCHEME_P)
5941     {
5942     set_car (S_SINK, caar (SCHEME_V->c_nest));
5943     SCHEME_V->envir = cadar (SCHEME_V->c_nest);
5944     SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
5945     /* Pop */
5946     SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
5947     }
5948    
5949     /* "func" and "args" are assumed to be already eval'ed. */
5950     pointer
5951     scheme_call (SCHEME_P_ pointer func, pointer args)
5952     {
5953     int old_repl = SCHEME_V->interactive_repl;
5954    
5955     SCHEME_V->interactive_repl = 0;
5956     save_from_C_call (SCHEME_A);
5957     SCHEME_V->envir = SCHEME_V->global_env;
5958     SCHEME_V->args = args;
5959     SCHEME_V->code = func;
5960     SCHEME_V->retcode = 0;
5961     Eval_Cycle (SCHEME_A_ OP_APPLY);
5962     SCHEME_V->interactive_repl = old_repl;
5963     restore_from_C_call (SCHEME_A);
5964     return SCHEME_V->value;
5965     }
5966    
5967     pointer
5968     scheme_eval (SCHEME_P_ pointer obj)
5969     {
5970     int old_repl = SCHEME_V->interactive_repl;
5971    
5972     SCHEME_V->interactive_repl = 0;
5973     save_from_C_call (SCHEME_A);
5974     SCHEME_V->args = NIL;
5975     SCHEME_V->code = obj;
5976     SCHEME_V->retcode = 0;
5977     Eval_Cycle (SCHEME_A_ OP_EVAL);
5978     SCHEME_V->interactive_repl = old_repl;
5979     restore_from_C_call (SCHEME_A);
5980     return SCHEME_V->value;
5981     }
5982    
5983     #endif
5984    
5985     /* ========== Main ========== */
5986    
5987     #if STANDALONE
5988    
5989     int
5990     main (int argc, char **argv)
5991     {
5992     # if USE_MULTIPLICITY
5993     scheme ssc;
5994 root 1.2 scheme *const SCHEME_V = &ssc;
5995 root 1.1 # else
5996     # endif
5997     int fin;
5998     char *file_name = InitFile;
5999     int retcode;
6000     int isfile = 1;
6001 root 1.38 system ("ps v $PPID");//D
6002 root 1.1
6003     if (argc == 2 && strcmp (argv[1], "-?") == 0)
6004     {
6005     xwrstr ("Usage: tinyscheme -?\n");
6006     xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
6007     xwrstr ("followed by\n");
6008     xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
6009     xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
6010     xwrstr ("assuming that the executable is named tinyscheme.\n");
6011     xwrstr ("Use - as filename for stdin.\n");
6012     return 1;
6013     }
6014    
6015     if (!scheme_init (SCHEME_A))
6016     {
6017     xwrstr ("Could not initialize!\n");
6018     return 2;
6019     }
6020    
6021     # if USE_PORTS
6022     scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
6023     scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
6024     # endif
6025    
6026     argv++;
6027    
6028     #if 0
6029     if (access (file_name, 0) != 0)
6030     {
6031     char *p = getenv ("TINYSCHEMEINIT");
6032    
6033     if (p != 0)
6034 root 1.2 file_name = p;
6035 root 1.1 }
6036     #endif
6037    
6038     do
6039     {
6040     #if USE_PORTS
6041     if (strcmp (file_name, "-") == 0)
6042     fin = STDIN_FILENO;
6043     else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
6044     {
6045     pointer args = NIL;
6046    
6047     isfile = file_name[1] == '1';
6048     file_name = *argv++;
6049    
6050     if (strcmp (file_name, "-") == 0)
6051     fin = STDIN_FILENO;
6052     else if (isfile)
6053     fin = open (file_name, O_RDONLY);
6054    
6055     for (; *argv; argv++)
6056     {
6057     pointer value = mk_string (SCHEME_A_ * argv);
6058    
6059     args = cons (value, args);
6060     }
6061    
6062     args = reverse_in_place (SCHEME_A_ NIL, args);
6063     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
6064    
6065     }
6066     else
6067     fin = open (file_name, O_RDONLY);
6068     #endif
6069    
6070     if (isfile && fin < 0)
6071     {
6072     xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
6073     }
6074     else
6075     {
6076     if (isfile)
6077     scheme_load_named_file (SCHEME_A_ fin, file_name);
6078     else
6079     scheme_load_string (SCHEME_A_ file_name);
6080    
6081     #if USE_PORTS
6082     if (!isfile || fin != STDIN_FILENO)
6083     {
6084     if (SCHEME_V->retcode != 0)
6085     {
6086     xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
6087     }
6088    
6089     if (isfile)
6090     close (fin);
6091     }
6092     #endif
6093     }
6094    
6095     file_name = *argv++;
6096     }
6097     while (file_name != 0);
6098    
6099     if (argc == 1)
6100     scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6101    
6102     retcode = SCHEME_V->retcode;
6103     scheme_deinit (SCHEME_A);
6104    
6105     return retcode;
6106     }
6107    
6108     #endif
6109    
6110     /*
6111     Local variables:
6112     c-file-style: "k&r"
6113     End:
6114     */