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