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

File Contents

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