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