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

File Contents

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