ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/microscheme/scheme.c
Revision: 1.45
Committed: Mon Nov 30 07:44:23 2015 UTC (8 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.44: +5 -2 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->cell_segsize [SCHEME_V->last_cell_seg] >> 2;
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_ NIL, NIL);
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 if (SCHEME_V->gc_verbose)
1662 xwrstr ("freeing...");
1663
1664 uint32_t total = 0;
1665
1666 /* Here we scan the cells to build the free-list. */
1667 for (i = SCHEME_V->last_cell_seg; i >= 0; i--)
1668 {
1669 pointer end = SCHEME_V->cell_seg[i] + SCHEME_V->cell_segsize [i];
1670 total += SCHEME_V->cell_segsize [i];
1671
1672 for (p = SCHEME_V->cell_seg[i]; p < end; ++p)
1673 {
1674 if (is_mark (p))
1675 clrmark (p);
1676 else
1677 {
1678 /* reclaim cell */
1679 if (typeflag (p) != T_PAIR)
1680 {
1681 finalize_cell (SCHEME_A_ p);
1682 set_typeflag (p, T_PAIR);
1683 set_car (p, NIL);
1684 }
1685
1686 ++SCHEME_V->fcells;
1687 set_cdr (p, SCHEME_V->free_cell);
1688 SCHEME_V->free_cell = p;
1689 }
1690 }
1691 }
1692
1693 if (SCHEME_V->gc_verbose)
1694 {
1695 xwrstr ("done: "); xwrnum (SCHEME_V->fcells); xwrstr (" out of "); xwrnum (total); xwrstr (" cells were recovered.\n");
1696 }
1697 }
1698
1699 static void
1700 finalize_cell (SCHEME_P_ pointer a)
1701 {
1702 /* TODO, fast bitmap check? */
1703 if (is_string (a) || is_symbol (a))
1704 free (strvalue (a));
1705 else if (is_vector (a))
1706 free (vecvalue (a));
1707 #if USE_PORTS
1708 else if (is_port (a))
1709 {
1710 if (a->object.port->kind & port_file && a->object.port->rep.stdio.closeit)
1711 port_close (SCHEME_A_ a, port_input | port_output);
1712
1713 free (a->object.port);
1714 }
1715 #endif
1716 }
1717
1718 /* ========== Routines for Reading ========== */
1719
1720 static int
1721 file_push (SCHEME_P_ const char *fname)
1722 {
1723 #if USE_PORTS
1724 int fin;
1725
1726 if (SCHEME_V->file_i == MAXFIL - 1)
1727 return 0;
1728
1729 fin = open (fname, O_RDONLY);
1730
1731 if (fin >= 0)
1732 {
1733 SCHEME_V->file_i++;
1734 SCHEME_V->load_stack[SCHEME_V->file_i].unget = -1;
1735 SCHEME_V->load_stack[SCHEME_V->file_i].kind = port_file | port_input;
1736 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.file = fin;
1737 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.closeit = 1;
1738 SCHEME_V->nesting_stack[SCHEME_V->file_i] = 0;
1739 SCHEME_V->loadport->object.port = SCHEME_V->load_stack + SCHEME_V->file_i;
1740
1741 #if SHOW_ERROR_LINE
1742 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line = 0;
1743
1744 if (fname)
1745 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.filename = store_string (SCHEME_A_ strlen (fname), fname, 0);
1746 #endif
1747 }
1748
1749 return fin >= 0;
1750
1751 #else
1752 return 1;
1753 #endif
1754 }
1755
1756 static void
1757 file_pop (SCHEME_P)
1758 {
1759 if (SCHEME_V->file_i != 0)
1760 {
1761 SCHEME_V->nesting = SCHEME_V->nesting_stack[SCHEME_V->file_i];
1762 #if USE_PORTS
1763 port_close (SCHEME_A_ SCHEME_V->loadport, port_input);
1764 #endif
1765 SCHEME_V->file_i--;
1766 SCHEME_V->loadport->object.port = SCHEME_V->load_stack + SCHEME_V->file_i;
1767 }
1768 }
1769
1770 static int
1771 file_interactive (SCHEME_P)
1772 {
1773 #if USE_PORTS
1774 return SCHEME_V->file_i == 0
1775 && SCHEME_V->load_stack[0].rep.stdio.file == STDIN_FILENO
1776 && (SCHEME_V->inport->object.port->kind & port_file);
1777 #else
1778 return 0;
1779 #endif
1780 }
1781
1782 #if USE_PORTS
1783 static port *
1784 port_rep_from_filename (SCHEME_P_ const char *fn, int prop)
1785 {
1786 int fd;
1787 int flags;
1788 char *rw;
1789 port *pt;
1790
1791 if (prop == (port_input | port_output))
1792 flags = O_RDWR | O_APPEND | O_CREAT;
1793 else if (prop == port_output)
1794 flags = O_WRONLY | O_TRUNC | O_CREAT;
1795 else
1796 flags = O_RDONLY;
1797
1798 fd = open (fn, flags, 0666);
1799
1800 if (fd < 0)
1801 return 0;
1802
1803 pt = port_rep_from_file (SCHEME_A_ fd, prop);
1804 pt->rep.stdio.closeit = 1;
1805
1806 # if SHOW_ERROR_LINE
1807 if (fn)
1808 pt->rep.stdio.filename = store_string (SCHEME_A_ strlen (fn), fn, 0);
1809
1810 pt->rep.stdio.curr_line = 0;
1811 # endif
1812
1813 return pt;
1814 }
1815
1816 static pointer
1817 port_from_filename (SCHEME_P_ const char *fn, int prop)
1818 {
1819 port *pt = port_rep_from_filename (SCHEME_A_ fn, prop);
1820
1821 if (!pt && USE_ERROR_CHECKING)
1822 return NIL;
1823
1824 return mk_port (SCHEME_A_ pt);
1825 }
1826
1827 static port *
1828 port_rep_from_file (SCHEME_P_ int f, int prop)
1829 {
1830 port *pt = malloc (sizeof *pt);
1831
1832 if (!pt && USE_ERROR_CHECKING)
1833 return NULL;
1834
1835 pt->unget = -1;
1836 pt->kind = port_file | prop;
1837 pt->rep.stdio.file = f;
1838 pt->rep.stdio.closeit = 0;
1839 return pt;
1840 }
1841
1842 static pointer
1843 port_from_file (SCHEME_P_ int f, int prop)
1844 {
1845 port *pt = port_rep_from_file (SCHEME_A_ f, prop);
1846
1847 if (!pt && USE_ERROR_CHECKING)
1848 return NIL;
1849
1850 return mk_port (SCHEME_A_ pt);
1851 }
1852
1853 static port *
1854 port_rep_from_string (SCHEME_P_ char *start, char *past_the_end, int prop)
1855 {
1856 port *pt = malloc (sizeof (port));
1857
1858 if (!pt && USE_ERROR_CHECKING)
1859 return 0;
1860
1861 pt->unget = -1;
1862 pt->kind = port_string | prop;
1863 pt->rep.string.start = start;
1864 pt->rep.string.curr = start;
1865 pt->rep.string.past_the_end = past_the_end;
1866 return pt;
1867 }
1868
1869 static pointer
1870 port_from_string (SCHEME_P_ char *start, char *past_the_end, int prop)
1871 {
1872 port *pt = port_rep_from_string (SCHEME_A_ start, past_the_end, prop);
1873
1874 if (!pt && USE_ERROR_CHECKING)
1875 return NIL;
1876
1877 return mk_port (SCHEME_A_ pt);
1878 }
1879
1880 # define BLOCK_SIZE 256
1881
1882 static port *
1883 port_rep_from_scratch (SCHEME_P)
1884 {
1885 char *start;
1886 port *pt = malloc (sizeof (port));
1887
1888 if (!pt && USE_ERROR_CHECKING)
1889 return 0;
1890
1891 start = malloc (BLOCK_SIZE);
1892
1893 if (start == 0)
1894 return 0;
1895
1896 memset (start, ' ', BLOCK_SIZE - 1);
1897 start[BLOCK_SIZE - 1] = '\0';
1898 pt->unget = -1;
1899 pt->kind = port_string | port_output | port_srfi6;
1900 pt->rep.string.start = start;
1901 pt->rep.string.curr = start;
1902 pt->rep.string.past_the_end = start + BLOCK_SIZE - 1;
1903 return pt;
1904 }
1905
1906 static pointer
1907 port_from_scratch (SCHEME_P)
1908 {
1909 port *pt = port_rep_from_scratch (SCHEME_A);
1910
1911 if (!pt && USE_ERROR_CHECKING)
1912 return NIL;
1913
1914 return mk_port (SCHEME_A_ pt);
1915 }
1916
1917 static void
1918 port_close (SCHEME_P_ pointer p, int flag)
1919 {
1920 port *pt = p->object.port;
1921
1922 pt->kind &= ~flag;
1923
1924 if ((pt->kind & (port_input | port_output)) == 0)
1925 {
1926 if (pt->kind & port_file)
1927 {
1928
1929 # if SHOW_ERROR_LINE
1930 /* Cleanup is here so (close-*-port) functions could work too */
1931 pt->rep.stdio.curr_line = 0;
1932
1933 if (pt->rep.stdio.filename)
1934 free (pt->rep.stdio.filename);
1935
1936 # endif
1937
1938 close (pt->rep.stdio.file);
1939 }
1940
1941 pt->kind = port_free;
1942 }
1943 }
1944 #endif
1945
1946 /* get new character from input file */
1947 static int
1948 inchar (SCHEME_P)
1949 {
1950 int c;
1951 port *pt;
1952
1953 pt = SCHEME_V->inport->object.port;
1954
1955 if (pt->kind & port_saw_EOF)
1956 return EOF;
1957
1958 c = basic_inchar (pt);
1959
1960 if (c == EOF && SCHEME_V->inport == SCHEME_V->loadport)
1961 {
1962 /* Instead, set port_saw_EOF */
1963 pt->kind |= port_saw_EOF;
1964
1965 /* file_pop(SCHEME_A); */
1966 return EOF;
1967 /* NOTREACHED */
1968 }
1969
1970 return c;
1971 }
1972
1973 static int ungot = -1;
1974
1975 static int
1976 basic_inchar (port *pt)
1977 {
1978 #if USE_PORTS
1979 if (pt->unget != -1)
1980 {
1981 int r = pt->unget;
1982 pt->unget = -1;
1983 return r;
1984 }
1985
1986 if (pt->kind & port_file)
1987 {
1988 char c;
1989
1990 if (!read (pt->rep.stdio.file, &c, 1))
1991 return EOF;
1992
1993 return c;
1994 }
1995 else
1996 {
1997 if (*pt->rep.string.curr == 0 || pt->rep.string.curr == pt->rep.string.past_the_end)
1998 return EOF;
1999 else
2000 return *pt->rep.string.curr++;
2001 }
2002 #else
2003 if (ungot == -1)
2004 {
2005 char c;
2006 if (!read (0, &c, 1))
2007 return EOF;
2008
2009 ungot = c;
2010 }
2011
2012 {
2013 int r = ungot;
2014 ungot = -1;
2015 return r;
2016 }
2017 #endif
2018 }
2019
2020 /* back character to input buffer */
2021 static void
2022 backchar (SCHEME_P_ int c)
2023 {
2024 #if USE_PORTS
2025 port *pt;
2026
2027 if (c == EOF)
2028 return;
2029
2030 pt = SCHEME_V->inport->object.port;
2031 pt->unget = c;
2032 #else
2033 if (c == EOF)
2034 return;
2035
2036 ungot = c;
2037 #endif
2038 }
2039
2040 #if USE_PORTS
2041 static int
2042 realloc_port_string (SCHEME_P_ port *p)
2043 {
2044 char *start = p->rep.string.start;
2045 size_t new_size = p->rep.string.past_the_end - start + 1 + BLOCK_SIZE;
2046 char *str = malloc (new_size);
2047
2048 if (str)
2049 {
2050 memset (str, ' ', new_size - 1);
2051 str[new_size - 1] = '\0';
2052 strcpy (str, start);
2053 p->rep.string.start = str;
2054 p->rep.string.past_the_end = str + new_size - 1;
2055 p->rep.string.curr -= start - str;
2056 free (start);
2057 return 1;
2058 }
2059 else
2060 return 0;
2061 }
2062 #endif
2063
2064 INTERFACE void
2065 putstr (SCHEME_P_ const char *s)
2066 {
2067 #if USE_PORTS
2068 port *pt = SCHEME_V->outport->object.port;
2069
2070 if (pt->kind & port_file)
2071 write (pt->rep.stdio.file, s, strlen (s));
2072 else
2073 for (; *s; s++)
2074 if (pt->rep.string.curr != pt->rep.string.past_the_end)
2075 *pt->rep.string.curr++ = *s;
2076 else if (pt->kind & port_srfi6 && realloc_port_string (SCHEME_A_ pt))
2077 *pt->rep.string.curr++ = *s;
2078
2079 #else
2080 xwrstr (s);
2081 #endif
2082 }
2083
2084 static void
2085 putchars (SCHEME_P_ const char *s, int len)
2086 {
2087 #if USE_PORTS
2088 port *pt = SCHEME_V->outport->object.port;
2089
2090 if (pt->kind & port_file)
2091 write (pt->rep.stdio.file, s, len);
2092 else
2093 {
2094 for (; len; len--)
2095 {
2096 if (pt->rep.string.curr != pt->rep.string.past_the_end)
2097 *pt->rep.string.curr++ = *s++;
2098 else if (pt->kind & port_srfi6 && realloc_port_string (SCHEME_A_ pt))
2099 *pt->rep.string.curr++ = *s++;
2100 }
2101 }
2102
2103 #else
2104 write (1, s, len);
2105 #endif
2106 }
2107
2108 INTERFACE void
2109 putcharacter (SCHEME_P_ int c)
2110 {
2111 #if USE_PORTS
2112 port *pt = SCHEME_V->outport->object.port;
2113
2114 if (pt->kind & port_file)
2115 {
2116 char cc = c;
2117 write (pt->rep.stdio.file, &cc, 1);
2118 }
2119 else
2120 {
2121 if (pt->rep.string.curr != pt->rep.string.past_the_end)
2122 *pt->rep.string.curr++ = c;
2123 else if (pt->kind & port_srfi6 && realloc_port_string (SCHEME_A_ pt))
2124 *pt->rep.string.curr++ = c;
2125 }
2126
2127 #else
2128 char cc = c;
2129 write (1, &c, 1);
2130 #endif
2131 }
2132
2133 /* read characters up to delimiter, but cater to character constants */
2134 static char *
2135 readstr_upto (SCHEME_P_ int skip, const char *delim)
2136 {
2137 char *p = SCHEME_V->strbuff + skip;
2138
2139 while ((p - SCHEME_V->strbuff < sizeof (SCHEME_V->strbuff)) && !is_one_of (delim, (*p++ = inchar (SCHEME_A))));
2140
2141 if (p == SCHEME_V->strbuff + 2 && p[-2] == '\\')
2142 *p = 0;
2143 else
2144 {
2145 backchar (SCHEME_A_ p[-1]);
2146 *--p = '\0';
2147 }
2148
2149 return SCHEME_V->strbuff;
2150 }
2151
2152 /* read string expression "xxx...xxx" */
2153 static pointer
2154 readstrexp (SCHEME_P_ char delim)
2155 {
2156 char *p = SCHEME_V->strbuff;
2157 int c;
2158 int c1 = 0;
2159 enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state = st_ok;
2160
2161 for (;;)
2162 {
2163 c = inchar (SCHEME_A);
2164
2165 if (c == EOF || p - SCHEME_V->strbuff > sizeof (SCHEME_V->strbuff) - 1)
2166 return S_F;
2167
2168 switch (state)
2169 {
2170 case st_ok:
2171 if (ecb_expect_false (c == delim))
2172 return mk_counted_string (SCHEME_A_ SCHEME_V->strbuff, p - SCHEME_V->strbuff);
2173
2174 if (ecb_expect_false (c == '\\'))
2175 state = st_bsl;
2176 else
2177 *p++ = c;
2178
2179 break;
2180
2181 case st_bsl:
2182 switch (c)
2183 {
2184 case '0':
2185 case '1':
2186 case '2':
2187 case '3':
2188 case '4':
2189 case '5':
2190 case '6':
2191 case '7':
2192 state = st_oct1;
2193 c1 = c - '0';
2194 break;
2195
2196 case 'x':
2197 case 'X':
2198 state = st_x1;
2199 c1 = 0;
2200 break;
2201
2202 case 'n':
2203 *p++ = '\n';
2204 state = st_ok;
2205 break;
2206
2207 case 't':
2208 *p++ = '\t';
2209 state = st_ok;
2210 break;
2211
2212 case 'r':
2213 *p++ = '\r';
2214 state = st_ok;
2215 break;
2216
2217 default:
2218 *p++ = c;
2219 state = st_ok;
2220 break;
2221 }
2222
2223 break;
2224
2225 case st_x1:
2226 case st_x2:
2227 c = tolower (c);
2228
2229 if (c >= '0' && c <= '9')
2230 c1 = (c1 << 4) + c - '0';
2231 else if (c >= 'a' && c <= 'f')
2232 c1 = (c1 << 4) + c - 'a' + 10;
2233 else
2234 return S_F;
2235
2236 if (state == st_x1)
2237 state = st_x2;
2238 else
2239 {
2240 *p++ = c1;
2241 state = st_ok;
2242 }
2243
2244 break;
2245
2246 case st_oct1:
2247 case st_oct2:
2248 if (c < '0' || c > '7')
2249 {
2250 *p++ = c1;
2251 backchar (SCHEME_A_ c);
2252 state = st_ok;
2253 }
2254 else
2255 {
2256 if (state == st_oct2 && c1 >= ' ')
2257 return S_F;
2258
2259 c1 = (c1 << 3) + (c - '0');
2260
2261 if (state == st_oct1)
2262 state = st_oct2;
2263 else
2264 {
2265 *p++ = c1;
2266 state = st_ok;
2267 }
2268 }
2269
2270 break;
2271 }
2272 }
2273 }
2274
2275 /* check c is in chars */
2276 ecb_inline int
2277 is_one_of (const char *s, int c)
2278 {
2279 return c == EOF || !!strchr (s, c);
2280 }
2281
2282 /* skip white characters */
2283 ecb_inline int
2284 skipspace (SCHEME_P)
2285 {
2286 int c, curr_line = 0;
2287
2288 do
2289 {
2290 c = inchar (SCHEME_A);
2291
2292 #if SHOW_ERROR_LINE
2293 if (ecb_expect_false (c == '\n'))
2294 curr_line++;
2295 #endif
2296
2297 if (ecb_expect_false (c == EOF))
2298 return c;
2299 }
2300 while (is_one_of (WHITESPACE, c));
2301
2302 /* record it */
2303 #if SHOW_ERROR_LINE
2304 if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
2305 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line += curr_line;
2306 #endif
2307
2308 backchar (SCHEME_A_ c);
2309 return 1;
2310 }
2311
2312 /* get token */
2313 static int
2314 token (SCHEME_P)
2315 {
2316 int c = skipspace (SCHEME_A);
2317
2318 if (c == EOF)
2319 return TOK_EOF;
2320
2321 switch ((c = inchar (SCHEME_A)))
2322 {
2323 case EOF:
2324 return TOK_EOF;
2325
2326 case '(':
2327 return TOK_LPAREN;
2328
2329 case ')':
2330 return TOK_RPAREN;
2331
2332 case '.':
2333 c = inchar (SCHEME_A);
2334
2335 if (is_one_of (WHITESPACE, c))
2336 return TOK_DOT;
2337 else
2338 {
2339 backchar (SCHEME_A_ c);
2340 return TOK_DOTATOM;
2341 }
2342
2343 case '|':
2344 return TOK_STRATOM;
2345
2346 case '\'':
2347 return TOK_QUOTE;
2348
2349 case ';':
2350 while ((c = inchar (SCHEME_A)) != '\n' && c != EOF)
2351 ;
2352
2353 #if SHOW_ERROR_LINE
2354
2355 if (c == '\n' && SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
2356 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
2357
2358 #endif
2359
2360 if (c == EOF)
2361 return TOK_EOF;
2362 else
2363 return token (SCHEME_A);
2364
2365 case '"':
2366 return TOK_DQUOTE;
2367
2368 case BACKQUOTE:
2369 return TOK_BQUOTE;
2370
2371 case ',':
2372 if ((c = inchar (SCHEME_A)) == '@')
2373 return TOK_ATMARK;
2374 else
2375 {
2376 backchar (SCHEME_A_ c);
2377 return TOK_COMMA;
2378 }
2379
2380 case '#':
2381 c = inchar (SCHEME_A);
2382
2383 if (c == '(')
2384 return TOK_VEC;
2385 else if (c == '!')
2386 {
2387 while ((c = inchar (SCHEME_A)) != '\n' && c != EOF)
2388 ;
2389
2390 #if SHOW_ERROR_LINE
2391
2392 if (c == '\n' && SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
2393 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
2394
2395 #endif
2396
2397 if (c == EOF)
2398 return TOK_EOF;
2399 else
2400 return token (SCHEME_A);
2401 }
2402 else
2403 {
2404 backchar (SCHEME_A_ c);
2405
2406 if (is_one_of (" tfodxb\\", c))
2407 return TOK_SHARP_CONST;
2408 else
2409 return TOK_SHARP;
2410 }
2411
2412 default:
2413 backchar (SCHEME_A_ c);
2414 return TOK_ATOM;
2415 }
2416 }
2417
2418 /* ========== Routines for Printing ========== */
2419 #define ok_abbrev(x) (is_pair(x) && cdr(x) == NIL)
2420
2421 static void
2422 printslashstring (SCHEME_P_ char *p, int len)
2423 {
2424 int i;
2425 unsigned char *s = (unsigned char *) p;
2426
2427 putcharacter (SCHEME_A_ '"');
2428
2429 for (i = 0; i < len; i++)
2430 {
2431 if (*s == 0xff || *s == '"' || *s < ' ' || *s == '\\')
2432 {
2433 putcharacter (SCHEME_A_ '\\');
2434
2435 switch (*s)
2436 {
2437 case '"':
2438 putcharacter (SCHEME_A_ '"');
2439 break;
2440
2441 case '\n':
2442 putcharacter (SCHEME_A_ 'n');
2443 break;
2444
2445 case '\t':
2446 putcharacter (SCHEME_A_ 't');
2447 break;
2448
2449 case '\r':
2450 putcharacter (SCHEME_A_ 'r');
2451 break;
2452
2453 case '\\':
2454 putcharacter (SCHEME_A_ '\\');
2455 break;
2456
2457 default:
2458 {
2459 int d = *s / 16;
2460
2461 putcharacter (SCHEME_A_ 'x');
2462
2463 if (d < 10)
2464 putcharacter (SCHEME_A_ d + '0');
2465 else
2466 putcharacter (SCHEME_A_ d - 10 + 'A');
2467
2468 d = *s % 16;
2469
2470 if (d < 10)
2471 putcharacter (SCHEME_A_ d + '0');
2472 else
2473 putcharacter (SCHEME_A_ d - 10 + 'A');
2474 }
2475 }
2476 }
2477 else
2478 putcharacter (SCHEME_A_ * s);
2479
2480 s++;
2481 }
2482
2483 putcharacter (SCHEME_A_ '"');
2484 }
2485
2486 /* print atoms */
2487 static void
2488 printatom (SCHEME_P_ pointer l, int f)
2489 {
2490 char *p;
2491 int len;
2492
2493 atom2str (SCHEME_A_ l, f, &p, &len);
2494 putchars (SCHEME_A_ p, len);
2495 }
2496
2497 /* Uses internal buffer unless string pointer is already available */
2498 static void
2499 atom2str (SCHEME_P_ pointer l, int f, char **pp, int *plen)
2500 {
2501 char *p;
2502
2503 if (l == NIL)
2504 p = "()";
2505 else if (l == S_T)
2506 p = "#t";
2507 else if (l == S_F)
2508 p = "#f";
2509 else if (l == S_EOF)
2510 p = "#<EOF>";
2511 else if (is_port (l))
2512 p = "#<PORT>";
2513 else if (is_number (l))
2514 {
2515 p = SCHEME_V->strbuff;
2516
2517 if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */
2518 {
2519 if (is_integer (l))
2520 xnum (p, ivalue_unchecked (l));
2521 #if USE_REAL
2522 else
2523 {
2524 snprintf (p, STRBUFFSIZE, "%.10g", rvalue_unchecked (l));
2525 /* r5rs says there must be a '.' (unless 'e'?) */
2526 f = strcspn (p, ".e");
2527
2528 if (p[f] == 0)
2529 {
2530 p[f] = '.'; /* not found, so add '.0' at the end */
2531 p[f + 1] = '0';
2532 p[f + 2] = 0;
2533 }
2534 }
2535 #endif
2536 }
2537 else
2538 {
2539 long v = ivalue (l);
2540
2541 if (f == 16)
2542 xbase (p, v, 16);
2543 else if (f == 8)
2544 xbase (p, v, 8);
2545 else if (f == 2)
2546 {
2547 unsigned long b = (v < 0) ? -v : v;
2548
2549 p = &p[STRBUFFSIZE - 1];
2550 *p = 0;
2551
2552 do
2553 {
2554 *--p = (b & 1) ? '1' : '0';
2555 b >>= 1;
2556 }
2557 while (b != 0);
2558
2559 if (v < 0)
2560 *--p = '-';
2561 }
2562 }
2563 }
2564 else if (is_string (l))
2565 {
2566 if (!f)
2567 p = strvalue (l);
2568 else /* Hack, uses the fact that printing is needed */
2569 {
2570 *pp = SCHEME_V->strbuff;
2571 *plen = 0;
2572 printslashstring (SCHEME_A_ strvalue (l), strlength (l));
2573 return;
2574 }
2575 }
2576 else if (is_character (l))
2577 {
2578 int c = charvalue (l);
2579
2580 p = SCHEME_V->strbuff;
2581
2582 if (!f)
2583 {
2584 p[0] = c;
2585 p[1] = 0;
2586 }
2587 else
2588 {
2589 switch (c)
2590 {
2591 case ' ':
2592 p ="#\\space";
2593 break;
2594
2595 case '\n':
2596 p ="#\\newline";
2597 break;
2598
2599 case '\r':
2600 p ="#\\return";
2601 break;
2602
2603 case '\t':
2604 p ="#\\tab";
2605 break;
2606
2607 default:
2608 #if USE_ASCII_NAMES
2609 if (c == 127)
2610 {
2611 strcpy (p, "#\\del");
2612 break;
2613 }
2614 else if (c < 32)
2615 {
2616 strcpy (p, "#\\");
2617 strcpy (p + 2, charnames[c]);
2618 break;
2619 }
2620
2621 #else
2622
2623 if (c < 32)
2624 {
2625 strcpy (p, "#\\x");
2626 xbase (p + 3, c, 16);
2627 break;
2628 }
2629
2630 #endif
2631 strcpy (p, "#\\%");
2632 p[2] = c;
2633 break;
2634 }
2635 }
2636 }
2637 else if (is_symbol (l))
2638 p = symname (l);
2639 else if (is_proc (l))
2640 {
2641 #if USE_PRINTF
2642 p = SCHEME_V->strbuff;
2643 snprintf (p, STRBUFFSIZE, "#<%s PROCEDURE %ld>", procname (l), procnum (l));
2644 #else
2645 p = "#<PROCEDURE>";
2646 #endif
2647 }
2648 else if (is_macro (l))
2649 p = "#<MACRO>";
2650 else if (is_closure (l))
2651 p = "#<CLOSURE>";
2652 else if (is_promise (l))
2653 p = "#<PROMISE>";
2654 else if (is_foreign (l))
2655 {
2656 #if USE_PRINTF
2657 p = SCHEME_V->strbuff;
2658 snprintf (p, STRBUFFSIZE, "#<FOREIGN PROCEDURE %ld>", procnum (l));
2659 #else
2660 p = "#<FOREIGN PROCEDURE>";
2661 #endif
2662 }
2663 else if (is_continuation (l))
2664 p = "#<CONTINUATION>";
2665 else
2666 {
2667 #if USE_PRINTF
2668 p = SCHEME_V->strbuff;
2669 snprintf (p, STRBUFFSIZE, "#<ERROR %x>", (int)typeflag (l));
2670 #else
2671 p = "#<ERROR>";
2672 #endif
2673 }
2674
2675 *pp = p;
2676 *plen = strlen (p);
2677 }
2678
2679 /* ========== Routines for Evaluation Cycle ========== */
2680
2681 /* make closure. c is code. e is environment */
2682 static pointer
2683 mk_closure (SCHEME_P_ pointer c, pointer e)
2684 {
2685 pointer x = get_cell (SCHEME_A_ c, e);
2686
2687 set_typeflag (x, T_CLOSURE);
2688 set_car (x, c);
2689 set_cdr (x, e);
2690 return x;
2691 }
2692
2693 /* make continuation. */
2694 static pointer
2695 mk_continuation (SCHEME_P_ pointer d)
2696 {
2697 pointer x = get_cell (SCHEME_A_ NIL, d);
2698
2699 set_typeflag (x, T_CONTINUATION);
2700 set_cont_dump (x, d);
2701 return x;
2702 }
2703
2704 static pointer
2705 list_star (SCHEME_P_ pointer d)
2706 {
2707 pointer p, q;
2708
2709 if (cdr (d) == NIL)
2710 return car (d);
2711
2712 p = cons (car (d), cdr (d));
2713 q = p;
2714
2715 while (cdr (cdr (p)) != NIL)
2716 {
2717 d = cons (car (p), cdr (p));
2718
2719 if (cdr (cdr (p)) != NIL)
2720 p = cdr (d);
2721 }
2722
2723 set_cdr (p, car (cdr (p)));
2724 return q;
2725 }
2726
2727 /* reverse list -- produce new list */
2728 static pointer
2729 reverse (SCHEME_P_ pointer a)
2730 {
2731 /* a must be checked by gc */
2732 pointer p = NIL;
2733
2734 for (; is_pair (a); a = cdr (a))
2735 p = cons (car (a), p);
2736
2737 return p;
2738 }
2739
2740 /* reverse list --- in-place */
2741 static pointer
2742 reverse_in_place (SCHEME_P_ pointer term, pointer list)
2743 {
2744 pointer result = term;
2745 pointer p = list;
2746
2747 while (p != NIL)
2748 {
2749 pointer q = cdr (p);
2750 set_cdr (p, result);
2751 result = p;
2752 p = q;
2753 }
2754
2755 return result;
2756 }
2757
2758 /* append list -- produce new list (in reverse order) */
2759 static pointer
2760 revappend (SCHEME_P_ pointer a, pointer b)
2761 {
2762 pointer result = a;
2763 pointer p = b;
2764
2765 while (is_pair (p))
2766 {
2767 result = cons (car (p), result);
2768 p = cdr (p);
2769 }
2770
2771 if (p == NIL)
2772 return result;
2773
2774 return S_F; /* signal an error */
2775 }
2776
2777 /* equivalence of atoms */
2778 int
2779 eqv (pointer a, pointer b)
2780 {
2781 if (is_string (a))
2782 {
2783 if (is_string (b))
2784 return strvalue (a) == strvalue (b);
2785 else
2786 return 0;
2787 }
2788 else if (is_number (a))
2789 {
2790 if (is_number (b))
2791 return num_cmp (nvalue (a), nvalue (b)) == 0;
2792
2793 return 0;
2794 }
2795 else if (is_character (a))
2796 {
2797 if (is_character (b))
2798 return charvalue (a) == charvalue (b);
2799 else
2800 return 0;
2801 }
2802 else if (is_port (a))
2803 {
2804 if (is_port (b))
2805 return a == b;
2806 else
2807 return 0;
2808 }
2809 else if (is_proc (a))
2810 {
2811 if (is_proc (b))
2812 return procnum (a) == procnum (b);
2813 else
2814 return 0;
2815 }
2816 else
2817 return a == b;
2818 }
2819
2820 /* true or false value macro */
2821
2822 /* () is #t in R5RS */
2823 #define is_true(p) ((p) != S_F)
2824 #define is_false(p) ((p) == S_F)
2825
2826 /* ========== Environment implementation ========== */
2827
2828 #ifndef USE_ALIST_ENV
2829
2830 /*
2831 * In this implementation, each frame of the environment may be
2832 * a hash table: a vector of alists hashed by variable name.
2833 * In practice, we use a vector only for the initial frame;
2834 * subsequent frames are too small and transient for the lookup
2835 * speed to out-weigh the cost of making a new vector.
2836 */
2837
2838 static void
2839 new_frame_in_env (SCHEME_P_ pointer old_env)
2840 {
2841 pointer new_frame;
2842
2843 /* The interaction-environment has about 300 variables in it. */
2844 if (old_env == NIL)
2845 new_frame = mk_vector (SCHEME_A_ 461);
2846 else
2847 new_frame = NIL;
2848
2849 SCHEME_V->envir = immutable_cons (new_frame, old_env);
2850 setenvironment (SCHEME_V->envir);
2851 }
2852
2853 static uint32_t
2854 sym_hash (pointer sym, uint32_t size)
2855 {
2856 uintptr_t ptr = (uintptr_t)sym;
2857
2858 #if 0
2859 /* table size is prime, so why mix */
2860 ptr += ptr >> 32;
2861 ptr += ptr >> 16;
2862 ptr += ptr >> 8;
2863 #endif
2864
2865 return ptr % size;
2866 }
2867
2868 ecb_inline void
2869 new_slot_spec_in_env (SCHEME_P_ pointer env, pointer variable, pointer value)
2870 {
2871 pointer slot = immutable_cons (variable, value);
2872
2873 if (is_vector (car (env)))
2874 {
2875 int location = sym_hash (variable, veclength (car (env)));
2876 vector_set (car (env), location, immutable_cons (slot, vector_get (car (env), location)));
2877 }
2878 else
2879 set_car (env, immutable_cons (slot, car (env)));
2880 }
2881
2882 static pointer
2883 find_slot_in_env (SCHEME_P_ pointer env, pointer hdl, int all)
2884 {
2885 pointer x, y;
2886
2887 for (x = env; x != NIL; x = cdr (x))
2888 {
2889 if (is_vector (car (x)))
2890 {
2891 int location = sym_hash (hdl, veclength (car (x)));
2892 y = vector_get (car (x), location);
2893 }
2894 else
2895 y = car (x);
2896
2897 for (; y != NIL; y = cdr (y))
2898 if (caar (y) == hdl)
2899 break;
2900
2901 if (y != NIL)
2902 return car (y);
2903
2904 if (!all)
2905 break;
2906 }
2907
2908 return NIL;
2909 }
2910
2911 #else /* USE_ALIST_ENV */
2912
2913 ecb_inline void
2914 new_frame_in_env (SCHEME_P_ pointer old_env)
2915 {
2916 SCHEME_V->envir = immutable_cons (NIL, old_env);
2917 setenvironment (SCHEME_V->envir);
2918 }
2919
2920 ecb_inline void
2921 new_slot_spec_in_env (SCHEME_P_ pointer env, pointer variable, pointer value)
2922 {
2923 set_car (env, immutable_cons (immutable_cons (variable, value), car (env)));
2924 }
2925
2926 static pointer
2927 find_slot_in_env (SCHEME_P_ pointer env, pointer hdl, int all)
2928 {
2929 pointer x, y;
2930
2931 for (x = env; x != NIL; x = cdr (x))
2932 {
2933 for (y = car (x); y != NIL; y = cdr (y))
2934 if (caar (y) == hdl)
2935 break;
2936
2937 if (y != NIL)
2938 return car (y);
2939 break;
2940
2941 if (!all)
2942 break;
2943 }
2944
2945 return NIL;
2946 }
2947
2948 #endif /* USE_ALIST_ENV else */
2949
2950 ecb_inline void
2951 new_slot_in_env (SCHEME_P_ pointer variable, pointer value)
2952 {
2953 assert (is_symbol (variable));//TODO: bug in current-ws/OP_LET2
2954 new_slot_spec_in_env (SCHEME_A_ SCHEME_V->envir, variable, value);
2955 }
2956
2957 ecb_inline void
2958 set_slot_in_env (SCHEME_P_ pointer slot, pointer value)
2959 {
2960 set_cdr (slot, value);
2961 }
2962
2963 ecb_inline pointer
2964 slot_value_in_env (pointer slot)
2965 {
2966 return cdr (slot);
2967 }
2968
2969 /* ========== Evaluation Cycle ========== */
2970
2971 static int
2972 xError_1 (SCHEME_P_ const char *s, pointer a)
2973 {
2974 #if USE_ERROR_HOOK
2975 pointer x;
2976 pointer hdl = SCHEME_V->ERROR_HOOK;
2977 #endif
2978
2979 #if USE_PRINTF
2980 #if SHOW_ERROR_LINE
2981 char sbuf[STRBUFFSIZE];
2982
2983 /* make sure error is not in REPL */
2984 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)
2985 {
2986 int ln = SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line;
2987 const char *fname = SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.filename;
2988
2989 /* should never happen */
2990 if (!fname)
2991 fname = "<unknown>";
2992
2993 /* we started from 0 */
2994 ln++;
2995 snprintf (sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s);
2996
2997 s = sbuf;
2998 }
2999 #endif
3000 #endif
3001
3002 #if USE_ERROR_HOOK
3003 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, hdl, 1);
3004
3005 if (x != NIL)
3006 {
3007 pointer code = a
3008 ? cons (cons (SCHEME_V->QUOTE, cons (a, NIL)), NIL)
3009 : NIL;
3010
3011 code = cons (mk_string (SCHEME_A_ s), code);
3012 setimmutable (car (code));
3013 SCHEME_V->code = cons (slot_value_in_env (x), code);
3014 SCHEME_V->op = OP_EVAL;
3015
3016 return 0;
3017 }
3018 #endif
3019
3020 if (a)
3021 SCHEME_V->args = cons (a, NIL);
3022 else
3023 SCHEME_V->args = NIL;
3024
3025 SCHEME_V->args = cons (mk_string (SCHEME_A_ s), SCHEME_V->args);
3026 setimmutable (car (SCHEME_V->args));
3027 SCHEME_V->op = OP_ERR0;
3028
3029 return 0;
3030 }
3031
3032 #define Error_1(s, a) return xError_1(SCHEME_A_ USE_ERROR_CHECKING ? s : "", a)
3033 #define Error_0(s) Error_1 (s, 0)
3034
3035 /* Too small to turn into function */
3036 #define BEGIN do {
3037 #define END } while (0)
3038 #define s_goto(a) BEGIN \
3039 SCHEME_V->op = a; \
3040 return 0; END
3041
3042 #define s_return(a) return xs_return (SCHEME_A_ a)
3043
3044 #ifndef USE_SCHEME_STACK
3045
3046 /* this structure holds all the interpreter's registers */
3047 struct dump_stack_frame
3048 {
3049 enum scheme_opcodes op;
3050 pointer args;
3051 pointer envir;
3052 pointer code;
3053 };
3054
3055 # define STACK_GROWTH 3
3056
3057 static void
3058 s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3059 {
3060 int nframes = (uintptr_t)SCHEME_V->dump;
3061 struct dump_stack_frame *next_frame;
3062
3063 /* enough room for the next frame? */
3064 if (nframes >= SCHEME_V->dump_size)
3065 {
3066 SCHEME_V->dump_size += STACK_GROWTH;
3067 SCHEME_V->dump_base = realloc (SCHEME_V->dump_base, sizeof (struct dump_stack_frame) * SCHEME_V->dump_size);
3068 }
3069
3070 next_frame = SCHEME_V->dump_base + nframes;
3071
3072 next_frame->op = op;
3073 next_frame->args = args;
3074 next_frame->envir = SCHEME_V->envir;
3075 next_frame->code = code;
3076
3077 SCHEME_V->dump = (pointer)(uintptr_t)(nframes + 1);
3078 }
3079
3080 static int
3081 xs_return (SCHEME_P_ pointer a)
3082 {
3083 int nframes = (uintptr_t)SCHEME_V->dump;
3084 struct dump_stack_frame *frame;
3085
3086 SCHEME_V->value = a;
3087
3088 if (nframes <= 0)
3089 return -1;
3090
3091 frame = &SCHEME_V->dump_base[--nframes];
3092 SCHEME_V->op = frame->op;
3093 SCHEME_V->args = frame->args;
3094 SCHEME_V->envir = frame->envir;
3095 SCHEME_V->code = frame->code;
3096 SCHEME_V->dump = (pointer)(uintptr_t)nframes;
3097
3098 return 0;
3099 }
3100
3101 ecb_inline void
3102 dump_stack_reset (SCHEME_P)
3103 {
3104 /* in this implementation, SCHEME_V->dump is the number of frames on the stack */
3105 SCHEME_V->dump = (pointer)+0;
3106 }
3107
3108 ecb_inline void
3109 dump_stack_initialize (SCHEME_P)
3110 {
3111 SCHEME_V->dump_size = 0;
3112 SCHEME_V->dump_base = 0;
3113 dump_stack_reset (SCHEME_A);
3114 }
3115
3116 static void
3117 dump_stack_free (SCHEME_P)
3118 {
3119 free (SCHEME_V->dump_base);
3120 SCHEME_V->dump_base = 0;
3121 SCHEME_V->dump = (pointer)0;
3122 SCHEME_V->dump_size = 0;
3123 }
3124
3125 static void
3126 dump_stack_mark (SCHEME_P)
3127 {
3128 int nframes = (uintptr_t)SCHEME_V->dump;
3129 int i;
3130
3131 for (i = 0; i < nframes; i++)
3132 {
3133 struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3134
3135 mark (frame->args);
3136 mark (frame->envir);
3137 mark (frame->code);
3138 }
3139 }
3140
3141 static pointer
3142 ss_get_cont (SCHEME_P)
3143 {
3144 int nframes = (uintptr_t)SCHEME_V->dump;
3145 int i;
3146
3147 pointer cont = NIL;
3148
3149 for (i = nframes; i--; )
3150 {
3151 struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3152
3153 cont = cons (mk_integer (SCHEME_A_ frame->op),
3154 cons (frame->args,
3155 cons (frame->envir,
3156 cons (frame->code,
3157 cont))));
3158 }
3159
3160 return cont;
3161 }
3162
3163 static void
3164 ss_set_cont (SCHEME_P_ pointer cont)
3165 {
3166 int i = 0;
3167 struct dump_stack_frame *frame = SCHEME_V->dump_base;
3168
3169 while (cont != NIL)
3170 {
3171 frame->op = ivalue_unchecked (car (cont)); cont = cdr (cont);
3172 frame->args = car (cont) ; cont = cdr (cont);
3173 frame->envir = car (cont) ; cont = cdr (cont);
3174 frame->code = car (cont) ; cont = cdr (cont);
3175
3176 ++frame;
3177 ++i;
3178 }
3179
3180 SCHEME_V->dump = (pointer)(uintptr_t)i;
3181 }
3182
3183 #else
3184
3185 ecb_inline void
3186 dump_stack_reset (SCHEME_P)
3187 {
3188 SCHEME_V->dump = NIL;
3189 }
3190
3191 ecb_inline void
3192 dump_stack_initialize (SCHEME_P)
3193 {
3194 dump_stack_reset (SCHEME_A);
3195 }
3196
3197 static void
3198 dump_stack_free (SCHEME_P)
3199 {
3200 SCHEME_V->dump = NIL;
3201 }
3202
3203 static int
3204 xs_return (SCHEME_P_ pointer a)
3205 {
3206 pointer dump = SCHEME_V->dump;
3207
3208 SCHEME_V->value = a;
3209
3210 if (dump == NIL)
3211 return -1;
3212
3213 SCHEME_V->op = ivalue_unchecked (car (dump)); dump = cdr (dump);
3214 SCHEME_V->args = car (dump) ; dump = cdr (dump);
3215 SCHEME_V->envir = car (dump) ; dump = cdr (dump);
3216 SCHEME_V->code = car (dump) ; dump = cdr (dump);
3217
3218 SCHEME_V->dump = dump;
3219
3220 return 0;
3221 }
3222
3223 static void
3224 s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3225 {
3226 SCHEME_V->dump = cons (mk_integer (SCHEME_A_ op),
3227 cons (args,
3228 cons (SCHEME_V->envir,
3229 cons (code,
3230 SCHEME_V->dump))));
3231 }
3232
3233 static void
3234 dump_stack_mark (SCHEME_P)
3235 {
3236 mark (SCHEME_V->dump);
3237 }
3238
3239 static pointer
3240 ss_get_cont (SCHEME_P)
3241 {
3242 return SCHEME_V->dump;
3243 }
3244
3245 static void
3246 ss_set_cont (SCHEME_P_ pointer cont)
3247 {
3248 SCHEME_V->dump = cont;
3249 }
3250
3251 #endif
3252
3253 #define s_retbool(tf) s_return ((tf) ? S_T : S_F)
3254
3255 #if EXPERIMENT
3256 static int
3257 debug (SCHEME_P_ int indent, pointer x)
3258 {
3259 int c;
3260
3261 if (is_syntax (x))
3262 {
3263 printf ("%*ssyntax<%s,%d>\n", indent, "", syntaxname(x),syntaxnum(x));
3264 return 8 + 8;
3265 }
3266
3267 if (x == NIL)
3268 {
3269 printf ("%*sNIL\n", indent, "");
3270 return 3;
3271 }
3272
3273 switch (type (x))
3274 {
3275 case T_INTEGER:
3276 printf ("%*sI<%d>%p\n", indent, "", (int)ivalue_unchecked (x), x);
3277 return 32+8;
3278
3279 case T_SYMBOL:
3280 printf ("%*sS<%s>\n", indent, "", symname (x));
3281 return 24+8;
3282
3283 case T_CLOSURE:
3284 printf ("%*sS<%s>\n", indent, "", "closure");
3285 debug (SCHEME_A_ indent + 3, cdr(x));
3286 return 32 + debug (SCHEME_A_ indent + 3, car (x));
3287
3288 case T_PAIR:
3289 printf ("%*spair %p %p\n", indent, "", car(x),cdr(x));
3290 c = debug (SCHEME_A_ indent + 3, car (x));
3291 c += debug (SCHEME_A_ indent + 3, cdr (x));
3292 return c + 1;
3293
3294 case T_PORT:
3295 printf ("%*sS<%s>\n", indent, "", "port");
3296 return 24+8;
3297
3298 case T_VECTOR:
3299 printf ("%*sS<%s>\n", indent, "", "vector");
3300 return 24+8;
3301
3302 case T_ENVIRONMENT:
3303 printf ("%*sS<%s>\n", indent, "", "environment");
3304 return 0 + debug (SCHEME_A_ indent + 3, car (x));
3305
3306 default:
3307 printf ("unhandled type %d\n", type (x));
3308 break;
3309 }
3310 }
3311 #endif
3312
3313 static int
3314 opexe_0 (SCHEME_P_ enum scheme_opcodes op)
3315 {
3316 pointer args = SCHEME_V->args;
3317 pointer x, y;
3318
3319 switch (op)
3320 {
3321 #if EXPERIMENT //D
3322 case OP_DEBUG:
3323 printf ("len = %d\n", debug (SCHEME_A_ 0, args) / 8);
3324 printf ("\n");
3325 s_return (S_T);
3326 #endif
3327 case OP_LOAD: /* load */
3328 if (file_interactive (SCHEME_A))
3329 {
3330 xwrstr ("Loading "); xwrstr (strvalue (car (args))); xwrstr ("\n");
3331 //D fprintf (SCHEME_V->outport->object.port->rep.stdio.file, "Loading %s\n", strvalue (car (args)));
3332 }
3333
3334 if (!file_push (SCHEME_A_ strvalue (car (args))))
3335 Error_1 ("unable to open", car (args));
3336 else
3337 {
3338 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
3339 s_goto (OP_T0LVL);
3340 }
3341
3342 case OP_T0LVL: /* top level */
3343
3344 /* If we reached the end of file, this loop is done. */
3345 if (SCHEME_V->loadport->object.port->kind & port_saw_EOF)
3346 {
3347 if (SCHEME_V->file_i == 0)
3348 {
3349 SCHEME_V->args = NIL;
3350 s_goto (OP_QUIT);
3351 }
3352 else
3353 {
3354 file_pop (SCHEME_A);
3355 s_return (SCHEME_V->value);
3356 }
3357
3358 /* NOTREACHED */
3359 }
3360
3361 /* If interactive, be nice to user. */
3362 if (file_interactive (SCHEME_A))
3363 {
3364 SCHEME_V->envir = SCHEME_V->global_env;
3365 dump_stack_reset (SCHEME_A);
3366 putstr (SCHEME_A_ "\n");
3367 putstr (SCHEME_A_ prompt);
3368 }
3369
3370 /* Set up another iteration of REPL */
3371 SCHEME_V->nesting = 0;
3372 SCHEME_V->save_inport = SCHEME_V->inport;
3373 SCHEME_V->inport = SCHEME_V->loadport;
3374 s_save (SCHEME_A_ OP_T0LVL, NIL, NIL);
3375 s_save (SCHEME_A_ OP_VALUEPRINT, NIL, NIL);
3376 s_save (SCHEME_A_ OP_T1LVL, NIL, NIL);
3377 s_goto (OP_READ_INTERNAL);
3378
3379 case OP_T1LVL: /* top level */
3380 SCHEME_V->code = SCHEME_V->value;
3381 SCHEME_V->inport = SCHEME_V->save_inport;
3382 s_goto (OP_EVAL);
3383
3384 case OP_READ_INTERNAL: /* internal read */
3385 SCHEME_V->tok = token (SCHEME_A);
3386
3387 if (SCHEME_V->tok == TOK_EOF)
3388 s_return (S_EOF);
3389
3390 s_goto (OP_RDSEXPR);
3391
3392 case OP_GENSYM:
3393 s_return (gensym (SCHEME_A));
3394
3395 case OP_VALUEPRINT: /* print evaluation result */
3396
3397 /* OP_VALUEPRINT is always pushed, because when changing from
3398 non-interactive to interactive mode, it needs to be
3399 already on the stack */
3400 #if USE_TRACING
3401 if (SCHEME_V->tracing)
3402 putstr (SCHEME_A_ "\nGives: ");
3403 #endif
3404
3405 if (file_interactive (SCHEME_A))
3406 {
3407 SCHEME_V->print_flag = 1;
3408 SCHEME_V->args = SCHEME_V->value;
3409 s_goto (OP_P0LIST);
3410 }
3411 else
3412 s_return (SCHEME_V->value);
3413
3414 case OP_EVAL: /* main part of evaluation */
3415 #if USE_TRACING
3416 if (SCHEME_V->tracing)
3417 {
3418 /*s_save(SCHEME_A_ OP_VALUEPRINT,NIL,NIL); */
3419 s_save (SCHEME_A_ OP_REAL_EVAL, args, SCHEME_V->code);
3420 SCHEME_V->args = SCHEME_V->code;
3421 putstr (SCHEME_A_ "\nEval: ");
3422 s_goto (OP_P0LIST);
3423 }
3424
3425 /* fall through */
3426
3427 case OP_REAL_EVAL:
3428 #endif
3429 if (is_symbol (SCHEME_V->code)) /* symbol */
3430 {
3431 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3432
3433 if (x != NIL)
3434 s_return (slot_value_in_env (x));
3435 else
3436 Error_1 ("eval: unbound variable:", SCHEME_V->code);
3437 }
3438 else if (is_pair (SCHEME_V->code))
3439 {
3440 x = car (SCHEME_V->code);
3441
3442 if (is_syntax (x)) /* SYNTAX */
3443 {
3444 SCHEME_V->code = cdr (SCHEME_V->code);
3445 s_goto (syntaxnum (x));
3446 }
3447 else /* first, eval top element and eval arguments */
3448 {
3449 s_save (SCHEME_A_ OP_E0ARGS, NIL, SCHEME_V->code);
3450 /* If no macros => s_save(SCHEME_A_ OP_E1ARGS, NIL, cdr(SCHEME_V->code)); */
3451 SCHEME_V->code = x;
3452 s_goto (OP_EVAL);
3453 }
3454 }
3455 else
3456 s_return (SCHEME_V->code);
3457
3458 case OP_E0ARGS: /* eval arguments */
3459 if (ecb_expect_false (is_macro (SCHEME_V->value))) /* macro expansion */
3460 {
3461 s_save (SCHEME_A_ OP_DOMACRO, NIL, NIL);
3462 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3463 SCHEME_V->code = SCHEME_V->value;
3464 s_goto (OP_APPLY);
3465 }
3466 else
3467 {
3468 SCHEME_V->code = cdr (SCHEME_V->code);
3469 s_goto (OP_E1ARGS);
3470 }
3471
3472 case OP_E1ARGS: /* eval arguments */
3473 args = cons (SCHEME_V->value, args);
3474
3475 if (is_pair (SCHEME_V->code)) /* continue */
3476 {
3477 s_save (SCHEME_A_ OP_E1ARGS, args, cdr (SCHEME_V->code));
3478 SCHEME_V->code = car (SCHEME_V->code);
3479 SCHEME_V->args = NIL;
3480 s_goto (OP_EVAL);
3481 }
3482 else /* end */
3483 {
3484 args = reverse_in_place (SCHEME_A_ NIL, args);
3485 SCHEME_V->code = car (args);
3486 SCHEME_V->args = cdr (args);
3487 s_goto (OP_APPLY);
3488 }
3489
3490 #if USE_TRACING
3491
3492 case OP_TRACING:
3493 {
3494 int tr = SCHEME_V->tracing;
3495
3496 SCHEME_V->tracing = ivalue_unchecked (car (args));
3497 s_return (mk_integer (SCHEME_A_ tr));
3498 }
3499
3500 #endif
3501
3502 case OP_APPLY: /* apply 'code' to 'args' */
3503 #if USE_TRACING
3504 if (SCHEME_V->tracing)
3505 {
3506 s_save (SCHEME_A_ OP_REAL_APPLY, args, SCHEME_V->code);
3507 SCHEME_V->print_flag = 1;
3508 /* args=cons(SCHEME_V->code,args); */
3509 putstr (SCHEME_A_ "\nApply to: ");
3510 s_goto (OP_P0LIST);
3511 }
3512
3513 /* fall through */
3514
3515 case OP_REAL_APPLY:
3516 #endif
3517 if (is_proc (SCHEME_V->code))
3518 s_goto (procnum (SCHEME_V->code)); /* PROCEDURE */
3519 else if (is_foreign (SCHEME_V->code))
3520 {
3521 /* Keep nested calls from GC'ing the arglist */
3522 push_recent_alloc (SCHEME_A_ args, NIL);
3523 x = SCHEME_V->code->object.ff (SCHEME_A_ args);
3524
3525 s_return (x);
3526 }
3527 else if (is_closure (SCHEME_V->code) || is_macro (SCHEME_V->code) || is_promise (SCHEME_V->code)) /* CLOSURE */
3528 {
3529 /* Should not accept promise */
3530 /* make environment */
3531 new_frame_in_env (SCHEME_A_ closure_env (SCHEME_V->code));
3532
3533 for (x = car (closure_code (SCHEME_V->code)), y = args; is_pair (x); x = cdr (x), y = cdr (y))
3534 {
3535 if (y == NIL)
3536 Error_0 ("not enough arguments");
3537 else
3538 new_slot_in_env (SCHEME_A_ car (x), car (y));
3539 }
3540
3541 if (x == NIL)
3542 {
3543 /*--
3544 * if (y != NIL) {
3545 * Error_0("too many arguments");
3546 * }
3547 */
3548 }
3549 else if (is_symbol (x))
3550 new_slot_in_env (SCHEME_A_ x, y);
3551 else
3552 Error_1 ("syntax error in closure: not a symbol:", x);
3553
3554 SCHEME_V->code = cdr (closure_code (SCHEME_V->code));
3555 SCHEME_V->args = NIL;
3556 s_goto (OP_BEGIN);
3557 }
3558 else if (is_continuation (SCHEME_V->code)) /* CONTINUATION */
3559 {
3560 ss_set_cont (SCHEME_A_ cont_dump (SCHEME_V->code));
3561 s_return (args != NIL ? car (args) : NIL);
3562 }
3563 else
3564 Error_0 ("illegal function");
3565
3566 case OP_DOMACRO: /* do macro */
3567 SCHEME_V->code = SCHEME_V->value;
3568 s_goto (OP_EVAL);
3569
3570 #if 1
3571
3572 case OP_LAMBDA: /* lambda */
3573 /* If the hook is defined, apply it to SCHEME_V->code, otherwise
3574 set SCHEME_V->value fall thru */
3575 {
3576 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->COMPILE_HOOK, 1);
3577
3578 if (f != NIL)
3579 {
3580 s_save (SCHEME_A_ OP_LAMBDA1, args, SCHEME_V->code);
3581 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3582 SCHEME_V->code = slot_value_in_env (f);
3583 s_goto (OP_APPLY);
3584 }
3585
3586 SCHEME_V->value = SCHEME_V->code;
3587 /* Fallthru */
3588 }
3589
3590 case OP_LAMBDA1:
3591 s_return (mk_closure (SCHEME_A_ SCHEME_V->value, SCHEME_V->envir));
3592
3593 #else
3594
3595 case OP_LAMBDA: /* lambda */
3596 s_return (mk_closure (SCHEME_A_ SCHEME_V->code, SCHEME_V->envir));
3597
3598 #endif
3599
3600 case OP_MKCLOSURE: /* make-closure */
3601 x = car (args);
3602
3603 if (car (x) == SCHEME_V->LAMBDA)
3604 x = cdr (x);
3605
3606 if (cdr (args) == NIL)
3607 y = SCHEME_V->envir;
3608 else
3609 y = cadr (args);
3610
3611 s_return (mk_closure (SCHEME_A_ x, y));
3612
3613 case OP_QUOTE: /* quote */
3614 s_return (car (SCHEME_V->code));
3615
3616 case OP_DEF0: /* define */
3617 if (is_immutable (car (SCHEME_V->code)))
3618 Error_1 ("define: unable to alter immutable", car (SCHEME_V->code));
3619
3620 if (is_pair (car (SCHEME_V->code)))
3621 {
3622 x = caar (SCHEME_V->code);
3623 SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3624 }
3625 else
3626 {
3627 x = car (SCHEME_V->code);
3628 SCHEME_V->code = cadr (SCHEME_V->code);
3629 }
3630
3631 if (!is_symbol (x))
3632 Error_0 ("variable is not a symbol");
3633
3634 s_save (SCHEME_A_ OP_DEF1, NIL, x);
3635 s_goto (OP_EVAL);
3636
3637 case OP_DEF1: /* define */
3638 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3639
3640 if (x != NIL)
3641 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3642 else
3643 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3644
3645 s_return (SCHEME_V->code);
3646
3647
3648 case OP_DEFP: /* defined? */
3649 x = SCHEME_V->envir;
3650
3651 if (cdr (args) != NIL)
3652 x = cadr (args);
3653
3654 s_retbool (find_slot_in_env (SCHEME_A_ x, car (args), 1) != NIL);
3655
3656 case OP_SET0: /* set! */
3657 if (is_immutable (car (SCHEME_V->code)))
3658 Error_1 ("set!: unable to alter immutable variable", car (SCHEME_V->code));
3659
3660 s_save (SCHEME_A_ OP_SET1, NIL, car (SCHEME_V->code));
3661 SCHEME_V->code = cadr (SCHEME_V->code);
3662 s_goto (OP_EVAL);
3663
3664 case OP_SET1: /* set! */
3665 y = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3666
3667 if (y != NIL)
3668 {
3669 set_slot_in_env (SCHEME_A_ y, SCHEME_V->value);
3670 s_return (SCHEME_V->value);
3671 }
3672 else
3673 Error_1 ("set!: unbound variable:", SCHEME_V->code);
3674
3675
3676 case OP_BEGIN: /* begin */
3677 if (!is_pair (SCHEME_V->code))
3678 s_return (SCHEME_V->code);
3679
3680 if (cdr (SCHEME_V->code) != NIL)
3681 s_save (SCHEME_A_ OP_BEGIN, NIL, cdr (SCHEME_V->code));
3682
3683 SCHEME_V->code = car (SCHEME_V->code);
3684 s_goto (OP_EVAL);
3685
3686 case OP_IF0: /* if */
3687 s_save (SCHEME_A_ OP_IF1, NIL, cdr (SCHEME_V->code));
3688 SCHEME_V->code = car (SCHEME_V->code);
3689 s_goto (OP_EVAL);
3690
3691 case OP_IF1: /* if */
3692 if (is_true (SCHEME_V->value))
3693 SCHEME_V->code = car (SCHEME_V->code);
3694 else
3695 SCHEME_V->code = cadr (SCHEME_V->code); /* (if #f 1) ==> () because * car(NIL) = NIL */
3696 s_goto (OP_EVAL);
3697
3698 case OP_LET0: /* let */
3699 SCHEME_V->args = NIL;
3700 SCHEME_V->value = SCHEME_V->code;
3701 SCHEME_V->code = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code);
3702 s_goto (OP_LET1);
3703
3704 case OP_LET1: /* let (calculate parameters) */
3705 args = cons (SCHEME_V->value, args);
3706
3707 if (is_pair (SCHEME_V->code)) /* continue */
3708 {
3709 if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3710 Error_1 ("Bad syntax of binding spec in let :", car (SCHEME_V->code));
3711
3712 s_save (SCHEME_A_ OP_LET1, args, cdr (SCHEME_V->code));
3713 SCHEME_V->code = cadar (SCHEME_V->code);
3714 SCHEME_V->args = NIL;
3715 s_goto (OP_EVAL);
3716 }
3717 else /* end */
3718 {
3719 args = reverse_in_place (SCHEME_A_ NIL, args);
3720 SCHEME_V->code = car (args);
3721 SCHEME_V->args = cdr (args);
3722 s_goto (OP_LET2);
3723 }
3724
3725 case OP_LET2: /* let */
3726 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3727
3728 for (x = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code), y = args;
3729 y != NIL; x = cdr (x), y = cdr (y))
3730 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3731
3732 if (is_symbol (car (SCHEME_V->code))) /* named let */
3733 {
3734 for (x = cadr (SCHEME_V->code), args = NIL; x != NIL; x = cdr (x))
3735 {
3736 if (!is_pair (x))
3737 Error_1 ("Bad syntax of binding in let :", x);
3738
3739 if (!is_list (SCHEME_A_ car (x)))
3740 Error_1 ("Bad syntax of binding in let :", car (x));
3741
3742 args = cons (caar (x), args);
3743 }
3744
3745 x = mk_closure (SCHEME_A_ cons (reverse_in_place (SCHEME_A_ NIL, args), cddr (SCHEME_V->code)),
3746 SCHEME_V->envir);
3747 new_slot_in_env (SCHEME_A_ car (SCHEME_V->code), x);
3748 SCHEME_V->code = cddr (SCHEME_V->code);
3749 }
3750 else
3751 {
3752 SCHEME_V->code = cdr (SCHEME_V->code);
3753 }
3754
3755 SCHEME_V->args = NIL;
3756 s_goto (OP_BEGIN);
3757
3758 case OP_LET0AST: /* let* */
3759 if (car (SCHEME_V->code) == NIL)
3760 {
3761 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3762 SCHEME_V->code = cdr (SCHEME_V->code);
3763 s_goto (OP_BEGIN);
3764 }
3765
3766 if (!is_pair (car (SCHEME_V->code)) || !is_pair (caar (SCHEME_V->code)) || !is_pair (cdaar (SCHEME_V->code)))
3767 Error_1 ("Bad syntax of binding spec in let* :", car (SCHEME_V->code));
3768
3769 s_save (SCHEME_A_ OP_LET1AST, cdr (SCHEME_V->code), car (SCHEME_V->code));
3770 SCHEME_V->code = car (cdaar (SCHEME_V->code));
3771 s_goto (OP_EVAL);
3772
3773 case OP_LET1AST: /* let* (make new frame) */
3774 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3775 s_goto (OP_LET2AST);
3776
3777 case OP_LET2AST: /* let* (calculate parameters) */
3778 new_slot_in_env (SCHEME_A_ caar (SCHEME_V->code), SCHEME_V->value);
3779 SCHEME_V->code = cdr (SCHEME_V->code);
3780
3781 if (is_pair (SCHEME_V->code)) /* continue */
3782 {
3783 s_save (SCHEME_A_ OP_LET2AST, args, SCHEME_V->code);
3784 SCHEME_V->code = cadar (SCHEME_V->code);
3785 SCHEME_V->args = NIL;
3786 s_goto (OP_EVAL);
3787 }
3788 else /* end */
3789 {
3790 SCHEME_V->code = args;
3791 SCHEME_V->args = NIL;
3792 s_goto (OP_BEGIN);
3793 }
3794
3795 case OP_LET0REC: /* letrec */
3796 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3797 SCHEME_V->args = NIL;
3798 SCHEME_V->value = SCHEME_V->code;
3799 SCHEME_V->code = car (SCHEME_V->code);
3800 s_goto (OP_LET1REC);
3801
3802 case OP_LET1REC: /* letrec (calculate parameters) */
3803 args = cons (SCHEME_V->value, args);
3804
3805 if (is_pair (SCHEME_V->code)) /* continue */
3806 {
3807 if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3808 Error_1 ("Bad syntax of binding spec in letrec :", car (SCHEME_V->code));
3809
3810 s_save (SCHEME_A_ OP_LET1REC, args, cdr (SCHEME_V->code));
3811 SCHEME_V->code = cadar (SCHEME_V->code);
3812 SCHEME_V->args = NIL;
3813 s_goto (OP_EVAL);
3814 }
3815 else /* end */
3816 {
3817 args = reverse_in_place (SCHEME_A_ NIL, args);
3818 SCHEME_V->code = car (args);
3819 SCHEME_V->args = cdr (args);
3820 s_goto (OP_LET2REC);
3821 }
3822
3823 case OP_LET2REC: /* letrec */
3824 for (x = car (SCHEME_V->code), y = args; y != NIL; x = cdr (x), y = cdr (y))
3825 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3826
3827 SCHEME_V->code = cdr (SCHEME_V->code);
3828 SCHEME_V->args = NIL;
3829 s_goto (OP_BEGIN);
3830
3831 case OP_COND0: /* cond */
3832 if (!is_pair (SCHEME_V->code))
3833 Error_0 ("syntax error in cond");
3834
3835 s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3836 SCHEME_V->code = caar (SCHEME_V->code);
3837 s_goto (OP_EVAL);
3838
3839 case OP_COND1: /* cond */
3840 if (is_true (SCHEME_V->value))
3841 {
3842 if ((SCHEME_V->code = cdar (SCHEME_V->code)) == NIL)
3843 s_return (SCHEME_V->value);
3844
3845 if (car (SCHEME_V->code) == SCHEME_V->FEED_TO)
3846 {
3847 if (!is_pair (cdr (SCHEME_V->code)))
3848 Error_0 ("syntax error in cond");
3849
3850 x = cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL));
3851 SCHEME_V->code = cons (cadr (SCHEME_V->code), cons (x, NIL));
3852 s_goto (OP_EVAL);
3853 }
3854
3855 s_goto (OP_BEGIN);
3856 }
3857 else
3858 {
3859 if ((SCHEME_V->code = cdr (SCHEME_V->code)) == NIL)
3860 s_return (NIL);
3861 else
3862 {
3863 s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3864 SCHEME_V->code = caar (SCHEME_V->code);
3865 s_goto (OP_EVAL);
3866 }
3867 }
3868
3869 case OP_DELAY: /* delay */
3870 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3871 set_typeflag (x, T_PROMISE);
3872 s_return (x);
3873
3874 case OP_AND0: /* and */
3875 if (SCHEME_V->code == NIL)
3876 s_return (S_T);
3877
3878 s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3879 SCHEME_V->code = car (SCHEME_V->code);
3880 s_goto (OP_EVAL);
3881
3882 case OP_AND1: /* and */
3883 if (is_false (SCHEME_V->value))
3884 s_return (SCHEME_V->value);
3885 else if (SCHEME_V->code == NIL)
3886 s_return (SCHEME_V->value);
3887 else
3888 {
3889 s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3890 SCHEME_V->code = car (SCHEME_V->code);
3891 s_goto (OP_EVAL);
3892 }
3893
3894 case OP_OR0: /* or */
3895 if (SCHEME_V->code == NIL)
3896 s_return (S_F);
3897
3898 s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3899 SCHEME_V->code = car (SCHEME_V->code);
3900 s_goto (OP_EVAL);
3901
3902 case OP_OR1: /* or */
3903 if (is_true (SCHEME_V->value))
3904 s_return (SCHEME_V->value);
3905 else if (SCHEME_V->code == NIL)
3906 s_return (SCHEME_V->value);
3907 else
3908 {
3909 s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3910 SCHEME_V->code = car (SCHEME_V->code);
3911 s_goto (OP_EVAL);
3912 }
3913
3914 case OP_C0STREAM: /* cons-stream */
3915 s_save (SCHEME_A_ OP_C1STREAM, NIL, cdr (SCHEME_V->code));
3916 SCHEME_V->code = car (SCHEME_V->code);
3917 s_goto (OP_EVAL);
3918
3919 case OP_C1STREAM: /* cons-stream */
3920 SCHEME_V->args = SCHEME_V->value; /* save SCHEME_V->value to register args for gc */
3921 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3922 set_typeflag (x, T_PROMISE);
3923 s_return (cons (args, x));
3924
3925 case OP_MACRO0: /* macro */
3926 if (is_pair (car (SCHEME_V->code)))
3927 {
3928 x = caar (SCHEME_V->code);
3929 SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3930 }
3931 else
3932 {
3933 x = car (SCHEME_V->code);
3934 SCHEME_V->code = cadr (SCHEME_V->code);
3935 }
3936
3937 if (!is_symbol (x))
3938 Error_0 ("variable is not a symbol");
3939
3940 s_save (SCHEME_A_ OP_MACRO1, NIL, x);
3941 s_goto (OP_EVAL);
3942
3943 case OP_MACRO1: /* macro */
3944 set_typeflag (SCHEME_V->value, T_MACRO);
3945 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3946
3947 if (x != NIL)
3948 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3949 else
3950 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3951
3952 s_return (SCHEME_V->code);
3953
3954 case OP_CASE0: /* case */
3955 s_save (SCHEME_A_ OP_CASE1, NIL, cdr (SCHEME_V->code));
3956 SCHEME_V->code = car (SCHEME_V->code);
3957 s_goto (OP_EVAL);
3958
3959 case OP_CASE1: /* case */
3960 for (x = SCHEME_V->code; x != NIL; x = cdr (x))
3961 {
3962 if (!is_pair (y = caar (x)))
3963 break;
3964
3965 for (; y != NIL; y = cdr (y))
3966 if (eqv (car (y), SCHEME_V->value))
3967 break;
3968
3969 if (y != NIL)
3970 break;
3971 }
3972
3973 if (x != NIL)
3974 {
3975 if (is_pair (caar (x)))
3976 {
3977 SCHEME_V->code = cdar (x);
3978 s_goto (OP_BEGIN);
3979 }
3980 else /* else */
3981 {
3982 s_save (SCHEME_A_ OP_CASE2, NIL, cdar (x));
3983 SCHEME_V->code = caar (x);
3984 s_goto (OP_EVAL);
3985 }
3986 }
3987 else
3988 s_return (NIL);
3989
3990 case OP_CASE2: /* case */
3991 if (is_true (SCHEME_V->value))
3992 s_goto (OP_BEGIN);
3993 else
3994 s_return (NIL);
3995
3996 case OP_PAPPLY: /* apply */
3997 SCHEME_V->code = car (args);
3998 SCHEME_V->args = list_star (SCHEME_A_ cdr (args));
3999 /*SCHEME_V->args = cadr(args); */
4000 s_goto (OP_APPLY);
4001
4002 case OP_PEVAL: /* eval */
4003 if (cdr (args) != NIL)
4004 SCHEME_V->envir = cadr (args);
4005
4006 SCHEME_V->code = car (args);
4007 s_goto (OP_EVAL);
4008
4009 case OP_CONTINUATION: /* call-with-current-continuation */
4010 SCHEME_V->code = car (args);
4011 SCHEME_V->args = cons (mk_continuation (SCHEME_A_ ss_get_cont (SCHEME_A)), NIL);
4012 s_goto (OP_APPLY);
4013 }
4014
4015 if (USE_ERROR_CHECKING) abort ();
4016 }
4017
4018 static int
4019 opexe_1 (SCHEME_P_ enum scheme_opcodes op)
4020 {
4021 pointer args = SCHEME_V->args;
4022 pointer x = car (args);
4023 num v;
4024
4025 switch (op)
4026 {
4027 #if USE_MATH
4028 case OP_INEX2EX: /* inexact->exact */
4029 {
4030 if (is_integer (x))
4031 s_return (x);
4032
4033 RVALUE r = rvalue_unchecked (x);
4034
4035 if (r == (RVALUE)(IVALUE)r)
4036 s_return (mk_integer (SCHEME_A_ rvalue_unchecked (x)));
4037 else
4038 Error_1 ("inexact->exact: not integral:", x);
4039 }
4040
4041 case OP_EXP: s_return (mk_real (SCHEME_A_ exp (rvalue (x))));
4042 case OP_LOG: s_return (mk_real (SCHEME_A_ log (rvalue (x))));
4043 case OP_SIN: s_return (mk_real (SCHEME_A_ sin (rvalue (x))));
4044 case OP_COS: s_return (mk_real (SCHEME_A_ cos (rvalue (x))));
4045 case OP_TAN: s_return (mk_real (SCHEME_A_ tan (rvalue (x))));
4046 case OP_ASIN: s_return (mk_real (SCHEME_A_ asin (rvalue (x))));
4047 case OP_ACOS: s_return (mk_real (SCHEME_A_ acos (rvalue (x))));
4048
4049 case OP_ATAN:
4050 if (cdr (args) == NIL)
4051 s_return (mk_real (SCHEME_A_ atan (rvalue (x))));
4052 else
4053 {
4054 pointer y = cadr (args);
4055 s_return (mk_real (SCHEME_A_ atan2 (rvalue (x), rvalue (y))));
4056 }
4057
4058 case OP_SQRT:
4059 s_return (mk_real (SCHEME_A_ sqrt (rvalue (x))));
4060
4061 case OP_EXPT:
4062 {
4063 RVALUE result;
4064 int real_result = 1;
4065 pointer y = cadr (args);
4066
4067 if (is_integer (x) && is_integer (y))
4068 real_result = 0;
4069
4070 /* This 'if' is an R5RS compatibility fix. */
4071 /* NOTE: Remove this 'if' fix for R6RS. */
4072 if (rvalue (x) == 0 && rvalue (y) < 0)
4073 result = 0;
4074 else
4075 result = pow (rvalue (x), rvalue (y));
4076
4077 /* Before returning integer result make sure we can. */
4078 /* If the test fails, result is too big for integer. */
4079 if (!real_result)
4080 {
4081 long result_as_long = result;
4082
4083 if (result != result_as_long)
4084 real_result = 1;
4085 }
4086
4087 if (real_result)
4088 s_return (mk_real (SCHEME_A_ result));
4089 else
4090 s_return (mk_integer (SCHEME_A_ result));
4091 }
4092
4093 case OP_FLOOR: s_return (mk_real (SCHEME_A_ floor (rvalue (x))));
4094 case OP_CEILING: s_return (mk_real (SCHEME_A_ ceil (rvalue (x))));
4095
4096 case OP_TRUNCATE:
4097 {
4098 RVALUE n = rvalue (x);
4099 s_return (mk_real (SCHEME_A_ n > 0 ? floor (n) : ceil (n)));
4100 }
4101
4102 case OP_ROUND:
4103 if (is_integer (x))
4104 s_return (x);
4105
4106 s_return (mk_real (SCHEME_A_ round_per_R5RS (rvalue (x))));
4107 #endif
4108
4109 case OP_ADD: /* + */
4110 v = num_zero;
4111
4112 for (x = args; x != NIL; x = cdr (x))
4113 v = num_op (NUM_ADD, v, nvalue (car (x)));
4114
4115 s_return (mk_number (SCHEME_A_ v));
4116
4117 case OP_MUL: /* * */
4118 v = num_one;
4119
4120 for (x = args; x != NIL; x = cdr (x))
4121 v = num_op (NUM_MUL, v, nvalue (car (x)));
4122
4123 s_return (mk_number (SCHEME_A_ v));
4124
4125 case OP_SUB: /* - */
4126 if (cdr (args) == NIL)
4127 {
4128 x = args;
4129 v = num_zero;
4130 }
4131 else
4132 {
4133 x = cdr (args);
4134 v = nvalue (car (args));
4135 }
4136
4137 for (; x != NIL; x = cdr (x))
4138 v = num_op (NUM_SUB, v, nvalue (car (x)));
4139
4140 s_return (mk_number (SCHEME_A_ v));
4141
4142 case OP_DIV: /* / */
4143 if (cdr (args) == NIL)
4144 {
4145 x = args;
4146 v = num_one;
4147 }
4148 else
4149 {
4150 x = cdr (args);
4151 v = nvalue (car (args));
4152 }
4153
4154 for (; x != NIL; x = cdr (x))
4155 if (!is_zero_rvalue (rvalue (car (x))))
4156 v = num_div (v, nvalue (car (x)));
4157 else
4158 Error_0 ("/: division by zero");
4159
4160 s_return (mk_number (SCHEME_A_ v));
4161
4162 case OP_INTDIV: /* quotient */
4163 if (cdr (args) == NIL)
4164 {
4165 x = args;
4166 v = num_one;
4167 }
4168 else
4169 {
4170 x = cdr (args);
4171 v = nvalue (car (args));
4172 }
4173
4174 for (; x != NIL; x = cdr (x))
4175 {
4176 if (ivalue (car (x)) != 0)
4177 v = num_op (NUM_INTDIV, v, nvalue (car (x)));
4178 else
4179 Error_0 ("quotient: division by zero");
4180 }
4181
4182 s_return (mk_number (SCHEME_A_ v));
4183
4184 case OP_REM: /* remainder */
4185 v = nvalue (x);
4186
4187 if (ivalue (cadr (args)) != 0)
4188 v = num_rem (v, nvalue (cadr (args)));
4189 else
4190 Error_0 ("remainder: division by zero");
4191
4192 s_return (mk_number (SCHEME_A_ v));
4193
4194 case OP_MOD: /* modulo */
4195 v = nvalue (x);
4196
4197 if (ivalue (cadr (args)) != 0)
4198 v = num_mod (v, nvalue (cadr (args)));
4199 else
4200 Error_0 ("modulo: division by zero");
4201
4202 s_return (mk_number (SCHEME_A_ v));
4203
4204 case OP_CAR: /* car */
4205 s_return (caar (args));
4206
4207 case OP_CDR: /* cdr */
4208 s_return (cdar (args));
4209
4210 case OP_CONS: /* cons */
4211 set_cdr (args, cadr (args));
4212 s_return (args);
4213
4214 case OP_SETCAR: /* set-car! */
4215 if (!is_immutable (x))
4216 {
4217 set_car (x, cadr (args));
4218 s_return (car (args));
4219 }
4220 else
4221 Error_0 ("set-car!: unable to alter immutable pair");
4222
4223 case OP_SETCDR: /* set-cdr! */
4224 if (!is_immutable (x))
4225 {
4226 set_cdr (x, cadr (args));
4227 s_return (car (args));
4228 }
4229 else
4230 Error_0 ("set-cdr!: unable to alter immutable pair");
4231
4232 case OP_CHAR2INT: /* char->integer */
4233 s_return (mk_integer (SCHEME_A_ ivalue_unchecked (x)));
4234
4235 case OP_INT2CHAR: /* integer->char */
4236 s_return (mk_character (SCHEME_A_ ivalue_unchecked (x)));
4237
4238 case OP_CHARUPCASE:
4239 {
4240 unsigned char c = ivalue_unchecked (x);
4241 c = toupper (c);
4242 s_return (mk_character (SCHEME_A_ c));
4243 }
4244
4245 case OP_CHARDNCASE:
4246 {
4247 unsigned char c = ivalue_unchecked (x);
4248 c = tolower (c);
4249 s_return (mk_character (SCHEME_A_ c));
4250 }
4251
4252 case OP_STR2SYM: /* string->symbol */
4253 s_return (mk_symbol (SCHEME_A_ strvalue (x)));
4254
4255 case OP_STR2ATOM: /* string->atom */
4256 {
4257 char *s = strvalue (x);
4258 long pf = 0;
4259
4260 if (cdr (args) != NIL)
4261 {
4262 /* we know cadr(args) is a natural number */
4263 /* see if it is 2, 8, 10, or 16, or error */
4264 pf = ivalue_unchecked (cadr (args));
4265
4266 if (pf == 16 || pf == 10 || pf == 8 || pf == 2)
4267 {
4268 /* base is OK */
4269 }
4270 else
4271 pf = -1;
4272 }
4273
4274 if (pf < 0)
4275 Error_1 ("string->atom: bad base:", cadr (args));
4276 else if (*s == '#') /* no use of base! */
4277 s_return (mk_sharp_const (SCHEME_A_ s + 1));
4278 else
4279 {
4280 if (pf == 0 || pf == 10)
4281 s_return (mk_atom (SCHEME_A_ s));
4282 else
4283 {
4284 char *ep;
4285 long iv = strtol (s, &ep, (int) pf);
4286
4287 if (*ep == 0)
4288 s_return (mk_integer (SCHEME_A_ iv));
4289 else
4290 s_return (S_F);
4291 }
4292 }
4293 }
4294
4295 case OP_SYM2STR: /* symbol->string */
4296 x = mk_string (SCHEME_A_ symname (x));
4297 setimmutable (x);
4298 s_return (x);
4299
4300 case OP_ATOM2STR: /* atom->string */
4301 {
4302 long pf = 0;
4303
4304 if (cdr (args) != NIL)
4305 {
4306 /* we know cadr(args) is a natural number */
4307 /* see if it is 2, 8, 10, or 16, or error */
4308 pf = ivalue_unchecked (cadr (args));
4309
4310 if (is_number (x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2))
4311 {
4312 /* base is OK */
4313 }
4314 else
4315 pf = -1;
4316 }
4317
4318 if (pf < 0)
4319 Error_1 ("atom->string: bad base:", cadr (args));
4320 else if (is_number (x) || is_character (x) || is_string (x) || is_symbol (x))
4321 {
4322 char *p;
4323 int len;
4324
4325 atom2str (SCHEME_A_ x, pf, &p, &len);
4326 s_return (mk_counted_string (SCHEME_A_ p, len));
4327 }
4328 else
4329 Error_1 ("atom->string: not an atom:", x);
4330 }
4331
4332 case OP_MKSTRING: /* make-string */
4333 {
4334 int fill = cdr (args) != NIL ? charvalue (cadr (args)) : ' ';
4335 int len = ivalue_unchecked (x);
4336
4337 s_return (mk_empty_string (SCHEME_A_ len, fill));
4338 }
4339
4340 case OP_STRLEN: /* string-length */
4341 s_return (mk_integer (SCHEME_A_ strlength (x)));
4342
4343 case OP_STRREF: /* string-ref */
4344 {
4345 char *str = strvalue (x);
4346 int index = ivalue_unchecked (cadr (args));
4347
4348 if (index >= strlength (x))
4349 Error_1 ("string-ref: out of bounds:", cadr (args));
4350
4351 s_return (mk_character (SCHEME_A_ ((unsigned char *)str)[index]));
4352 }
4353
4354 case OP_STRSET: /* string-set! */
4355 {
4356 char *str = strvalue (x);
4357 int index = ivalue_unchecked (cadr (args));
4358 int c;
4359
4360 if (is_immutable (x))
4361 Error_1 ("string-set!: unable to alter immutable string:", x);
4362
4363 if (index >= strlength (x))
4364 Error_1 ("string-set!: out of bounds:", cadr (args));
4365
4366 c = charvalue (caddr (args));
4367
4368 str[index] = c;
4369 s_return (car (args));
4370 }
4371
4372 case OP_STRAPPEND: /* string-append */
4373 {
4374 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4375 int len = 0;
4376 pointer newstr;
4377 char *pos;
4378
4379 /* compute needed length for new string */
4380 for (x = args; x != NIL; x = cdr (x))
4381 len += strlength (car (x));
4382
4383 newstr = mk_empty_string (SCHEME_A_ len, ' ');
4384
4385 /* store the contents of the argument strings into the new string */
4386 for (pos = strvalue (newstr), x = args; x != NIL; pos += strlength (car (x)), x = cdr (x))
4387 memcpy (pos, strvalue (car (x)), strlength (car (x)));
4388
4389 s_return (newstr);
4390 }
4391
4392 case OP_SUBSTR: /* substring */
4393 {
4394 char *str = strvalue (x);
4395 int index0 = ivalue_unchecked (cadr (args));
4396 int index1;
4397 int len;
4398
4399 if (index0 > strlength (x))
4400 Error_1 ("substring: start out of bounds:", cadr (args));
4401
4402 if (cddr (args) != NIL)
4403 {
4404 index1 = ivalue_unchecked (caddr (args));
4405
4406 if (index1 > strlength (x) || index1 < index0)
4407 Error_1 ("substring: end out of bounds:", caddr (args));
4408 }
4409 else
4410 index1 = strlength (x);
4411
4412 len = index1 - index0;
4413 x = mk_empty_string (SCHEME_A_ len, ' ');
4414 memcpy (strvalue (x), str + index0, len);
4415 strvalue (x)[len] = 0;
4416
4417 s_return (x);
4418 }
4419
4420 case OP_VECTOR: /* vector */
4421 {
4422 int i;
4423 pointer vec;
4424 int len = list_length (SCHEME_A_ args);
4425
4426 if (len < 0)
4427 Error_1 ("vector: not a proper list:", args);
4428
4429 vec = mk_vector (SCHEME_A_ len);
4430
4431 #if USE_ERROR_CHECKING
4432 if (SCHEME_V->no_memory)
4433 s_return (S_SINK);
4434 #endif
4435
4436 for (x = args, i = 0; is_pair (x); x = cdr (x), i++)
4437 vector_set (vec, i, car (x));
4438
4439 s_return (vec);
4440 }
4441
4442 case OP_MKVECTOR: /* make-vector */
4443 {
4444 pointer fill = NIL;
4445 pointer vec;
4446 int len = ivalue_unchecked (x);
4447
4448 if (cdr (args) != NIL)
4449 fill = cadr (args);
4450
4451 vec = mk_vector (SCHEME_A_ len);
4452
4453 #if USE_ERROR_CHECKING
4454 if (SCHEME_V->no_memory)
4455 s_return (S_SINK);
4456 #endif
4457
4458 if (fill != NIL)
4459 fill_vector (vec, 0, fill);
4460
4461 s_return (vec);
4462 }
4463
4464 case OP_VECLEN: /* vector-length */
4465 s_return (mk_integer (SCHEME_A_ veclength (x)));
4466
4467 case OP_VECRESIZE:
4468 vector_resize (x, ivalue_unchecked (cadr (args)), caddr (args));
4469 s_return (x);
4470
4471 case OP_VECREF: /* vector-ref */
4472 {
4473 int index = ivalue_unchecked (cadr (args));
4474
4475 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4476 Error_1 ("vector-ref: out of bounds:", cadr (args));
4477
4478 s_return (vector_get (x, index));
4479 }
4480
4481 case OP_VECSET: /* vector-set! */
4482 {
4483 int index = ivalue_unchecked (cadr (args));
4484
4485 if (is_immutable (x))
4486 Error_1 ("vector-set!: unable to alter immutable vector:", x);
4487
4488 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4489 Error_1 ("vector-set!: out of bounds:", cadr (args));
4490
4491 vector_set (x, index, caddr (args));
4492 s_return (x);
4493 }
4494 }
4495
4496 if (USE_ERROR_CHECKING) abort ();
4497 }
4498
4499 static int
4500 opexe_2 (SCHEME_P_ enum scheme_opcodes op)
4501 {
4502 pointer x = SCHEME_V->args;
4503
4504 for (;;)
4505 {
4506 num v = nvalue (car (x));
4507 x = cdr (x);
4508
4509 if (x == NIL)
4510 break;
4511
4512 int r = num_cmp (v, nvalue (car (x)));
4513
4514 switch (op)
4515 {
4516 case OP_NUMEQ: r = r == 0; break;
4517 case OP_LESS: r = r < 0; break;
4518 case OP_GRE: r = r > 0; break;
4519 case OP_LEQ: r = r <= 0; break;
4520 case OP_GEQ: r = r >= 0; break;
4521 }
4522
4523 if (!r)
4524 s_return (S_F);
4525 }
4526
4527 s_return (S_T);
4528 }
4529
4530 static int
4531 opexe_3 (SCHEME_P_ enum scheme_opcodes op)
4532 {
4533 pointer args = SCHEME_V->args;
4534 pointer a = car (args);
4535 pointer d = cdr (args);
4536 int r;
4537
4538 switch (op)
4539 {
4540 case OP_NOT: /* not */ r = is_false (a) ; break;
4541 case OP_BOOLP: /* boolean? */ r = a == S_F || a == S_T ; break;
4542 case OP_EOFOBJP: /* eof-object? */ r = a == S_EOF ; break;
4543 case OP_NULLP: /* null? */ r = a == NIL ; break;
4544 case OP_SYMBOLP: /* symbol? */ r = is_symbol (a) ; break;
4545 case OP_GENSYMP: /* gensym? */ r = is_gensym (SCHEME_A_ a); break;
4546 case OP_NUMBERP: /* number? */ r = is_number (a) ; break;
4547 case OP_STRINGP: /* string? */ r = is_string (a) ; break;
4548 case OP_INTEGERP: /* integer? */ r = is_integer (a) ; break;
4549 case OP_REALP: /* real? */ r = is_number (a) ; break; /* all numbers are real */
4550 case OP_CHARP: /* char? */ r = is_character (a) ; break;
4551
4552 #if USE_CHAR_CLASSIFIERS
4553 case OP_CHARAP: /* char-alphabetic? */ r = Cisalpha (ivalue_unchecked (a)); break;
4554 case OP_CHARNP: /* char-numeric? */ r = Cisdigit (ivalue_unchecked (a)); break;
4555 case OP_CHARWP: /* char-whitespace? */ r = Cisspace (ivalue_unchecked (a)); break;
4556 case OP_CHARUP: /* char-upper-case? */ r = Cisupper (ivalue_unchecked (a)); break;
4557 case OP_CHARLP: /* char-lower-case? */ r = Cislower (ivalue_unchecked (a)); break;
4558 #endif
4559
4560 #if USE_PORTS
4561 case OP_PORTP: /* port? */ r = is_port (a) ; break;
4562 case OP_INPORTP: /* input-port? */ r = is_inport (a) ; break;
4563 case OP_OUTPORTP: /* output-port? */ r = is_outport (a); break;
4564 #endif
4565
4566 case OP_PROCP: /* procedure? */
4567
4568 /*--
4569 * continuation should be procedure by the example
4570 * (call-with-current-continuation procedure?) ==> #t
4571 * in R^3 report sec. 6.9
4572 */
4573 r = is_proc (a) || is_closure (a) || is_continuation (a) || is_foreign (a);
4574 break;
4575
4576 case OP_PAIRP: /* pair? */ r = is_pair (a) ; break;
4577 case OP_LISTP: /* list? */ r = list_length (SCHEME_A_ a) >= 0; break;
4578 case OP_ENVP: /* environment? */ r = is_environment (a) ; break;
4579 case OP_VECTORP: /* vector? */ r = is_vector (a) ; break;
4580 case OP_EQ: /* eq? */ r = a == cadr (args) ; break;
4581 case OP_EQV: /* eqv? */ r = eqv (a, cadr (args)) ; break;
4582 }
4583
4584 s_retbool (r);
4585 }
4586
4587 static int
4588 opexe_4 (SCHEME_P_ enum scheme_opcodes op)
4589 {
4590 pointer args = SCHEME_V->args;
4591 pointer a = car (args);
4592 pointer x, y;
4593
4594 switch (op)
4595 {
4596 case OP_FORCE: /* force */
4597 SCHEME_V->code = a;
4598
4599 if (is_promise (SCHEME_V->code))
4600 {
4601 /* Should change type to closure here */
4602 s_save (SCHEME_A_ OP_SAVE_FORCED, NIL, SCHEME_V->code);
4603 SCHEME_V->args = NIL;
4604 s_goto (OP_APPLY);
4605 }
4606 else
4607 s_return (SCHEME_V->code);
4608
4609 case OP_SAVE_FORCED: /* Save forced value replacing promise */
4610 memcpy (SCHEME_V->code, SCHEME_V->value, sizeof (struct cell));
4611 s_return (SCHEME_V->value);
4612
4613 #if USE_PORTS
4614
4615 case OP_WRITE: /* write */
4616 case OP_DISPLAY: /* display */
4617 case OP_WRITE_CHAR: /* write-char */
4618 if (is_pair (cdr (SCHEME_V->args)))
4619 {
4620 if (cadr (SCHEME_V->args) != SCHEME_V->outport)
4621 {
4622 x = cons (SCHEME_V->outport, NIL);
4623 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4624 SCHEME_V->outport = cadr (SCHEME_V->args);
4625 }
4626 }
4627
4628 SCHEME_V->args = a;
4629
4630 if (op == OP_WRITE)
4631 SCHEME_V->print_flag = 1;
4632 else
4633 SCHEME_V->print_flag = 0;
4634
4635 s_goto (OP_P0LIST);
4636
4637 case OP_NEWLINE: /* newline */
4638 if (is_pair (args))
4639 {
4640 if (a != SCHEME_V->outport)
4641 {
4642 x = cons (SCHEME_V->outport, NIL);
4643 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4644 SCHEME_V->outport = a;
4645 }
4646 }
4647
4648 putstr (SCHEME_A_ "\n");
4649 s_return (S_T);
4650 #endif
4651
4652 case OP_ERR0: /* error */
4653 SCHEME_V->retcode = -1;
4654
4655 if (!is_string (a))
4656 {
4657 args = cons (mk_string (SCHEME_A_ " -- "), args);
4658 setimmutable (car (args));
4659 }
4660
4661 putstr (SCHEME_A_ "Error: ");
4662 putstr (SCHEME_A_ strvalue (car (args)));
4663 SCHEME_V->args = cdr (args);
4664 s_goto (OP_ERR1);
4665
4666 case OP_ERR1: /* error */
4667 putstr (SCHEME_A_ " ");
4668
4669 if (args != NIL)
4670 {
4671 s_save (SCHEME_A_ OP_ERR1, cdr (args), NIL);
4672 SCHEME_V->args = a;
4673 SCHEME_V->print_flag = 1;
4674 s_goto (OP_P0LIST);
4675 }
4676 else
4677 {
4678 putstr (SCHEME_A_ "\n");
4679
4680 if (SCHEME_V->interactive_repl)
4681 s_goto (OP_T0LVL);
4682 else
4683 return -1;
4684 }
4685
4686 case OP_REVERSE: /* reverse */
4687 s_return (reverse (SCHEME_A_ a));
4688
4689 case OP_LIST_STAR: /* list* */
4690 s_return (list_star (SCHEME_A_ SCHEME_V->args));
4691
4692 case OP_APPEND: /* append */
4693 x = NIL;
4694 y = args;
4695
4696 if (y == x)
4697 s_return (x);
4698
4699 /* cdr() in the while condition is not a typo. If car() */
4700 /* is used (append '() 'a) will return the wrong result. */
4701 while (cdr (y) != NIL)
4702 {
4703 x = revappend (SCHEME_A_ x, car (y));
4704 y = cdr (y);
4705
4706 if (x == S_F)
4707 Error_0 ("non-list argument to append");
4708 }
4709
4710 s_return (reverse_in_place (SCHEME_A_ car (y), x));
4711
4712 #if USE_PLIST
4713
4714 case OP_PUT: /* put */
4715 if (!hasprop (a) || !hasprop (cadr (args)))
4716 Error_0 ("illegal use of put");
4717
4718 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4719 {
4720 if (caar (x) == y)
4721 break;
4722 }
4723
4724 if (x != NIL)
4725 cdar (x) = caddr (args);
4726 else
4727 symprop (a) = cons (cons (y, caddr (args)), symprop (a));
4728
4729 s_return (S_T);
4730
4731 case OP_GET: /* get */
4732 if (!hasprop (a) || !hasprop (cadr (args)))
4733 Error_0 ("illegal use of get");
4734
4735 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4736 if (caar (x) == y)
4737 break;
4738
4739 if (x != NIL)
4740 s_return (cdar (x));
4741 else
4742 s_return (NIL);
4743
4744 #endif /* USE_PLIST */
4745
4746 case OP_QUIT: /* quit */
4747 if (is_pair (args))
4748 SCHEME_V->retcode = ivalue (a);
4749
4750 return -1;
4751
4752 case OP_GC: /* gc */
4753 gc (SCHEME_A_ NIL, NIL);
4754 s_return (S_T);
4755
4756 case OP_GCVERB: /* gc-verbose */
4757 {
4758 int was = SCHEME_V->gc_verbose;
4759
4760 SCHEME_V->gc_verbose = (a != S_F);
4761 s_retbool (was);
4762 }
4763
4764 case OP_NEWSEGMENT: /* new-segment */
4765 if (!is_pair (args) || !is_number (a))
4766 Error_0 ("new-segment: argument must be a number");
4767
4768 alloc_cellseg (SCHEME_A_ ivalue (a));
4769
4770 s_return (S_T);
4771
4772 case OP_OBLIST: /* oblist */
4773 s_return (oblist_all_symbols (SCHEME_A));
4774
4775 #if USE_PORTS
4776
4777 case OP_CURR_INPORT: /* current-input-port */
4778 s_return (SCHEME_V->inport);
4779
4780 case OP_CURR_OUTPORT: /* current-output-port */
4781 s_return (SCHEME_V->outport);
4782
4783 case OP_OPEN_INFILE: /* open-input-file */
4784 case OP_OPEN_OUTFILE: /* open-output-file */
4785 case OP_OPEN_INOUTFILE: /* open-input-output-file */
4786 {
4787 int prop = 0;
4788 pointer p;
4789
4790 switch (op)
4791 {
4792 case OP_OPEN_INFILE:
4793 prop = port_input;
4794 break;
4795
4796 case OP_OPEN_OUTFILE:
4797 prop = port_output;
4798 break;
4799
4800 case OP_OPEN_INOUTFILE:
4801 prop = port_input | port_output;
4802 break;
4803 }
4804
4805 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
4806
4807 s_return (p == NIL ? S_F : p);
4808 }
4809
4810 # if USE_STRING_PORTS
4811
4812 case OP_OPEN_INSTRING: /* open-input-string */
4813 case OP_OPEN_INOUTSTRING: /* open-input-output-string */
4814 {
4815 int prop = 0;
4816 pointer p;
4817
4818 switch (op)
4819 {
4820 case OP_OPEN_INSTRING:
4821 prop = port_input;
4822 break;
4823
4824 case OP_OPEN_INOUTSTRING:
4825 prop = port_input | port_output;
4826 break;
4827 }
4828
4829 p = port_from_string (SCHEME_A_ strvalue (a),
4830 strvalue (a) + strlength (a), prop);
4831
4832 s_return (p == NIL ? S_F : p);
4833 }
4834
4835 case OP_OPEN_OUTSTRING: /* open-output-string */
4836 {
4837 pointer p;
4838
4839 if (a == NIL)
4840 p = port_from_scratch (SCHEME_A);
4841 else
4842 p = port_from_string (SCHEME_A_ strvalue (a),
4843 strvalue (a) + strlength (a), port_output);
4844
4845 s_return (p == NIL ? S_F : p);
4846 }
4847
4848 case OP_GET_OUTSTRING: /* get-output-string */
4849 {
4850 port *p;
4851
4852 if ((p = a->object.port)->kind & port_string)
4853 {
4854 off_t size;
4855 char *str;
4856
4857 size = p->rep.string.curr - p->rep.string.start + 1;
4858 str = malloc (size);
4859
4860 if (str != NULL)
4861 {
4862 pointer s;
4863
4864 memcpy (str, p->rep.string.start, size - 1);
4865 str[size - 1] = '\0';
4866 s = mk_string (SCHEME_A_ str);
4867 free (str);
4868 s_return (s);
4869 }
4870 }
4871
4872 s_return (S_F);
4873 }
4874
4875 # endif
4876
4877 case OP_CLOSE_INPORT: /* close-input-port */
4878 port_close (SCHEME_A_ a, port_input);
4879 s_return (S_T);
4880
4881 case OP_CLOSE_OUTPORT: /* close-output-port */
4882 port_close (SCHEME_A_ a, port_output);
4883 s_return (S_T);
4884 #endif
4885
4886 case OP_INT_ENV: /* interaction-environment */
4887 s_return (SCHEME_V->global_env);
4888
4889 case OP_CURR_ENV: /* current-environment */
4890 s_return (SCHEME_V->envir);
4891
4892 }
4893
4894 if (USE_ERROR_CHECKING) abort ();
4895 }
4896
4897 static int
4898 opexe_5 (SCHEME_P_ enum scheme_opcodes op)
4899 {
4900 pointer args = SCHEME_V->args;
4901 pointer x;
4902
4903 if (SCHEME_V->nesting != 0)
4904 {
4905 int n = SCHEME_V->nesting;
4906
4907 SCHEME_V->nesting = 0;
4908 SCHEME_V->retcode = -1;
4909 Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
4910 }
4911
4912 switch (op)
4913 {
4914 /* ========== reading part ========== */
4915 #if USE_PORTS
4916 case OP_READ:
4917 if (!is_pair (args))
4918 s_goto (OP_READ_INTERNAL);
4919
4920 if (!is_inport (car (args)))
4921 Error_1 ("read: not an input port:", car (args));
4922
4923 if (car (args) == SCHEME_V->inport)
4924 s_goto (OP_READ_INTERNAL);
4925
4926 x = SCHEME_V->inport;
4927 SCHEME_V->inport = car (args);
4928 x = cons (x, NIL);
4929 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4930 s_goto (OP_READ_INTERNAL);
4931
4932 case OP_READ_CHAR: /* read-char */
4933 case OP_PEEK_CHAR: /* peek-char */
4934 {
4935 int c;
4936
4937 if (is_pair (args))
4938 {
4939 if (car (args) != SCHEME_V->inport)
4940 {
4941 x = SCHEME_V->inport;
4942 x = cons (x, NIL);
4943 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4944 SCHEME_V->inport = car (args);
4945 }
4946 }
4947
4948 c = inchar (SCHEME_A);
4949
4950 if (c == EOF)
4951 s_return (S_EOF);
4952
4953 if (SCHEME_V->op == OP_PEEK_CHAR)
4954 backchar (SCHEME_A_ c);
4955
4956 s_return (mk_character (SCHEME_A_ c));
4957 }
4958
4959 case OP_CHAR_READY: /* char-ready? */
4960 {
4961 pointer p = SCHEME_V->inport;
4962 int res;
4963
4964 if (is_pair (args))
4965 p = car (args);
4966
4967 res = p->object.port->kind & port_string;
4968
4969 s_retbool (res);
4970 }
4971
4972 case OP_SET_INPORT: /* set-input-port */
4973 SCHEME_V->inport = car (args);
4974 s_return (SCHEME_V->value);
4975
4976 case OP_SET_OUTPORT: /* set-output-port */
4977 SCHEME_V->outport = car (args);
4978 s_return (SCHEME_V->value);
4979 #endif
4980
4981 case OP_RDSEXPR:
4982 switch (SCHEME_V->tok)
4983 {
4984 case TOK_EOF:
4985 s_return (S_EOF);
4986 /* NOTREACHED */
4987
4988 case TOK_VEC:
4989 s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
4990 /* fall through */
4991
4992 case TOK_LPAREN:
4993 SCHEME_V->tok = token (SCHEME_A);
4994
4995 if (SCHEME_V->tok == TOK_RPAREN)
4996 s_return (NIL);
4997 else if (SCHEME_V->tok == TOK_DOT)
4998 Error_0 ("syntax error: illegal dot expression");
4999 else
5000 {
5001 SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
5002 s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
5003 s_goto (OP_RDSEXPR);
5004 }
5005
5006 case TOK_QUOTE:
5007 s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
5008 SCHEME_V->tok = token (SCHEME_A);
5009 s_goto (OP_RDSEXPR);
5010
5011 case TOK_BQUOTE:
5012 SCHEME_V->tok = token (SCHEME_A);
5013
5014 if (SCHEME_V->tok == TOK_VEC)
5015 {
5016 s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
5017 SCHEME_V->tok = TOK_LPAREN;
5018 s_goto (OP_RDSEXPR);
5019 }
5020 else
5021 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
5022
5023 s_goto (OP_RDSEXPR);
5024
5025 case TOK_COMMA:
5026 s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
5027 SCHEME_V->tok = token (SCHEME_A);
5028 s_goto (OP_RDSEXPR);
5029
5030 case TOK_ATMARK:
5031 s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
5032 SCHEME_V->tok = token (SCHEME_A);
5033 s_goto (OP_RDSEXPR);
5034
5035 case TOK_ATOM:
5036 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS)));
5037
5038 case TOK_DOTATOM:
5039 SCHEME_V->strbuff[0] = '.';
5040 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ 1, DELIMITERS)));
5041
5042 case TOK_STRATOM:
5043 x = readstrexp (SCHEME_A_ '|');
5044 //TODO: haven't checked whether the garbage collector could interfere
5045 s_return (mk_atom (SCHEME_A_ strvalue (x)));
5046
5047 case TOK_DQUOTE:
5048 x = readstrexp (SCHEME_A_ '"');
5049
5050 if (x == S_F)
5051 Error_0 ("Error reading string");
5052
5053 setimmutable (x);
5054 s_return (x);
5055
5056 case TOK_SHARP:
5057 {
5058 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
5059
5060 if (f == NIL)
5061 Error_0 ("undefined sharp expression");
5062 else
5063 {
5064 SCHEME_V->code = cons (slot_value_in_env (f), NIL);
5065 s_goto (OP_EVAL);
5066 }
5067 }
5068
5069 case TOK_SHARP_CONST:
5070 if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS))) == NIL)
5071 Error_0 ("undefined sharp expression");
5072 else
5073 s_return (x);
5074
5075 default:
5076 Error_0 ("syntax error: illegal token");
5077 }
5078
5079 break;
5080
5081 case OP_RDLIST:
5082 SCHEME_V->args = cons (SCHEME_V->value, args);
5083 SCHEME_V->tok = token (SCHEME_A);
5084
5085 switch (SCHEME_V->tok)
5086 {
5087 case TOK_EOF:
5088 s_return (S_EOF);
5089
5090 case TOK_RPAREN:
5091 {
5092 int c = inchar (SCHEME_A);
5093
5094 if (c != '\n')
5095 backchar (SCHEME_A_ c);
5096 #if SHOW_ERROR_LINE
5097 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5098 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5099 #endif
5100
5101 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5102 s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5103 }
5104
5105 case TOK_DOT:
5106 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5107 SCHEME_V->tok = token (SCHEME_A);
5108 s_goto (OP_RDSEXPR);
5109
5110 default:
5111 s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5112 s_goto (OP_RDSEXPR);
5113 }
5114
5115 case OP_RDDOT:
5116 if (token (SCHEME_A) != TOK_RPAREN)
5117 Error_0 ("syntax error: illegal dot expression");
5118
5119 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5120 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5121
5122 case OP_RDQUOTE:
5123 s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5124
5125 case OP_RDQQUOTE:
5126 s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5127
5128 case OP_RDQQUOTEVEC:
5129 s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5130 cons (mk_symbol (SCHEME_A_ "vector"),
5131 cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5132
5133 case OP_RDUNQUOTE:
5134 s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5135
5136 case OP_RDUQTSP:
5137 s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5138
5139 case OP_RDVEC:
5140 /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5141 s_goto(OP_EVAL); Cannot be quoted */
5142 /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5143 s_return(x); Cannot be part of pairs */
5144 /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5145 SCHEME_V->args=SCHEME_V->value;
5146 s_goto(OP_APPLY); */
5147 SCHEME_V->args = SCHEME_V->value;
5148 s_goto (OP_VECTOR);
5149
5150 /* ========== printing part ========== */
5151 case OP_P0LIST:
5152 if (is_vector (args))
5153 {
5154 putstr (SCHEME_A_ "#(");
5155 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5156 s_goto (OP_PVECFROM);
5157 }
5158 else if (is_environment (args))
5159 {
5160 putstr (SCHEME_A_ "#<ENVIRONMENT>");
5161 s_return (S_T);
5162 }
5163 else if (!is_pair (args))
5164 {
5165 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5166 s_return (S_T);
5167 }
5168 else
5169 {
5170 pointer a = car (args);
5171 pointer b = cdr (args);
5172 int ok_abbr = ok_abbrev (b);
5173 SCHEME_V->args = car (b);
5174
5175 if (a == SCHEME_V->QUOTE && ok_abbr)
5176 putstr (SCHEME_A_ "'");
5177 else if (a == SCHEME_V->QQUOTE && ok_abbr)
5178 putstr (SCHEME_A_ "`");
5179 else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5180 putstr (SCHEME_A_ ",");
5181 else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5182 putstr (SCHEME_A_ ",@");
5183 else
5184 {
5185 putstr (SCHEME_A_ "(");
5186 s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5187 SCHEME_V->args = a;
5188 }
5189
5190 s_goto (OP_P0LIST);
5191 }
5192
5193 case OP_P1LIST:
5194 if (is_pair (args))
5195 {
5196 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5197 putstr (SCHEME_A_ " ");
5198 SCHEME_V->args = car (args);
5199 s_goto (OP_P0LIST);
5200 }
5201 else if (is_vector (args))
5202 {
5203 s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5204 putstr (SCHEME_A_ " . ");
5205 s_goto (OP_P0LIST);
5206 }
5207 else
5208 {
5209 if (args != NIL)
5210 {
5211 putstr (SCHEME_A_ " . ");
5212 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5213 }
5214
5215 putstr (SCHEME_A_ ")");
5216 s_return (S_T);
5217 }
5218
5219 case OP_PVECFROM:
5220 {
5221 int i = ivalue_unchecked (cdr (args));
5222 pointer vec = car (args);
5223 int len = veclength (vec);
5224
5225 if (i == len)
5226 {
5227 putstr (SCHEME_A_ ")");
5228 s_return (S_T);
5229 }
5230 else
5231 {
5232 pointer elem = vector_get (vec, i);
5233
5234 ivalue_unchecked (cdr (args)) = i + 1;
5235 s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5236 SCHEME_V->args = elem;
5237
5238 if (i > 0)
5239 putstr (SCHEME_A_ " ");
5240
5241 s_goto (OP_P0LIST);
5242 }
5243 }
5244 }
5245
5246 if (USE_ERROR_CHECKING) abort ();
5247 }
5248
5249 static int
5250 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5251 {
5252 pointer args = SCHEME_V->args;
5253 pointer a = car (args);
5254 pointer x, y;
5255
5256 switch (op)
5257 {
5258 case OP_LIST_LENGTH: /* length *//* a.k */
5259 {
5260 long v = list_length (SCHEME_A_ a);
5261
5262 if (v < 0)
5263 Error_1 ("length: not a list:", a);
5264
5265 s_return (mk_integer (SCHEME_A_ v));
5266 }
5267
5268 case OP_ASSQ: /* assq *//* a.k */
5269 x = a;
5270
5271 for (y = cadr (args); is_pair (y); y = cdr (y))
5272 {
5273 if (!is_pair (car (y)))
5274 Error_0 ("unable to handle non pair element");
5275
5276 if (x == caar (y))
5277 break;
5278 }
5279
5280 if (is_pair (y))
5281 s_return (car (y));
5282 else
5283 s_return (S_F);
5284
5285
5286 case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5287 SCHEME_V->args = a;
5288
5289 if (SCHEME_V->args == NIL)
5290 s_return (S_F);
5291 else if (is_closure (SCHEME_V->args))
5292 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5293 else if (is_macro (SCHEME_V->args))
5294 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5295 else
5296 s_return (S_F);
5297
5298 case OP_CLOSUREP: /* closure? */
5299 /*
5300 * Note, macro object is also a closure.
5301 * Therefore, (closure? <#MACRO>) ==> #t
5302 * (schmorp) well, obviously not, fix? TODO
5303 */
5304 s_retbool (is_closure (a));
5305
5306 case OP_MACROP: /* macro? */
5307 s_retbool (is_macro (a));
5308 }
5309
5310 if (USE_ERROR_CHECKING) abort ();
5311 }
5312
5313 /* dispatch functions (opexe_x) return new opcode, or 0 for same opcode, or -1 to stop */
5314 typedef int (*dispatch_func)(SCHEME_P_ enum scheme_opcodes);
5315
5316 typedef int (*test_predicate)(pointer);
5317 static int
5318 tst_any (pointer p)
5319 {
5320 return 1;
5321 }
5322
5323 static int
5324 tst_inonneg (pointer p)
5325 {
5326 return is_integer (p) && ivalue_unchecked (p) >= 0;
5327 }
5328
5329 static int
5330 tst_is_list (SCHEME_P_ pointer p)
5331 {
5332 return p == NIL || is_pair (p);
5333 }
5334
5335 /* Correspond carefully with following defines! */
5336 static struct
5337 {
5338 test_predicate fct;
5339 const char *kind;
5340 } tests[] = {
5341 { tst_any , 0 },
5342 { is_string , "string" },
5343 { is_symbol , "symbol" },
5344 { is_port , "port" },
5345 { is_inport , "input port" },
5346 { is_outport , "output port" },
5347 { is_environment, "environment" },
5348 { is_pair , "pair" },
5349 { 0 , "pair or '()" },
5350 { is_character , "character" },
5351 { is_vector , "vector" },
5352 { is_number , "number" },
5353 { is_integer , "integer" },
5354 { tst_inonneg , "non-negative integer" }
5355 };
5356
5357 #define TST_NONE 0 /* TST_NONE used for built-ins, 0 for internal ops */
5358 #define TST_ANY "\001"
5359 #define TST_STRING "\002"
5360 #define TST_SYMBOL "\003"
5361 #define TST_PORT "\004"
5362 #define TST_INPORT "\005"
5363 #define TST_OUTPORT "\006"
5364 #define TST_ENVIRONMENT "\007"
5365 #define TST_PAIR "\010"
5366 #define TST_LIST "\011"
5367 #define TST_CHAR "\012"
5368 #define TST_VECTOR "\013"
5369 #define TST_NUMBER "\014"
5370 #define TST_INTEGER "\015"
5371 #define TST_NATURAL "\016"
5372
5373 #define INF_ARG 0xff
5374 #define UNNAMED_OP ""
5375
5376 static const char opnames[] =
5377 #define OP_DEF(func,name,minarity,maxarity,argtest,op) name "\x00"
5378 #include "opdefines.h"
5379 #undef OP_DEF
5380 ;
5381
5382 static const char *
5383 opname (int idx)
5384 {
5385 const char *name = opnames;
5386
5387 /* should do this at compile time, but would require external program, right? */
5388 while (idx--)
5389 name += strlen (name) + 1;
5390
5391 return *name ? name : "ILLEGAL";
5392 }
5393
5394 static const char *
5395 procname (pointer x)
5396 {
5397 return opname (procnum (x));
5398 }
5399
5400 typedef struct
5401 {
5402 uint8_t func;
5403 /*dispatch_func func;*//*TODO: maybe optionally keep the pointer, for speed? */
5404 uint8_t builtin;
5405 #if USE_ERROR_CHECKING
5406 uint8_t min_arity;
5407 uint8_t max_arity;
5408 char arg_tests_encoding[3];
5409 #endif
5410 } op_code_info;
5411
5412 static const op_code_info dispatch_table[] = {
5413 #if USE_ERROR_CHECKING
5414 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1, minarity, maxarity, argtest },
5415 #else
5416 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1 },
5417 #endif
5418 #include "opdefines.h"
5419 #undef OP_DEF
5420 {0}
5421 };
5422
5423 /* kernel of this interpreter */
5424 static void ecb_hot
5425 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5426 {
5427 SCHEME_V->op = op;
5428
5429 for (;;)
5430 {
5431 const op_code_info *pcd = dispatch_table + SCHEME_V->op;
5432
5433 #if USE_ERROR_CHECKING
5434 if (pcd->builtin) /* if built-in function, check arguments */
5435 {
5436 char msg[STRBUFFSIZE];
5437 int n = list_length (SCHEME_A_ SCHEME_V->args);
5438
5439 /* Check number of arguments */
5440 if (ecb_expect_false (n < pcd->min_arity))
5441 {
5442 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5443 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5444 xError_1 (SCHEME_A_ msg, 0);
5445 continue;
5446 }
5447 else if (ecb_expect_false (n > pcd->max_arity && pcd->max_arity != INF_ARG))
5448 {
5449 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5450 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5451 xError_1 (SCHEME_A_ msg, 0);
5452 continue;
5453 }
5454 else
5455 {
5456 if (*pcd->arg_tests_encoding) /* literal 0 and TST_NONE treated the same */
5457 {
5458 int i = 0;
5459 int j;
5460 const char *t = pcd->arg_tests_encoding;
5461 pointer arglist = SCHEME_V->args;
5462
5463 do
5464 {
5465 pointer arg = car (arglist);
5466
5467 j = t[0];
5468
5469 /*TODO: tst_is_list has different prototype - fix if other tests acquire same prototype */
5470 if (j == TST_LIST[0])
5471 {
5472 if (!tst_is_list (SCHEME_A_ arg))
5473 break;
5474 }
5475 else
5476 {
5477 if (!tests[j - 1].fct (arg))
5478 break;
5479 }
5480
5481 if (t < pcd->arg_tests_encoding + sizeof (pcd->arg_tests_encoding) - 1 && t[1]) /* last test is replicated as necessary */
5482 t++;
5483
5484 arglist = cdr (arglist);
5485 i++;
5486 }
5487 while (i < n);
5488
5489 if (i < n)
5490 {
5491 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", opname (SCHEME_V->op), i + 1, tests[j].kind);
5492 xError_1 (SCHEME_A_ msg, 0);
5493 continue;
5494 }
5495 }
5496 }
5497 }
5498 #endif
5499
5500 ok_to_freely_gc (SCHEME_A);
5501
5502 static const dispatch_func dispatch_funcs[] = {
5503 opexe_0,
5504 opexe_1,
5505 opexe_2,
5506 opexe_3,
5507 opexe_4,
5508 opexe_5,
5509 opexe_6,
5510 };
5511
5512 if (ecb_expect_false (dispatch_funcs [pcd->func] (SCHEME_A_ SCHEME_V->op) != 0))
5513 return;
5514
5515 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5516 {
5517 xwrstr ("No memory!\n");
5518 return;
5519 }
5520 }
5521 }
5522
5523 /* ========== Initialization of internal keywords ========== */
5524
5525 static void
5526 assign_syntax (SCHEME_P_ const char *name)
5527 {
5528 pointer x = oblist_add_by_name (SCHEME_A_ name);
5529 set_typeflag (x, typeflag (x) | T_SYNTAX);
5530 }
5531
5532 static void
5533 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5534 {
5535 pointer x = mk_symbol (SCHEME_A_ name);
5536 pointer y = mk_proc (SCHEME_A_ op);
5537 new_slot_in_env (SCHEME_A_ x, y);
5538 }
5539
5540 static pointer
5541 mk_proc (SCHEME_P_ enum scheme_opcodes op)
5542 {
5543 pointer y = get_cell (SCHEME_A_ NIL, NIL);
5544 set_typeflag (y, (T_PROC | T_ATOM));
5545 ivalue_unchecked (y) = op;
5546 return y;
5547 }
5548
5549 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5550 static int
5551 syntaxnum (pointer p)
5552 {
5553 const char *s = strvalue (p);
5554
5555 switch (strlength (p))
5556 {
5557 case 2:
5558 if (s[0] == 'i')
5559 return OP_IF0; /* if */
5560 else
5561 return OP_OR0; /* or */
5562
5563 case 3:
5564 if (s[0] == 'a')
5565 return OP_AND0; /* and */
5566 else
5567 return OP_LET0; /* let */
5568
5569 case 4:
5570 switch (s[3])
5571 {
5572 case 'e':
5573 return OP_CASE0; /* case */
5574
5575 case 'd':
5576 return OP_COND0; /* cond */
5577
5578 case '*':
5579 return OP_LET0AST;/* let* */
5580
5581 default:
5582 return OP_SET0; /* set! */
5583 }
5584
5585 case 5:
5586 switch (s[2])
5587 {
5588 case 'g':
5589 return OP_BEGIN; /* begin */
5590
5591 case 'l':
5592 return OP_DELAY; /* delay */
5593
5594 case 'c':
5595 return OP_MACRO0; /* macro */
5596
5597 default:
5598 return OP_QUOTE; /* quote */
5599 }
5600
5601 case 6:
5602 switch (s[2])
5603 {
5604 case 'm':
5605 return OP_LAMBDA; /* lambda */
5606
5607 case 'f':
5608 return OP_DEF0; /* define */
5609
5610 default:
5611 return OP_LET0REC;/* letrec */
5612 }
5613
5614 default:
5615 return OP_C0STREAM; /* cons-stream */
5616 }
5617 }
5618
5619 #if USE_MULTIPLICITY
5620 ecb_cold scheme *
5621 scheme_init_new ()
5622 {
5623 scheme *sc = malloc (sizeof (scheme));
5624
5625 if (!scheme_init (SCHEME_A))
5626 {
5627 free (SCHEME_A);
5628 return 0;
5629 }
5630 else
5631 return sc;
5632 }
5633 #endif
5634
5635 ecb_cold int
5636 scheme_init (SCHEME_P)
5637 {
5638 int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5639 pointer x;
5640
5641 num_set_fixnum (num_zero, 1);
5642 num_set_ivalue (num_zero, 0);
5643 num_set_fixnum (num_one, 1);
5644 num_set_ivalue (num_one, 1);
5645
5646 #if USE_INTERFACE
5647 SCHEME_V->vptr = &vtbl;
5648 #endif
5649 SCHEME_V->gensym_cnt = 0;
5650 SCHEME_V->last_cell_seg = -1;
5651 SCHEME_V->free_cell = NIL;
5652 SCHEME_V->fcells = 0;
5653 SCHEME_V->no_memory = 0;
5654 SCHEME_V->inport = NIL;
5655 SCHEME_V->outport = NIL;
5656 SCHEME_V->save_inport = NIL;
5657 SCHEME_V->loadport = NIL;
5658 SCHEME_V->nesting = 0;
5659 SCHEME_V->interactive_repl = 0;
5660
5661 if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5662 {
5663 #if USE_ERROR_CHECKING
5664 SCHEME_V->no_memory = 1;
5665 return 0;
5666 #endif
5667 }
5668
5669 SCHEME_V->gc_verbose = 0;
5670 dump_stack_initialize (SCHEME_A);
5671 SCHEME_V->code = NIL;
5672 SCHEME_V->args = NIL;
5673 SCHEME_V->envir = NIL;
5674 SCHEME_V->tracing = 0;
5675
5676 /* init NIL */
5677 set_typeflag (NIL, T_ATOM | T_MARK);
5678 set_car (NIL, NIL);
5679 set_cdr (NIL, NIL);
5680 /* init T */
5681 set_typeflag (S_T, T_ATOM | T_MARK);
5682 set_car (S_T, S_T);
5683 set_cdr (S_T, S_T);
5684 /* init F */
5685 set_typeflag (S_F, T_ATOM | T_MARK);
5686 set_car (S_F, S_F);
5687 set_cdr (S_F, S_F);
5688 /* init EOF_OBJ */
5689 set_typeflag (S_EOF, T_ATOM | T_MARK);
5690 set_car (S_EOF, S_EOF);
5691 set_cdr (S_EOF, S_EOF);
5692 /* init sink */
5693 set_typeflag (S_SINK, T_PAIR | T_MARK);
5694 set_car (S_SINK, NIL);
5695
5696 /* init c_nest */
5697 SCHEME_V->c_nest = NIL;
5698
5699 SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5700 /* init global_env */
5701 new_frame_in_env (SCHEME_A_ NIL);
5702 SCHEME_V->global_env = SCHEME_V->envir;
5703 /* init else */
5704 x = mk_symbol (SCHEME_A_ "else");
5705 new_slot_in_env (SCHEME_A_ x, S_T);
5706
5707 {
5708 static const char *syntax_names[] = {
5709 "lambda", "quote", "define", "if", "begin", "set!",
5710 "let", "let*", "letrec", "cond", "delay", "and",
5711 "or", "cons-stream", "macro", "case"
5712 };
5713
5714 for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5715 assign_syntax (SCHEME_A_ syntax_names[i]);
5716 }
5717
5718 // TODO: should iterate via strlen, to avoid n² complexity
5719 for (i = 0; i < n; i++)
5720 if (dispatch_table[i].builtin)
5721 assign_proc (SCHEME_A_ i, opname (i));
5722
5723 /* initialization of global pointers to special symbols */
5724 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5725 SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5726 SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5727 SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5728 SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5729 SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5730 SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5731 SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5732 SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5733 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5734
5735 return !SCHEME_V->no_memory;
5736 }
5737
5738 #if USE_PORTS
5739 void
5740 scheme_set_input_port_file (SCHEME_P_ int fin)
5741 {
5742 SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5743 }
5744
5745 void
5746 scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5747 {
5748 SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5749 }
5750
5751 void
5752 scheme_set_output_port_file (SCHEME_P_ int fout)
5753 {
5754 SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5755 }
5756
5757 void
5758 scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5759 {
5760 SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5761 }
5762 #endif
5763
5764 void
5765 scheme_set_external_data (SCHEME_P_ void *p)
5766 {
5767 SCHEME_V->ext_data = p;
5768 }
5769
5770 ecb_cold void
5771 scheme_deinit (SCHEME_P)
5772 {
5773 int i;
5774
5775 #if SHOW_ERROR_LINE
5776 char *fname;
5777 #endif
5778
5779 SCHEME_V->oblist = NIL;
5780 SCHEME_V->global_env = NIL;
5781 dump_stack_free (SCHEME_A);
5782 SCHEME_V->envir = NIL;
5783 SCHEME_V->code = NIL;
5784 SCHEME_V->args = NIL;
5785 SCHEME_V->value = NIL;
5786
5787 if (is_port (SCHEME_V->inport))
5788 set_typeflag (SCHEME_V->inport, T_ATOM);
5789
5790 SCHEME_V->inport = NIL;
5791 SCHEME_V->outport = NIL;
5792
5793 if (is_port (SCHEME_V->save_inport))
5794 set_typeflag (SCHEME_V->save_inport, T_ATOM);
5795
5796 SCHEME_V->save_inport = NIL;
5797
5798 if (is_port (SCHEME_V->loadport))
5799 set_typeflag (SCHEME_V->loadport, T_ATOM);
5800
5801 SCHEME_V->loadport = NIL;
5802 SCHEME_V->gc_verbose = 0;
5803 gc (SCHEME_A_ NIL, NIL);
5804
5805 for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5806 free (SCHEME_V->alloc_seg[i]);
5807
5808 #if SHOW_ERROR_LINE
5809 for (i = 0; i <= SCHEME_V->file_i; i++)
5810 {
5811 if (SCHEME_V->load_stack[i].kind & port_file)
5812 {
5813 fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5814
5815 if (fname)
5816 free (fname);
5817 }
5818 }
5819 #endif
5820 }
5821
5822 void
5823 scheme_load_file (SCHEME_P_ int fin)
5824 {
5825 scheme_load_named_file (SCHEME_A_ fin, 0);
5826 }
5827
5828 void
5829 scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5830 {
5831 dump_stack_reset (SCHEME_A);
5832 SCHEME_V->envir = SCHEME_V->global_env;
5833 SCHEME_V->file_i = 0;
5834 SCHEME_V->load_stack[0].unget = -1;
5835 SCHEME_V->load_stack[0].kind = port_input | port_file;
5836 SCHEME_V->load_stack[0].rep.stdio.file = fin;
5837 #if USE_PORTS
5838 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5839 #endif
5840 SCHEME_V->retcode = 0;
5841
5842 #if USE_PORTS
5843 if (fin == STDIN_FILENO)
5844 SCHEME_V->interactive_repl = 1;
5845 #endif
5846
5847 #if USE_PORTS
5848 #if SHOW_ERROR_LINE
5849 SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5850
5851 if (fin != STDIN_FILENO && filename)
5852 SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5853 #endif
5854 #endif
5855
5856 SCHEME_V->inport = SCHEME_V->loadport;
5857 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5858 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5859 set_typeflag (SCHEME_V->loadport, T_ATOM);
5860
5861 if (SCHEME_V->retcode == 0)
5862 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5863 }
5864
5865 void
5866 scheme_load_string (SCHEME_P_ const char *cmd)
5867 {
5868 dump_stack_reset (SCHEME_A);
5869 SCHEME_V->envir = SCHEME_V->global_env;
5870 SCHEME_V->file_i = 0;
5871 SCHEME_V->load_stack[0].kind = port_input | port_string;
5872 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
5873 SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
5874 SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
5875 #if USE_PORTS
5876 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5877 #endif
5878 SCHEME_V->retcode = 0;
5879 SCHEME_V->interactive_repl = 0;
5880 SCHEME_V->inport = SCHEME_V->loadport;
5881 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5882 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5883 set_typeflag (SCHEME_V->loadport, T_ATOM);
5884
5885 if (SCHEME_V->retcode == 0)
5886 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5887 }
5888
5889 void
5890 scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
5891 {
5892 pointer x;
5893
5894 x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
5895
5896 if (x != NIL)
5897 set_slot_in_env (SCHEME_A_ x, value);
5898 else
5899 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
5900 }
5901
5902 #if !STANDALONE
5903
5904 void
5905 scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
5906 {
5907 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
5908 }
5909
5910 void
5911 scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
5912 {
5913 int i;
5914
5915 for (i = 0; i < count; i++)
5916 scheme_register_foreign_func (SCHEME_A_ list + i);
5917 }
5918
5919 pointer
5920 scheme_apply0 (SCHEME_P_ const char *procname)
5921 {
5922 return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
5923 }
5924
5925 void
5926 save_from_C_call (SCHEME_P)
5927 {
5928 pointer saved_data = cons (car (S_SINK),
5929 cons (SCHEME_V->envir,
5930 SCHEME_V->dump));
5931
5932 /* Push */
5933 SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
5934 /* Truncate the dump stack so TS will return here when done, not
5935 directly resume pre-C-call operations. */
5936 dump_stack_reset (SCHEME_A);
5937 }
5938
5939 void
5940 restore_from_C_call (SCHEME_P)
5941 {
5942 set_car (S_SINK, caar (SCHEME_V->c_nest));
5943 SCHEME_V->envir = cadar (SCHEME_V->c_nest);
5944 SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
5945 /* Pop */
5946 SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
5947 }
5948
5949 /* "func" and "args" are assumed to be already eval'ed. */
5950 pointer
5951 scheme_call (SCHEME_P_ pointer func, pointer args)
5952 {
5953 int old_repl = SCHEME_V->interactive_repl;
5954
5955 SCHEME_V->interactive_repl = 0;
5956 save_from_C_call (SCHEME_A);
5957 SCHEME_V->envir = SCHEME_V->global_env;
5958 SCHEME_V->args = args;
5959 SCHEME_V->code = func;
5960 SCHEME_V->retcode = 0;
5961 Eval_Cycle (SCHEME_A_ OP_APPLY);
5962 SCHEME_V->interactive_repl = old_repl;
5963 restore_from_C_call (SCHEME_A);
5964 return SCHEME_V->value;
5965 }
5966
5967 pointer
5968 scheme_eval (SCHEME_P_ pointer obj)
5969 {
5970 int old_repl = SCHEME_V->interactive_repl;
5971
5972 SCHEME_V->interactive_repl = 0;
5973 save_from_C_call (SCHEME_A);
5974 SCHEME_V->args = NIL;
5975 SCHEME_V->code = obj;
5976 SCHEME_V->retcode = 0;
5977 Eval_Cycle (SCHEME_A_ OP_EVAL);
5978 SCHEME_V->interactive_repl = old_repl;
5979 restore_from_C_call (SCHEME_A);
5980 return SCHEME_V->value;
5981 }
5982
5983 #endif
5984
5985 /* ========== Main ========== */
5986
5987 #if STANDALONE
5988
5989 int
5990 main (int argc, char **argv)
5991 {
5992 # if USE_MULTIPLICITY
5993 scheme ssc;
5994 scheme *const SCHEME_V = &ssc;
5995 # else
5996 # endif
5997 int fin;
5998 char *file_name = InitFile;
5999 int retcode;
6000 int isfile = 1;
6001 system ("ps v $PPID");//D
6002
6003 if (argc == 2 && strcmp (argv[1], "-?") == 0)
6004 {
6005 xwrstr ("Usage: tinyscheme -?\n");
6006 xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
6007 xwrstr ("followed by\n");
6008 xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
6009 xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
6010 xwrstr ("assuming that the executable is named tinyscheme.\n");
6011 xwrstr ("Use - as filename for stdin.\n");
6012 return 1;
6013 }
6014
6015 if (!scheme_init (SCHEME_A))
6016 {
6017 xwrstr ("Could not initialize!\n");
6018 return 2;
6019 }
6020
6021 # if USE_PORTS
6022 scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
6023 scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
6024 # endif
6025
6026 argv++;
6027
6028 #if 0
6029 if (access (file_name, 0) != 0)
6030 {
6031 char *p = getenv ("TINYSCHEMEINIT");
6032
6033 if (p != 0)
6034 file_name = p;
6035 }
6036 #endif
6037
6038 do
6039 {
6040 #if USE_PORTS
6041 if (strcmp (file_name, "-") == 0)
6042 fin = STDIN_FILENO;
6043 else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
6044 {
6045 pointer args = NIL;
6046
6047 isfile = file_name[1] == '1';
6048 file_name = *argv++;
6049
6050 if (strcmp (file_name, "-") == 0)
6051 fin = STDIN_FILENO;
6052 else if (isfile)
6053 fin = open (file_name, O_RDONLY);
6054
6055 for (; *argv; argv++)
6056 {
6057 pointer value = mk_string (SCHEME_A_ * argv);
6058
6059 args = cons (value, args);
6060 }
6061
6062 args = reverse_in_place (SCHEME_A_ NIL, args);
6063 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
6064
6065 }
6066 else
6067 fin = open (file_name, O_RDONLY);
6068 #endif
6069
6070 if (isfile && fin < 0)
6071 {
6072 xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
6073 }
6074 else
6075 {
6076 if (isfile)
6077 scheme_load_named_file (SCHEME_A_ fin, file_name);
6078 else
6079 scheme_load_string (SCHEME_A_ file_name);
6080
6081 #if USE_PORTS
6082 if (!isfile || fin != STDIN_FILENO)
6083 {
6084 if (SCHEME_V->retcode != 0)
6085 {
6086 xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
6087 }
6088
6089 if (isfile)
6090 close (fin);
6091 }
6092 #endif
6093 }
6094
6095 file_name = *argv++;
6096 }
6097 while (file_name != 0);
6098
6099 if (argc == 1)
6100 scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6101
6102 retcode = SCHEME_V->retcode;
6103 scheme_deinit (SCHEME_A);
6104
6105 return retcode;
6106 }
6107
6108 #endif
6109
6110 /*
6111 Local variables:
6112 c-file-style: "k&r"
6113 End:
6114 */