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