ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/microscheme/scheme.c
Revision: 1.39
Committed: Sun Nov 29 14:22:30 2015 UTC (8 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.38: +66 -6 lines
Log Message:
*** empty log message ***

File Contents

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