ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.40
Committed: Mon Nov 30 05:19:01 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.39: +6 -8 lines
Log Message:
*** empty log message ***

File Contents

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