ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.26
Committed: Sat Nov 28 05:12:53 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.25: +256 -244 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.26 exit(0);//D
4715 root 1.20 return -1;
4716 root 1.1
4717     case OP_GC: /* gc */
4718     gc (SCHEME_A_ NIL, NIL);
4719     s_return (S_T);
4720    
4721     case OP_GCVERB: /* gc-verbose */
4722     {
4723     int was = SCHEME_V->gc_verbose;
4724    
4725 root 1.16 SCHEME_V->gc_verbose = (a != S_F);
4726 root 1.1 s_retbool (was);
4727     }
4728    
4729     case OP_NEWSEGMENT: /* new-segment */
4730 root 1.16 if (!is_pair (args) || !is_number (a))
4731 root 1.1 Error_0 ("new-segment: argument must be a number");
4732    
4733 root 1.26 alloc_cellseg (SCHEME_A_ ivalue (a));
4734 root 1.1
4735     s_return (S_T);
4736    
4737     case OP_OBLIST: /* oblist */
4738     s_return (oblist_all_symbols (SCHEME_A));
4739    
4740     #if USE_PORTS
4741    
4742     case OP_CURR_INPORT: /* current-input-port */
4743     s_return (SCHEME_V->inport);
4744    
4745     case OP_CURR_OUTPORT: /* current-output-port */
4746     s_return (SCHEME_V->outport);
4747    
4748     case OP_OPEN_INFILE: /* open-input-file */
4749     case OP_OPEN_OUTFILE: /* open-output-file */
4750     case OP_OPEN_INOUTFILE: /* open-input-output-file */
4751     {
4752     int prop = 0;
4753     pointer p;
4754    
4755     switch (op)
4756     {
4757     case OP_OPEN_INFILE:
4758     prop = port_input;
4759     break;
4760    
4761     case OP_OPEN_OUTFILE:
4762     prop = port_output;
4763     break;
4764    
4765     case OP_OPEN_INOUTFILE:
4766     prop = port_input | port_output;
4767     break;
4768     }
4769    
4770 root 1.16 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
4771 root 1.1
4772 root 1.23 s_return (p == NIL ? S_F : p);
4773 root 1.1 }
4774    
4775     # if USE_STRING_PORTS
4776    
4777     case OP_OPEN_INSTRING: /* open-input-string */
4778     case OP_OPEN_INOUTSTRING: /* open-input-output-string */
4779     {
4780     int prop = 0;
4781     pointer p;
4782    
4783     switch (op)
4784     {
4785     case OP_OPEN_INSTRING:
4786     prop = port_input;
4787     break;
4788    
4789     case OP_OPEN_INOUTSTRING:
4790     prop = port_input | port_output;
4791     break;
4792     }
4793    
4794 root 1.16 p = port_from_string (SCHEME_A_ strvalue (a),
4795     strvalue (a) + strlength (a), prop);
4796 root 1.1
4797 root 1.23 s_return (p == NIL ? S_F : p);
4798 root 1.1 }
4799    
4800     case OP_OPEN_OUTSTRING: /* open-output-string */
4801     {
4802     pointer p;
4803    
4804 root 1.16 if (a == NIL)
4805 root 1.23 p = port_from_scratch (SCHEME_A);
4806 root 1.1 else
4807 root 1.23 p = port_from_string (SCHEME_A_ strvalue (a),
4808     strvalue (a) + strlength (a), port_output);
4809 root 1.1
4810 root 1.23 s_return (p == NIL ? S_F : p);
4811 root 1.1 }
4812    
4813     case OP_GET_OUTSTRING: /* get-output-string */
4814     {
4815     port *p;
4816    
4817 root 1.16 if ((p = a->object.port)->kind & port_string)
4818 root 1.1 {
4819     off_t size;
4820     char *str;
4821    
4822     size = p->rep.string.curr - p->rep.string.start + 1;
4823     str = malloc (size);
4824    
4825     if (str != NULL)
4826     {
4827     pointer s;
4828    
4829     memcpy (str, p->rep.string.start, size - 1);
4830     str[size - 1] = '\0';
4831     s = mk_string (SCHEME_A_ str);
4832     free (str);
4833     s_return (s);
4834     }
4835     }
4836    
4837     s_return (S_F);
4838     }
4839    
4840     # endif
4841    
4842     case OP_CLOSE_INPORT: /* close-input-port */
4843 root 1.16 port_close (SCHEME_A_ a, port_input);
4844 root 1.1 s_return (S_T);
4845    
4846     case OP_CLOSE_OUTPORT: /* close-output-port */
4847 root 1.16 port_close (SCHEME_A_ a, port_output);
4848 root 1.1 s_return (S_T);
4849     #endif
4850    
4851     case OP_INT_ENV: /* interaction-environment */
4852     s_return (SCHEME_V->global_env);
4853    
4854     case OP_CURR_ENV: /* current-environment */
4855     s_return (SCHEME_V->envir);
4856    
4857     }
4858    
4859 root 1.24 if (USE_ERROR_CHECKING) abort ();
4860 root 1.1 }
4861    
4862 root 1.20 static int
4863 root 1.1 opexe_5 (SCHEME_P_ enum scheme_opcodes op)
4864     {
4865 root 1.18 pointer args = SCHEME_V->args;
4866 root 1.1 pointer x;
4867    
4868     if (SCHEME_V->nesting != 0)
4869     {
4870     int n = SCHEME_V->nesting;
4871    
4872     SCHEME_V->nesting = 0;
4873     SCHEME_V->retcode = -1;
4874     Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
4875     }
4876    
4877     switch (op)
4878     {
4879     /* ========== reading part ========== */
4880     #if USE_PORTS
4881     case OP_READ:
4882 root 1.18 if (!is_pair (args))
4883 root 1.2 s_goto (OP_READ_INTERNAL);
4884 root 1.1
4885 root 1.18 if (!is_inport (car (args)))
4886     Error_1 ("read: not an input port:", car (args));
4887 root 1.1
4888 root 1.18 if (car (args) == SCHEME_V->inport)
4889 root 1.2 s_goto (OP_READ_INTERNAL);
4890 root 1.1
4891     x = SCHEME_V->inport;
4892 root 1.18 SCHEME_V->inport = car (args);
4893 root 1.1 x = cons (x, NIL);
4894     s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4895     s_goto (OP_READ_INTERNAL);
4896    
4897     case OP_READ_CHAR: /* read-char */
4898     case OP_PEEK_CHAR: /* peek-char */
4899     {
4900     int c;
4901    
4902 root 1.18 if (is_pair (args))
4903 root 1.1 {
4904 root 1.18 if (car (args) != SCHEME_V->inport)
4905 root 1.1 {
4906     x = SCHEME_V->inport;
4907     x = cons (x, NIL);
4908     s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4909 root 1.18 SCHEME_V->inport = car (args);
4910 root 1.1 }
4911     }
4912    
4913     c = inchar (SCHEME_A);
4914    
4915     if (c == EOF)
4916     s_return (S_EOF);
4917    
4918     if (SCHEME_V->op == OP_PEEK_CHAR)
4919     backchar (SCHEME_A_ c);
4920    
4921     s_return (mk_character (SCHEME_A_ c));
4922     }
4923    
4924     case OP_CHAR_READY: /* char-ready? */
4925     {
4926     pointer p = SCHEME_V->inport;
4927     int res;
4928    
4929 root 1.18 if (is_pair (args))
4930     p = car (args);
4931 root 1.1
4932     res = p->object.port->kind & port_string;
4933    
4934     s_retbool (res);
4935     }
4936    
4937     case OP_SET_INPORT: /* set-input-port */
4938 root 1.18 SCHEME_V->inport = car (args);
4939 root 1.1 s_return (SCHEME_V->value);
4940    
4941     case OP_SET_OUTPORT: /* set-output-port */
4942 root 1.18 SCHEME_V->outport = car (args);
4943 root 1.1 s_return (SCHEME_V->value);
4944     #endif
4945    
4946     case OP_RDSEXPR:
4947     switch (SCHEME_V->tok)
4948     {
4949     case TOK_EOF:
4950     s_return (S_EOF);
4951     /* NOTREACHED */
4952    
4953     case TOK_VEC:
4954     s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
4955 root 1.2 /* fall through */
4956 root 1.1
4957     case TOK_LPAREN:
4958     SCHEME_V->tok = token (SCHEME_A);
4959    
4960     if (SCHEME_V->tok == TOK_RPAREN)
4961     s_return (NIL);
4962     else if (SCHEME_V->tok == TOK_DOT)
4963     Error_0 ("syntax error: illegal dot expression");
4964     else
4965     {
4966     SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
4967     s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
4968     s_goto (OP_RDSEXPR);
4969     }
4970    
4971     case TOK_QUOTE:
4972     s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
4973     SCHEME_V->tok = token (SCHEME_A);
4974     s_goto (OP_RDSEXPR);
4975    
4976     case TOK_BQUOTE:
4977     SCHEME_V->tok = token (SCHEME_A);
4978    
4979     if (SCHEME_V->tok == TOK_VEC)
4980     {
4981     s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
4982     SCHEME_V->tok = TOK_LPAREN;
4983     s_goto (OP_RDSEXPR);
4984     }
4985     else
4986 root 1.2 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
4987 root 1.1
4988     s_goto (OP_RDSEXPR);
4989    
4990     case TOK_COMMA:
4991     s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
4992     SCHEME_V->tok = token (SCHEME_A);
4993     s_goto (OP_RDSEXPR);
4994    
4995     case TOK_ATMARK:
4996     s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
4997     SCHEME_V->tok = token (SCHEME_A);
4998     s_goto (OP_RDSEXPR);
4999    
5000     case TOK_ATOM:
5001     s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS)));
5002    
5003     case TOK_DQUOTE:
5004     x = readstrexp (SCHEME_A);
5005    
5006     if (x == S_F)
5007     Error_0 ("Error reading string");
5008    
5009     setimmutable (x);
5010     s_return (x);
5011    
5012     case TOK_SHARP:
5013     {
5014     pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
5015    
5016     if (f == NIL)
5017     Error_0 ("undefined sharp expression");
5018     else
5019     {
5020     SCHEME_V->code = cons (slot_value_in_env (f), NIL);
5021     s_goto (OP_EVAL);
5022     }
5023     }
5024    
5025     case TOK_SHARP_CONST:
5026     if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS))) == NIL)
5027     Error_0 ("undefined sharp expression");
5028     else
5029     s_return (x);
5030    
5031     default:
5032     Error_0 ("syntax error: illegal token");
5033     }
5034    
5035     break;
5036    
5037     case OP_RDLIST:
5038 root 1.18 SCHEME_V->args = cons (SCHEME_V->value, args);
5039 root 1.2 SCHEME_V->tok = token (SCHEME_A);
5040 root 1.1
5041 root 1.2 switch (SCHEME_V->tok)
5042     {
5043     case TOK_EOF:
5044     s_return (S_EOF);
5045 root 1.1
5046 root 1.2 case TOK_RPAREN:
5047     {
5048     int c = inchar (SCHEME_A);
5049 root 1.1
5050 root 1.2 if (c != '\n')
5051     backchar (SCHEME_A_ c);
5052 root 1.1 #if SHOW_ERROR_LINE
5053 root 1.2 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5054     SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5055     #endif
5056 root 1.1
5057 root 1.2 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5058     s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5059     }
5060    
5061     case TOK_DOT:
5062 root 1.1 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5063     SCHEME_V->tok = token (SCHEME_A);
5064     s_goto (OP_RDSEXPR);
5065 root 1.2
5066     default:
5067     s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5068 root 1.1 s_goto (OP_RDSEXPR);
5069 root 1.2 }
5070 root 1.1
5071     case OP_RDDOT:
5072     if (token (SCHEME_A) != TOK_RPAREN)
5073     Error_0 ("syntax error: illegal dot expression");
5074 root 1.2
5075     SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5076 root 1.18 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5077 root 1.1
5078     case OP_RDQUOTE:
5079     s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5080    
5081     case OP_RDQQUOTE:
5082     s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5083    
5084     case OP_RDQQUOTEVEC:
5085     s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5086     cons (mk_symbol (SCHEME_A_ "vector"),
5087     cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5088    
5089     case OP_RDUNQUOTE:
5090     s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5091    
5092     case OP_RDUQTSP:
5093     s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5094    
5095     case OP_RDVEC:
5096     /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5097     s_goto(OP_EVAL); Cannot be quoted */
5098     /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5099     s_return(x); Cannot be part of pairs */
5100     /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5101     SCHEME_V->args=SCHEME_V->value;
5102     s_goto(OP_APPLY); */
5103     SCHEME_V->args = SCHEME_V->value;
5104     s_goto (OP_VECTOR);
5105    
5106     /* ========== printing part ========== */
5107     case OP_P0LIST:
5108 root 1.18 if (is_vector (args))
5109 root 1.1 {
5110     putstr (SCHEME_A_ "#(");
5111 root 1.18 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5112 root 1.1 s_goto (OP_PVECFROM);
5113     }
5114 root 1.18 else if (is_environment (args))
5115 root 1.1 {
5116     putstr (SCHEME_A_ "#<ENVIRONMENT>");
5117     s_return (S_T);
5118     }
5119 root 1.18 else if (!is_pair (args))
5120 root 1.1 {
5121 root 1.18 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5122 root 1.1 s_return (S_T);
5123     }
5124     else
5125     {
5126 root 1.18 pointer a = car (args);
5127     pointer b = cdr (args);
5128     int ok_abbr = ok_abbrev (b);
5129     SCHEME_V->args = car (b);
5130    
5131     if (a == SCHEME_V->QUOTE && ok_abbr)
5132     putstr (SCHEME_A_ "'");
5133     else if (a == SCHEME_V->QQUOTE && ok_abbr)
5134     putstr (SCHEME_A_ "`");
5135     else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5136     putstr (SCHEME_A_ ",");
5137     else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5138     putstr (SCHEME_A_ ",@");
5139     else
5140     {
5141     putstr (SCHEME_A_ "(");
5142     s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5143     SCHEME_V->args = a;
5144     }
5145    
5146 root 1.1 s_goto (OP_P0LIST);
5147     }
5148    
5149     case OP_P1LIST:
5150 root 1.18 if (is_pair (args))
5151 root 1.1 {
5152 root 1.18 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5153 root 1.1 putstr (SCHEME_A_ " ");
5154 root 1.18 SCHEME_V->args = car (args);
5155 root 1.1 s_goto (OP_P0LIST);
5156     }
5157 root 1.18 else if (is_vector (args))
5158 root 1.1 {
5159     s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5160     putstr (SCHEME_A_ " . ");
5161     s_goto (OP_P0LIST);
5162     }
5163     else
5164     {
5165 root 1.18 if (args != NIL)
5166 root 1.1 {
5167     putstr (SCHEME_A_ " . ");
5168 root 1.18 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5169 root 1.1 }
5170    
5171     putstr (SCHEME_A_ ")");
5172     s_return (S_T);
5173     }
5174    
5175     case OP_PVECFROM:
5176     {
5177 root 1.18 int i = ivalue_unchecked (cdr (args));
5178     pointer vec = car (args);
5179 root 1.7 int len = veclength (vec);
5180 root 1.1
5181     if (i == len)
5182     {
5183     putstr (SCHEME_A_ ")");
5184     s_return (S_T);
5185     }
5186     else
5187     {
5188     pointer elem = vector_elem (vec, i);
5189    
5190 root 1.18 ivalue_unchecked (cdr (args)) = i + 1;
5191     s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5192 root 1.1 SCHEME_V->args = elem;
5193    
5194     if (i > 0)
5195     putstr (SCHEME_A_ " ");
5196    
5197     s_goto (OP_P0LIST);
5198     }
5199     }
5200     }
5201    
5202 root 1.24 if (USE_ERROR_CHECKING) abort ();
5203 root 1.1 }
5204    
5205 root 1.20 static int
5206 root 1.1 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5207     {
5208 root 1.18 pointer args = SCHEME_V->args;
5209     pointer a = car (args);
5210 root 1.1 pointer x, y;
5211    
5212     switch (op)
5213     {
5214     case OP_LIST_LENGTH: /* length *//* a.k */
5215     {
5216 root 1.18 long v = list_length (SCHEME_A_ a);
5217 root 1.1
5218     if (v < 0)
5219 root 1.18 Error_1 ("length: not a list:", a);
5220 root 1.1
5221     s_return (mk_integer (SCHEME_A_ v));
5222     }
5223    
5224     case OP_ASSQ: /* assq *//* a.k */
5225 root 1.18 x = a;
5226 root 1.1
5227 root 1.18 for (y = cadr (args); is_pair (y); y = cdr (y))
5228 root 1.1 {
5229     if (!is_pair (car (y)))
5230     Error_0 ("unable to handle non pair element");
5231    
5232     if (x == caar (y))
5233     break;
5234     }
5235    
5236     if (is_pair (y))
5237     s_return (car (y));
5238     else
5239     s_return (S_F);
5240    
5241    
5242     case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5243 root 1.18 SCHEME_V->args = a;
5244 root 1.1
5245     if (SCHEME_V->args == NIL)
5246     s_return (S_F);
5247     else if (is_closure (SCHEME_V->args))
5248     s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5249     else if (is_macro (SCHEME_V->args))
5250     s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5251     else
5252     s_return (S_F);
5253    
5254     case OP_CLOSUREP: /* closure? */
5255     /*
5256     * Note, macro object is also a closure.
5257     * Therefore, (closure? <#MACRO>) ==> #t
5258     */
5259 root 1.18 s_retbool (is_closure (a));
5260 root 1.1
5261     case OP_MACROP: /* macro? */
5262 root 1.18 s_retbool (is_macro (a));
5263 root 1.1 }
5264    
5265 root 1.24 if (USE_ERROR_CHECKING) abort ();
5266 root 1.1 }
5267    
5268 root 1.20 /* dispatch functions (opexe_x) return new opcode, or 0 for same opcode, or -1 to stop */
5269     typedef int (*dispatch_func)(SCHEME_P_ enum scheme_opcodes);
5270 root 1.1
5271 root 1.19 typedef int (*test_predicate)(pointer);
5272 root 1.1 static int
5273 root 1.26 tst_any (pointer p)
5274 root 1.1 {
5275     return 1;
5276     }
5277    
5278     static int
5279 root 1.26 tst_inonneg (pointer p)
5280 root 1.1 {
5281 root 1.26 return is_integer (p) && ivalue_unchecked (p) >= 0;
5282 root 1.1 }
5283    
5284 root 1.19 static int
5285 root 1.26 tst_is_list (SCHEME_P_ pointer p)
5286 root 1.19 {
5287     return p == NIL || is_pair (p);
5288     }
5289    
5290 root 1.1 /* Correspond carefully with following defines! */
5291     static struct
5292     {
5293     test_predicate fct;
5294     const char *kind;
5295 root 1.26 } tests[] = {
5296     { tst_any , 0 },
5297     { is_string , "string" },
5298     { is_symbol , "symbol" },
5299     { is_port , "port" },
5300     { is_inport , "input port" },
5301     { is_outport , "output port" },
5302 root 1.19 { is_environment, "environment" },
5303 root 1.26 { is_pair , "pair" },
5304     { 0 , "pair or '()" },
5305     { is_character , "character" },
5306     { is_vector , "vector" },
5307     { is_number , "number" },
5308     { is_integer , "integer" },
5309     { tst_inonneg , "non-negative integer" }
5310 root 1.1 };
5311    
5312 root 1.20 #define TST_NONE 0 /* TST_NONE used for built-ins, 0 for internal ops */
5313 root 1.18 #define TST_ANY "\001"
5314     #define TST_STRING "\002"
5315     #define TST_SYMBOL "\003"
5316     #define TST_PORT "\004"
5317     #define TST_INPORT "\005"
5318     #define TST_OUTPORT "\006"
5319 root 1.1 #define TST_ENVIRONMENT "\007"
5320 root 1.18 #define TST_PAIR "\010"
5321     #define TST_LIST "\011"
5322     #define TST_CHAR "\012"
5323     #define TST_VECTOR "\013"
5324     #define TST_NUMBER "\014"
5325     #define TST_INTEGER "\015"
5326     #define TST_NATURAL "\016"
5327 root 1.1
5328 root 1.20 #define INF_ARG 0xff
5329     #define UNNAMED_OP ""
5330    
5331     static const char opnames[] =
5332     #define OP_DEF(func,name,minarity,maxarity,argtest,op) name "\x00"
5333     #include "opdefines.h"
5334     #undef OP_DEF
5335     ;
5336    
5337     static const char *
5338     opname (int idx)
5339     {
5340     const char *name = opnames;
5341    
5342     /* should do this at compile time, but would require external program, right? */
5343     while (idx--)
5344     name += strlen (name) + 1;
5345    
5346     return *name ? name : "ILLEGAL";
5347     }
5348    
5349     static const char *
5350     procname (pointer x)
5351     {
5352     return opname (procnum (x));
5353     }
5354    
5355 root 1.1 typedef struct
5356     {
5357 root 1.20 uint8_t func;
5358     /*dispatch_func func;*//*TODO: maybe optionally keep the pointer, for speed? */
5359     uint8_t builtin;
5360 root 1.26 #if USE_ERROR_CHECKING
5361 root 1.20 uint8_t min_arity;
5362     uint8_t max_arity;
5363 root 1.18 char arg_tests_encoding[3];
5364 root 1.26 #endif
5365 root 1.1 } op_code_info;
5366    
5367 root 1.20 static const op_code_info dispatch_table[] = {
5368 root 1.26 #if USE_ERROR_CHECKING
5369 root 1.20 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1, minarity, maxarity, argtest },
5370 root 1.26 #else
5371     #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1 },
5372     #endif
5373 root 1.1 #include "opdefines.h"
5374 root 1.18 #undef OP_DEF
5375 root 1.1 {0}
5376     };
5377    
5378     /* kernel of this interpreter */
5379 root 1.23 static void ecb_hot
5380 root 1.1 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5381     {
5382     SCHEME_V->op = op;
5383    
5384     for (;;)
5385     {
5386 root 1.20 const op_code_info *pcd = dispatch_table + SCHEME_V->op;
5387 root 1.1
5388 root 1.4 #if USE_ERROR_CHECKING
5389 root 1.20 if (pcd->builtin) /* if built-in function, check arguments */
5390 root 1.1 {
5391     char msg[STRBUFFSIZE];
5392     int n = list_length (SCHEME_A_ SCHEME_V->args);
5393    
5394     /* Check number of arguments */
5395 root 1.10 if (ecb_expect_false (n < pcd->min_arity))
5396 root 1.1 {
5397     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5398 root 1.20 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5399 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5400     continue;
5401 root 1.1 }
5402 root 1.20 else if (ecb_expect_false (n > pcd->max_arity && pcd->max_arity != INF_ARG))
5403 root 1.1 {
5404     snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5405 root 1.20 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5406 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5407     continue;
5408 root 1.1 }
5409 root 1.20 else
5410 root 1.1 {
5411 root 1.20 if (*pcd->arg_tests_encoding) /* literal 0 and TST_NONE treated the same */
5412 root 1.1 {
5413     int i = 0;
5414     int j;
5415     const char *t = pcd->arg_tests_encoding;
5416     pointer arglist = SCHEME_V->args;
5417    
5418     do
5419     {
5420     pointer arg = car (arglist);
5421    
5422 root 1.18 j = t[0];
5423 root 1.1
5424 root 1.26 /*TODO: tst_is_list has different prototype - fix if other tests acquire same prototype */
5425     if (j == TST_LIST[0])
5426     {
5427     if (!tst_is_list (SCHEME_A_ arg))
5428     break;
5429     }
5430     else
5431     {
5432     if (!tests[j - 1].fct (arg))
5433     break;
5434     }
5435 root 1.1
5436 root 1.18 if (t[1]) /* last test is replicated as necessary */
5437 root 1.2 t++;
5438 root 1.1
5439     arglist = cdr (arglist);
5440     i++;
5441     }
5442     while (i < n);
5443    
5444     if (i < n)
5445     {
5446 root 1.20 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", opname (SCHEME_V->op), i + 1, tests[j].kind);
5447 root 1.21 xError_1 (SCHEME_A_ msg, 0);
5448     continue;
5449 root 1.1 }
5450     }
5451     }
5452     }
5453 root 1.4 #endif
5454 root 1.1
5455     ok_to_freely_gc (SCHEME_A);
5456    
5457 root 1.20 static const dispatch_func dispatch_funcs[] = {
5458     opexe_0,
5459     opexe_1,
5460     opexe_2,
5461     opexe_3,
5462     opexe_4,
5463     opexe_5,
5464     opexe_6,
5465     };
5466    
5467     if (ecb_expect_false (dispatch_funcs [pcd->func] (SCHEME_A_ SCHEME_V->op) != 0))
5468 root 1.1 return;
5469    
5470 root 1.5 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5471 root 1.1 {
5472     xwrstr ("No memory!\n");
5473     return;
5474     }
5475     }
5476     }
5477    
5478     /* ========== Initialization of internal keywords ========== */
5479    
5480     static void
5481 root 1.2 assign_syntax (SCHEME_P_ const char *name)
5482 root 1.1 {
5483     pointer x = oblist_add_by_name (SCHEME_A_ name);
5484     set_typeflag (x, typeflag (x) | T_SYNTAX);
5485     }
5486    
5487     static void
5488 root 1.2 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5489 root 1.1 {
5490     pointer x = mk_symbol (SCHEME_A_ name);
5491     pointer y = mk_proc (SCHEME_A_ op);
5492     new_slot_in_env (SCHEME_A_ x, y);
5493     }
5494    
5495     static pointer
5496     mk_proc (SCHEME_P_ enum scheme_opcodes op)
5497     {
5498     pointer y = get_cell (SCHEME_A_ NIL, NIL);
5499     set_typeflag (y, (T_PROC | T_ATOM));
5500 root 1.2 ivalue_unchecked (y) = op;
5501 root 1.1 return y;
5502     }
5503    
5504     /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5505     static int
5506     syntaxnum (pointer p)
5507     {
5508     const char *s = strvalue (car (p));
5509    
5510     switch (strlength (car (p)))
5511     {
5512     case 2:
5513     if (s[0] == 'i')
5514     return OP_IF0; /* if */
5515     else
5516     return OP_OR0; /* or */
5517    
5518     case 3:
5519     if (s[0] == 'a')
5520     return OP_AND0; /* and */
5521     else
5522     return OP_LET0; /* let */
5523    
5524     case 4:
5525     switch (s[3])
5526     {
5527     case 'e':
5528     return OP_CASE0; /* case */
5529    
5530     case 'd':
5531     return OP_COND0; /* cond */
5532    
5533     case '*':
5534 root 1.10 return OP_LET0AST;/* let* */
5535 root 1.1
5536     default:
5537     return OP_SET0; /* set! */
5538     }
5539    
5540     case 5:
5541     switch (s[2])
5542     {
5543     case 'g':
5544     return OP_BEGIN; /* begin */
5545    
5546     case 'l':
5547     return OP_DELAY; /* delay */
5548    
5549     case 'c':
5550     return OP_MACRO0; /* macro */
5551    
5552     default:
5553     return OP_QUOTE; /* quote */
5554     }
5555    
5556     case 6:
5557     switch (s[2])
5558     {
5559     case 'm':
5560     return OP_LAMBDA; /* lambda */
5561    
5562     case 'f':
5563     return OP_DEF0; /* define */
5564    
5565     default:
5566 root 1.10 return OP_LET0REC;/* letrec */
5567 root 1.1 }
5568    
5569     default:
5570     return OP_C0STREAM; /* cons-stream */
5571     }
5572     }
5573    
5574     #if USE_MULTIPLICITY
5575 root 1.23 ecb_cold scheme *
5576 root 1.1 scheme_init_new ()
5577     {
5578     scheme *sc = malloc (sizeof (scheme));
5579    
5580     if (!scheme_init (SCHEME_A))
5581     {
5582     free (SCHEME_A);
5583     return 0;
5584     }
5585     else
5586     return sc;
5587     }
5588     #endif
5589    
5590 root 1.23 ecb_cold int
5591 root 1.1 scheme_init (SCHEME_P)
5592     {
5593     int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5594     pointer x;
5595    
5596     num_set_fixnum (num_zero, 1);
5597     num_set_ivalue (num_zero, 0);
5598     num_set_fixnum (num_one, 1);
5599     num_set_ivalue (num_one, 1);
5600    
5601     #if USE_INTERFACE
5602     SCHEME_V->vptr = &vtbl;
5603     #endif
5604     SCHEME_V->gensym_cnt = 0;
5605     SCHEME_V->last_cell_seg = -1;
5606     SCHEME_V->free_cell = NIL;
5607     SCHEME_V->fcells = 0;
5608     SCHEME_V->no_memory = 0;
5609     SCHEME_V->inport = NIL;
5610     SCHEME_V->outport = NIL;
5611     SCHEME_V->save_inport = NIL;
5612     SCHEME_V->loadport = NIL;
5613     SCHEME_V->nesting = 0;
5614     SCHEME_V->interactive_repl = 0;
5615    
5616     if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5617     {
5618     #if USE_ERROR_CHECKING
5619     SCHEME_V->no_memory = 1;
5620     return 0;
5621     #endif
5622     }
5623    
5624     SCHEME_V->gc_verbose = 0;
5625     dump_stack_initialize (SCHEME_A);
5626     SCHEME_V->code = NIL;
5627 root 1.2 SCHEME_V->args = NIL;
5628     SCHEME_V->envir = NIL;
5629 root 1.1 SCHEME_V->tracing = 0;
5630    
5631     /* init NIL */
5632 root 1.2 set_typeflag (NIL, T_ATOM | T_MARK);
5633 root 1.1 set_car (NIL, NIL);
5634     set_cdr (NIL, NIL);
5635     /* init T */
5636 root 1.2 set_typeflag (S_T, T_ATOM | T_MARK);
5637 root 1.1 set_car (S_T, S_T);
5638     set_cdr (S_T, S_T);
5639     /* init F */
5640 root 1.2 set_typeflag (S_F, T_ATOM | T_MARK);
5641 root 1.1 set_car (S_F, S_F);
5642     set_cdr (S_F, S_F);
5643 root 1.7 /* init EOF_OBJ */
5644     set_typeflag (S_EOF, T_ATOM | T_MARK);
5645     set_car (S_EOF, S_EOF);
5646     set_cdr (S_EOF, S_EOF);
5647 root 1.1 /* init sink */
5648 root 1.2 set_typeflag (S_SINK, T_PAIR | T_MARK);
5649 root 1.1 set_car (S_SINK, NIL);
5650 root 1.7
5651 root 1.1 /* init c_nest */
5652     SCHEME_V->c_nest = NIL;
5653    
5654     SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5655     /* init global_env */
5656     new_frame_in_env (SCHEME_A_ NIL);
5657     SCHEME_V->global_env = SCHEME_V->envir;
5658     /* init else */
5659     x = mk_symbol (SCHEME_A_ "else");
5660     new_slot_in_env (SCHEME_A_ x, S_T);
5661    
5662 root 1.2 {
5663     static const char *syntax_names[] = {
5664     "lambda", "quote", "define", "if", "begin", "set!",
5665     "let", "let*", "letrec", "cond", "delay", "and",
5666     "or", "cons-stream", "macro", "case"
5667     };
5668    
5669     for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5670     assign_syntax (SCHEME_A_ syntax_names[i]);
5671     }
5672 root 1.1
5673 root 1.20 // TODO: should iterate via strlen, to avoid n² complexity
5674 root 1.1 for (i = 0; i < n; i++)
5675 root 1.20 if (dispatch_table[i].builtin)
5676     assign_proc (SCHEME_A_ i, opname (i));
5677 root 1.1
5678     /* initialization of global pointers to special symbols */
5679 root 1.6 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5680     SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5681     SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5682     SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5683     SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5684     SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5685     SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5686     SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5687     SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5688 root 1.1 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5689    
5690     return !SCHEME_V->no_memory;
5691     }
5692    
5693     #if USE_PORTS
5694     void
5695     scheme_set_input_port_file (SCHEME_P_ int fin)
5696     {
5697     SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5698     }
5699    
5700     void
5701     scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5702     {
5703     SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5704     }
5705    
5706     void
5707     scheme_set_output_port_file (SCHEME_P_ int fout)
5708     {
5709     SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5710     }
5711    
5712     void
5713     scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5714     {
5715     SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5716     }
5717     #endif
5718    
5719     void
5720     scheme_set_external_data (SCHEME_P_ void *p)
5721     {
5722     SCHEME_V->ext_data = p;
5723     }
5724    
5725 root 1.23 ecb_cold void
5726 root 1.1 scheme_deinit (SCHEME_P)
5727     {
5728     int i;
5729    
5730     #if SHOW_ERROR_LINE
5731     char *fname;
5732     #endif
5733    
5734     SCHEME_V->oblist = NIL;
5735     SCHEME_V->global_env = NIL;
5736     dump_stack_free (SCHEME_A);
5737     SCHEME_V->envir = NIL;
5738     SCHEME_V->code = NIL;
5739     SCHEME_V->args = NIL;
5740     SCHEME_V->value = NIL;
5741    
5742     if (is_port (SCHEME_V->inport))
5743     set_typeflag (SCHEME_V->inport, T_ATOM);
5744    
5745     SCHEME_V->inport = NIL;
5746     SCHEME_V->outport = NIL;
5747    
5748     if (is_port (SCHEME_V->save_inport))
5749     set_typeflag (SCHEME_V->save_inport, T_ATOM);
5750    
5751     SCHEME_V->save_inport = NIL;
5752    
5753     if (is_port (SCHEME_V->loadport))
5754     set_typeflag (SCHEME_V->loadport, T_ATOM);
5755    
5756     SCHEME_V->loadport = NIL;
5757     SCHEME_V->gc_verbose = 0;
5758     gc (SCHEME_A_ NIL, NIL);
5759    
5760     for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5761     free (SCHEME_V->alloc_seg[i]);
5762    
5763     #if SHOW_ERROR_LINE
5764     for (i = 0; i <= SCHEME_V->file_i; i++)
5765     {
5766     if (SCHEME_V->load_stack[i].kind & port_file)
5767     {
5768     fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5769    
5770     if (fname)
5771     free (fname);
5772     }
5773     }
5774     #endif
5775     }
5776    
5777     void
5778     scheme_load_file (SCHEME_P_ int fin)
5779     {
5780     scheme_load_named_file (SCHEME_A_ fin, 0);
5781     }
5782    
5783     void
5784     scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5785     {
5786     dump_stack_reset (SCHEME_A);
5787     SCHEME_V->envir = SCHEME_V->global_env;
5788     SCHEME_V->file_i = 0;
5789     SCHEME_V->load_stack[0].unget = -1;
5790     SCHEME_V->load_stack[0].kind = port_input | port_file;
5791     SCHEME_V->load_stack[0].rep.stdio.file = fin;
5792     #if USE_PORTS
5793     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5794     #endif
5795     SCHEME_V->retcode = 0;
5796    
5797     #if USE_PORTS
5798     if (fin == STDIN_FILENO)
5799     SCHEME_V->interactive_repl = 1;
5800     #endif
5801    
5802     #if USE_PORTS
5803     #if SHOW_ERROR_LINE
5804     SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5805    
5806     if (fin != STDIN_FILENO && filename)
5807     SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5808     #endif
5809     #endif
5810    
5811     SCHEME_V->inport = SCHEME_V->loadport;
5812     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5813     Eval_Cycle (SCHEME_A_ OP_T0LVL);
5814     set_typeflag (SCHEME_V->loadport, T_ATOM);
5815    
5816     if (SCHEME_V->retcode == 0)
5817     SCHEME_V->retcode = SCHEME_V->nesting != 0;
5818     }
5819    
5820     void
5821     scheme_load_string (SCHEME_P_ const char *cmd)
5822     {
5823     dump_stack_reset (SCHEME_A);
5824     SCHEME_V->envir = SCHEME_V->global_env;
5825     SCHEME_V->file_i = 0;
5826     SCHEME_V->load_stack[0].kind = port_input | port_string;
5827 root 1.17 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
5828     SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
5829     SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
5830 root 1.1 #if USE_PORTS
5831     SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5832     #endif
5833     SCHEME_V->retcode = 0;
5834     SCHEME_V->interactive_repl = 0;
5835     SCHEME_V->inport = SCHEME_V->loadport;
5836     SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5837     Eval_Cycle (SCHEME_A_ OP_T0LVL);
5838     set_typeflag (SCHEME_V->loadport, T_ATOM);
5839    
5840     if (SCHEME_V->retcode == 0)
5841     SCHEME_V->retcode = SCHEME_V->nesting != 0;
5842     }
5843    
5844     void
5845     scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
5846     {
5847     pointer x;
5848    
5849     x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
5850    
5851     if (x != NIL)
5852 root 1.2 set_slot_in_env (SCHEME_A_ x, value);
5853 root 1.1 else
5854 root 1.2 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
5855 root 1.1 }
5856    
5857     #if !STANDALONE
5858 root 1.2
5859 root 1.1 void
5860     scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
5861     {
5862     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
5863     }
5864    
5865     void
5866     scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
5867     {
5868     int i;
5869    
5870     for (i = 0; i < count; i++)
5871 root 1.2 scheme_register_foreign_func (SCHEME_A_ list + i);
5872 root 1.1 }
5873    
5874     pointer
5875     scheme_apply0 (SCHEME_P_ const char *procname)
5876     {
5877     return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
5878     }
5879    
5880     void
5881     save_from_C_call (SCHEME_P)
5882     {
5883     pointer saved_data = cons (car (S_SINK),
5884     cons (SCHEME_V->envir,
5885     SCHEME_V->dump));
5886    
5887     /* Push */
5888     SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
5889     /* Truncate the dump stack so TS will return here when done, not
5890     directly resume pre-C-call operations. */
5891     dump_stack_reset (SCHEME_A);
5892     }
5893    
5894     void
5895     restore_from_C_call (SCHEME_P)
5896     {
5897     set_car (S_SINK, caar (SCHEME_V->c_nest));
5898     SCHEME_V->envir = cadar (SCHEME_V->c_nest);
5899     SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
5900     /* Pop */
5901     SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
5902     }
5903    
5904     /* "func" and "args" are assumed to be already eval'ed. */
5905     pointer
5906     scheme_call (SCHEME_P_ pointer func, pointer args)
5907     {
5908     int old_repl = SCHEME_V->interactive_repl;
5909    
5910     SCHEME_V->interactive_repl = 0;
5911     save_from_C_call (SCHEME_A);
5912     SCHEME_V->envir = SCHEME_V->global_env;
5913     SCHEME_V->args = args;
5914     SCHEME_V->code = func;
5915     SCHEME_V->retcode = 0;
5916     Eval_Cycle (SCHEME_A_ OP_APPLY);
5917     SCHEME_V->interactive_repl = old_repl;
5918     restore_from_C_call (SCHEME_A);
5919     return SCHEME_V->value;
5920     }
5921    
5922     pointer
5923     scheme_eval (SCHEME_P_ pointer obj)
5924     {
5925     int old_repl = SCHEME_V->interactive_repl;
5926    
5927     SCHEME_V->interactive_repl = 0;
5928     save_from_C_call (SCHEME_A);
5929     SCHEME_V->args = NIL;
5930     SCHEME_V->code = obj;
5931     SCHEME_V->retcode = 0;
5932     Eval_Cycle (SCHEME_A_ OP_EVAL);
5933     SCHEME_V->interactive_repl = old_repl;
5934     restore_from_C_call (SCHEME_A);
5935     return SCHEME_V->value;
5936     }
5937    
5938     #endif
5939    
5940     /* ========== Main ========== */
5941    
5942     #if STANDALONE
5943    
5944     int
5945     main (int argc, char **argv)
5946     {
5947     # if USE_MULTIPLICITY
5948     scheme ssc;
5949 root 1.2 scheme *const SCHEME_V = &ssc;
5950 root 1.1 # else
5951     # endif
5952     int fin;
5953     char *file_name = InitFile;
5954     int retcode;
5955     int isfile = 1;
5956    
5957     if (argc == 2 && strcmp (argv[1], "-?") == 0)
5958     {
5959     xwrstr ("Usage: tinyscheme -?\n");
5960     xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
5961     xwrstr ("followed by\n");
5962     xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
5963     xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5964     xwrstr ("assuming that the executable is named tinyscheme.\n");
5965     xwrstr ("Use - as filename for stdin.\n");
5966     return 1;
5967     }
5968    
5969     if (!scheme_init (SCHEME_A))
5970     {
5971     xwrstr ("Could not initialize!\n");
5972     return 2;
5973     }
5974    
5975     # if USE_PORTS
5976     scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
5977     scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
5978     # endif
5979    
5980     argv++;
5981    
5982     #if 0
5983     if (access (file_name, 0) != 0)
5984     {
5985     char *p = getenv ("TINYSCHEMEINIT");
5986    
5987     if (p != 0)
5988 root 1.2 file_name = p;
5989 root 1.1 }
5990     #endif
5991    
5992     do
5993     {
5994     #if USE_PORTS
5995     if (strcmp (file_name, "-") == 0)
5996     fin = STDIN_FILENO;
5997     else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
5998     {
5999     pointer args = NIL;
6000    
6001     isfile = file_name[1] == '1';
6002     file_name = *argv++;
6003    
6004     if (strcmp (file_name, "-") == 0)
6005     fin = STDIN_FILENO;
6006     else if (isfile)
6007     fin = open (file_name, O_RDONLY);
6008    
6009     for (; *argv; argv++)
6010     {
6011     pointer value = mk_string (SCHEME_A_ * argv);
6012    
6013     args = cons (value, args);
6014     }
6015    
6016     args = reverse_in_place (SCHEME_A_ NIL, args);
6017     scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
6018    
6019     }
6020     else
6021     fin = open (file_name, O_RDONLY);
6022     #endif
6023    
6024     if (isfile && fin < 0)
6025     {
6026     xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
6027     }
6028     else
6029     {
6030     if (isfile)
6031     scheme_load_named_file (SCHEME_A_ fin, file_name);
6032     else
6033     scheme_load_string (SCHEME_A_ file_name);
6034    
6035     #if USE_PORTS
6036     if (!isfile || fin != STDIN_FILENO)
6037     {
6038     if (SCHEME_V->retcode != 0)
6039     {
6040     xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
6041     }
6042    
6043     if (isfile)
6044     close (fin);
6045     }
6046     #endif
6047     }
6048    
6049     file_name = *argv++;
6050     }
6051     while (file_name != 0);
6052    
6053     if (argc == 1)
6054     scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6055    
6056     retcode = SCHEME_V->retcode;
6057     scheme_deinit (SCHEME_A);
6058    
6059     return retcode;
6060     }
6061    
6062     #endif
6063    
6064     /*
6065     Local variables:
6066     c-file-style: "k&r"
6067     End:
6068     */