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

File Contents

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