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