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