ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.49
Committed: Mon Nov 30 13:09:56 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.48: +5 -1 lines
Log Message:
*** empty log message ***

File Contents

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