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