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