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

File Contents

# Content
1 /*
2 * µscheme
3 *
4 * Copyright (C) 2015 Marc Alexander Lehmann <uscheme@schmorp.de>
5 * do as you want with this, attribution appreciated.
6 *
7 * Based opn tinyscheme-1.41 (original credits follow)
8 * Dimitrios Souflis (dsouflis@acm.org)
9 * Based on MiniScheme (original credits follow)
10 * (MINISCM) coded by Atsushi Moriwaki (11/5/1989)
11 * (MINISCM) E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp
12 * (MINISCM) This version has been modified by R.C. Secrist.
13 * (MINISCM)
14 * (MINISCM) Mini-Scheme is now maintained by Akira KIDA.
15 * (MINISCM)
16 * (MINISCM) This is a revised and modified version by Akira KIDA.
17 * (MINISCM) current version is 0.85k4 (15 May 1994)
18 *
19 */
20
21 #define 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] >> 1;
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 /* the compiler will optimize this mess... */
4205 case OP_CAR: op_car: s_return (car (x));
4206 case OP_CDR: op_cdr: s_return (cdr (x));
4207 case OP_CAAR: op_caar: x = car (x); goto op_car;
4208 case OP_CADR: op_cadr: x = cdr (x); goto op_car;
4209 case OP_CDAR: op_cdar: x = car (x); goto op_cdr;
4210 case OP_CDDR: op_cddr: x = cdr (x); goto op_cdr;
4211 case OP_CAAAR: op_caaar: x = car (x); goto op_caar;
4212 case OP_CAADR: op_caadr: x = cdr (x); goto op_caar;
4213 case OP_CADAR: op_cadar: x = car (x); goto op_cadr;
4214 case OP_CADDR: op_caddr: x = cdr (x); goto op_cadr;
4215 case OP_CDAAR: op_cdaar: x = car (x); goto op_cdar;
4216 case OP_CDADR: op_cdadr: x = cdr (x); goto op_cdar;
4217 case OP_CDDAR: op_cddar: x = car (x); goto op_cddr;
4218 case OP_CDDDR: op_cdddr: x = cdr (x); goto op_cddr;
4219 case OP_CAAAAR: x = car (x); goto op_caaar;
4220 case OP_CAAADR: x = cdr (x); goto op_caaar;
4221 case OP_CAADAR: x = car (x); goto op_caadr;
4222 case OP_CAADDR: x = cdr (x); goto op_caadr;
4223 case OP_CADAAR: x = car (x); goto op_cadar;
4224 case OP_CADADR: x = cdr (x); goto op_cadar;
4225 case OP_CADDAR: x = car (x); goto op_caddr;
4226 case OP_CADDDR: x = cdr (x); goto op_caddr;
4227 case OP_CDAAAR: x = car (x); goto op_cdaar;
4228 case OP_CDAADR: x = cdr (x); goto op_cdaar;
4229 case OP_CDADAR: x = car (x); goto op_cdadr;
4230 case OP_CDADDR: x = cdr (x); goto op_cdadr;
4231 case OP_CDDAAR: x = car (x); goto op_cddar;
4232 case OP_CDDADR: x = cdr (x); goto op_cddar;
4233 case OP_CDDDAR: x = car (x); goto op_cdddr;
4234 case OP_CDDDDR: x = cdr (x); goto op_cdddr;
4235
4236 case OP_CONS: /* cons */
4237 set_cdr (args, cadr (args));
4238 s_return (args);
4239
4240 case OP_SETCAR: /* set-car! */
4241 if (!is_immutable (x))
4242 {
4243 set_car (x, cadr (args));
4244 s_return (car (args));
4245 }
4246 else
4247 Error_0 ("set-car!: unable to alter immutable pair");
4248
4249 case OP_SETCDR: /* set-cdr! */
4250 if (!is_immutable (x))
4251 {
4252 set_cdr (x, cadr (args));
4253 s_return (car (args));
4254 }
4255 else
4256 Error_0 ("set-cdr!: unable to alter immutable pair");
4257
4258 case OP_CHAR2INT: /* char->integer */
4259 s_return (mk_integer (SCHEME_A_ ivalue_unchecked (x)));
4260
4261 case OP_INT2CHAR: /* integer->char */
4262 s_return (mk_character (SCHEME_A_ ivalue_unchecked (x)));
4263
4264 case OP_CHARUPCASE:
4265 {
4266 unsigned char c = ivalue_unchecked (x);
4267 c = toupper (c);
4268 s_return (mk_character (SCHEME_A_ c));
4269 }
4270
4271 case OP_CHARDNCASE:
4272 {
4273 unsigned char c = ivalue_unchecked (x);
4274 c = tolower (c);
4275 s_return (mk_character (SCHEME_A_ c));
4276 }
4277
4278 case OP_STR2SYM: /* string->symbol */
4279 s_return (mk_symbol (SCHEME_A_ strvalue (x)));
4280
4281 case OP_STR2ATOM: /* string->atom */
4282 {
4283 char *s = strvalue (x);
4284 long pf = 0;
4285
4286 if (cdr (args) != NIL)
4287 {
4288 /* we know cadr(args) is a natural number */
4289 /* see if it is 2, 8, 10, or 16, or error */
4290 pf = ivalue_unchecked (cadr (args));
4291
4292 if (pf == 16 || pf == 10 || pf == 8 || pf == 2)
4293 {
4294 /* base is OK */
4295 }
4296 else
4297 pf = -1;
4298 }
4299
4300 if (pf < 0)
4301 Error_1 ("string->atom: bad base:", cadr (args));
4302 else if (*s == '#') /* no use of base! */
4303 s_return (mk_sharp_const (SCHEME_A_ s + 1));
4304 else
4305 {
4306 if (pf == 0 || pf == 10)
4307 s_return (mk_atom (SCHEME_A_ s));
4308 else
4309 {
4310 char *ep;
4311 long iv = strtol (s, &ep, (int) pf);
4312
4313 if (*ep == 0)
4314 s_return (mk_integer (SCHEME_A_ iv));
4315 else
4316 s_return (S_F);
4317 }
4318 }
4319 }
4320
4321 case OP_SYM2STR: /* symbol->string */
4322 x = mk_string (SCHEME_A_ symname (x));
4323 setimmutable (x);
4324 s_return (x);
4325
4326 case OP_ATOM2STR: /* atom->string */
4327 {
4328 long pf = 0;
4329
4330 if (cdr (args) != NIL)
4331 {
4332 /* we know cadr(args) is a natural number */
4333 /* see if it is 2, 8, 10, or 16, or error */
4334 pf = ivalue_unchecked (cadr (args));
4335
4336 if (is_number (x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2))
4337 {
4338 /* base is OK */
4339 }
4340 else
4341 pf = -1;
4342 }
4343
4344 if (pf < 0)
4345 Error_1 ("atom->string: bad base:", cadr (args));
4346 else if (is_number (x) || is_character (x) || is_string (x) || is_symbol (x))
4347 {
4348 char *p;
4349 int len;
4350
4351 atom2str (SCHEME_A_ x, pf, &p, &len);
4352 s_return (mk_counted_string (SCHEME_A_ p, len));
4353 }
4354 else
4355 Error_1 ("atom->string: not an atom:", x);
4356 }
4357
4358 case OP_MKSTRING: /* make-string */
4359 {
4360 int fill = cdr (args) != NIL ? charvalue (cadr (args)) : ' ';
4361 int len = ivalue_unchecked (x);
4362
4363 s_return (mk_empty_string (SCHEME_A_ len, fill));
4364 }
4365
4366 case OP_STRLEN: /* string-length */
4367 s_return (mk_integer (SCHEME_A_ strlength (x)));
4368
4369 case OP_STRREF: /* string-ref */
4370 {
4371 char *str = strvalue (x);
4372 int index = ivalue_unchecked (cadr (args));
4373
4374 if (index >= strlength (x))
4375 Error_1 ("string-ref: out of bounds:", cadr (args));
4376
4377 s_return (mk_character (SCHEME_A_ ((unsigned char *)str)[index]));
4378 }
4379
4380 case OP_STRSET: /* string-set! */
4381 {
4382 char *str = strvalue (x);
4383 int index = ivalue_unchecked (cadr (args));
4384 int c;
4385
4386 if (is_immutable (x))
4387 Error_1 ("string-set!: unable to alter immutable string:", x);
4388
4389 if (index >= strlength (x))
4390 Error_1 ("string-set!: out of bounds:", cadr (args));
4391
4392 c = charvalue (caddr (args));
4393
4394 str[index] = c;
4395 s_return (car (args));
4396 }
4397
4398 case OP_STRAPPEND: /* string-append */
4399 {
4400 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4401 int len = 0;
4402 pointer newstr;
4403 char *pos;
4404
4405 /* compute needed length for new string */
4406 for (x = args; x != NIL; x = cdr (x))
4407 len += strlength (car (x));
4408
4409 newstr = mk_empty_string (SCHEME_A_ len, ' ');
4410
4411 /* store the contents of the argument strings into the new string */
4412 for (pos = strvalue (newstr), x = args; x != NIL; pos += strlength (car (x)), x = cdr (x))
4413 memcpy (pos, strvalue (car (x)), strlength (car (x)));
4414
4415 s_return (newstr);
4416 }
4417
4418 case OP_SUBSTR: /* substring */
4419 {
4420 char *str = strvalue (x);
4421 int index0 = ivalue_unchecked (cadr (args));
4422 int index1;
4423 int len;
4424
4425 if (index0 > strlength (x))
4426 Error_1 ("substring: start out of bounds:", cadr (args));
4427
4428 if (cddr (args) != NIL)
4429 {
4430 index1 = ivalue_unchecked (caddr (args));
4431
4432 if (index1 > strlength (x) || index1 < index0)
4433 Error_1 ("substring: end out of bounds:", caddr (args));
4434 }
4435 else
4436 index1 = strlength (x);
4437
4438 len = index1 - index0;
4439 x = mk_empty_string (SCHEME_A_ len, ' ');
4440 memcpy (strvalue (x), str + index0, len);
4441 strvalue (x)[len] = 0;
4442
4443 s_return (x);
4444 }
4445
4446 case OP_VECTOR: /* vector */
4447 {
4448 int i;
4449 pointer vec;
4450 int len = list_length (SCHEME_A_ args);
4451
4452 if (len < 0)
4453 Error_1 ("vector: not a proper list:", args);
4454
4455 vec = mk_vector (SCHEME_A_ len);
4456
4457 #if USE_ERROR_CHECKING
4458 if (SCHEME_V->no_memory)
4459 s_return (S_SINK);
4460 #endif
4461
4462 for (x = args, i = 0; is_pair (x); x = cdr (x), i++)
4463 vector_set (vec, i, car (x));
4464
4465 s_return (vec);
4466 }
4467
4468 case OP_MKVECTOR: /* make-vector */
4469 {
4470 pointer fill = NIL;
4471 pointer vec;
4472 int len = ivalue_unchecked (x);
4473
4474 if (cdr (args) != NIL)
4475 fill = cadr (args);
4476
4477 vec = mk_vector (SCHEME_A_ len);
4478
4479 #if USE_ERROR_CHECKING
4480 if (SCHEME_V->no_memory)
4481 s_return (S_SINK);
4482 #endif
4483
4484 if (fill != NIL)
4485 fill_vector (vec, 0, fill);
4486
4487 s_return (vec);
4488 }
4489
4490 case OP_VECLEN: /* vector-length */
4491 s_return (mk_integer (SCHEME_A_ veclength (x)));
4492
4493 case OP_VECRESIZE:
4494 vector_resize (x, ivalue_unchecked (cadr (args)), caddr (args));
4495 s_return (x);
4496
4497 case OP_VECREF: /* vector-ref */
4498 {
4499 int index = ivalue_unchecked (cadr (args));
4500
4501 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4502 Error_1 ("vector-ref: out of bounds:", cadr (args));
4503
4504 s_return (vector_get (x, index));
4505 }
4506
4507 case OP_VECSET: /* vector-set! */
4508 {
4509 int index = ivalue_unchecked (cadr (args));
4510
4511 if (is_immutable (x))
4512 Error_1 ("vector-set!: unable to alter immutable vector:", x);
4513
4514 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4515 Error_1 ("vector-set!: out of bounds:", cadr (args));
4516
4517 vector_set (x, index, caddr (args));
4518 s_return (x);
4519 }
4520 }
4521
4522 if (USE_ERROR_CHECKING) abort ();
4523 }
4524
4525 static int
4526 opexe_2 (SCHEME_P_ enum scheme_opcodes op)
4527 {
4528 pointer x = SCHEME_V->args;
4529
4530 for (;;)
4531 {
4532 num v = nvalue (car (x));
4533 x = cdr (x);
4534
4535 if (x == NIL)
4536 break;
4537
4538 int r = num_cmp (v, nvalue (car (x)));
4539
4540 switch (op)
4541 {
4542 case OP_NUMEQ: r = r == 0; break;
4543 case OP_LESS: r = r < 0; break;
4544 case OP_GRE: r = r > 0; break;
4545 case OP_LEQ: r = r <= 0; break;
4546 case OP_GEQ: r = r >= 0; break;
4547 }
4548
4549 if (!r)
4550 s_return (S_F);
4551 }
4552
4553 s_return (S_T);
4554 }
4555
4556 static int
4557 opexe_3 (SCHEME_P_ enum scheme_opcodes op)
4558 {
4559 pointer args = SCHEME_V->args;
4560 pointer a = car (args);
4561 pointer d = cdr (args);
4562 int r;
4563
4564 switch (op)
4565 {
4566 case OP_NOT: /* not */ r = is_false (a) ; break;
4567 case OP_BOOLP: /* boolean? */ r = a == S_F || a == S_T ; break;
4568 case OP_EOFOBJP: /* eof-object? */ r = a == S_EOF ; break;
4569 case OP_NULLP: /* null? */ r = a == NIL ; break;
4570 case OP_SYMBOLP: /* symbol? */ r = is_symbol (a) ; break;
4571 case OP_GENSYMP: /* gensym? */ r = is_gensym (SCHEME_A_ a); break;
4572 case OP_NUMBERP: /* number? */ r = is_number (a) ; break;
4573 case OP_STRINGP: /* string? */ r = is_string (a) ; break;
4574 case OP_INTEGERP: /* integer? */ r = is_integer (a) ; break;
4575 case OP_REALP: /* real? */ r = is_number (a) ; break; /* all numbers are real */
4576 case OP_CHARP: /* char? */ r = is_character (a) ; break;
4577
4578 #if USE_CHAR_CLASSIFIERS
4579 case OP_CHARAP: /* char-alphabetic? */ r = Cisalpha (ivalue_unchecked (a)); break;
4580 case OP_CHARNP: /* char-numeric? */ r = Cisdigit (ivalue_unchecked (a)); break;
4581 case OP_CHARWP: /* char-whitespace? */ r = Cisspace (ivalue_unchecked (a)); break;
4582 case OP_CHARUP: /* char-upper-case? */ r = Cisupper (ivalue_unchecked (a)); break;
4583 case OP_CHARLP: /* char-lower-case? */ r = Cislower (ivalue_unchecked (a)); break;
4584 #endif
4585
4586 #if USE_PORTS
4587 case OP_PORTP: /* port? */ r = is_port (a) ; break;
4588 case OP_INPORTP: /* input-port? */ r = is_inport (a) ; break;
4589 case OP_OUTPORTP: /* output-port? */ r = is_outport (a); break;
4590 #endif
4591
4592 case OP_PROCP: /* procedure? */
4593
4594 /*--
4595 * continuation should be procedure by the example
4596 * (call-with-current-continuation procedure?) ==> #t
4597 * in R^3 report sec. 6.9
4598 */
4599 r = is_proc (a) || is_closure (a) || is_continuation (a) || is_foreign (a);
4600 break;
4601
4602 case OP_PAIRP: /* pair? */ r = is_pair (a) ; break;
4603 case OP_LISTP: /* list? */ r = list_length (SCHEME_A_ a) >= 0; break;
4604 case OP_ENVP: /* environment? */ r = is_environment (a) ; break;
4605 case OP_VECTORP: /* vector? */ r = is_vector (a) ; break;
4606 case OP_EQ: /* eq? */ r = a == cadr (args) ; break;
4607 case OP_EQV: /* eqv? */ r = eqv (a, cadr (args)) ; break;
4608 }
4609
4610 s_retbool (r);
4611 }
4612
4613 static int
4614 opexe_4 (SCHEME_P_ enum scheme_opcodes op)
4615 {
4616 pointer args = SCHEME_V->args;
4617 pointer a = car (args);
4618 pointer x, y;
4619
4620 switch (op)
4621 {
4622 case OP_FORCE: /* force */
4623 SCHEME_V->code = a;
4624
4625 if (is_promise (SCHEME_V->code))
4626 {
4627 /* Should change type to closure here */
4628 s_save (SCHEME_A_ OP_SAVE_FORCED, NIL, SCHEME_V->code);
4629 SCHEME_V->args = NIL;
4630 s_goto (OP_APPLY);
4631 }
4632 else
4633 s_return (SCHEME_V->code);
4634
4635 case OP_SAVE_FORCED: /* Save forced value replacing promise */
4636 memcpy (SCHEME_V->code, SCHEME_V->value, sizeof (struct cell));
4637 s_return (SCHEME_V->value);
4638
4639 #if USE_PORTS
4640
4641 case OP_WRITE: /* write */
4642 case OP_DISPLAY: /* display */
4643 case OP_WRITE_CHAR: /* write-char */
4644 if (is_pair (cdr (SCHEME_V->args)))
4645 {
4646 if (cadr (SCHEME_V->args) != SCHEME_V->outport)
4647 {
4648 x = cons (SCHEME_V->outport, NIL);
4649 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4650 SCHEME_V->outport = cadr (SCHEME_V->args);
4651 }
4652 }
4653
4654 SCHEME_V->args = a;
4655
4656 if (op == OP_WRITE)
4657 SCHEME_V->print_flag = 1;
4658 else
4659 SCHEME_V->print_flag = 0;
4660
4661 s_goto (OP_P0LIST);
4662
4663 case OP_NEWLINE: /* newline */
4664 if (is_pair (args))
4665 {
4666 if (a != SCHEME_V->outport)
4667 {
4668 x = cons (SCHEME_V->outport, NIL);
4669 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4670 SCHEME_V->outport = a;
4671 }
4672 }
4673
4674 putstr (SCHEME_A_ "\n");
4675 s_return (S_T);
4676 #endif
4677
4678 case OP_ERR0: /* error */
4679 SCHEME_V->retcode = -1;
4680
4681 if (!is_string (a))
4682 {
4683 args = cons (mk_string (SCHEME_A_ " -- "), args);
4684 setimmutable (car (args));
4685 }
4686
4687 putstr (SCHEME_A_ "Error: ");
4688 putstr (SCHEME_A_ strvalue (car (args)));
4689 SCHEME_V->args = cdr (args);
4690 s_goto (OP_ERR1);
4691
4692 case OP_ERR1: /* error */
4693 putstr (SCHEME_A_ " ");
4694
4695 if (args != NIL)
4696 {
4697 s_save (SCHEME_A_ OP_ERR1, cdr (args), NIL);
4698 SCHEME_V->args = a;
4699 SCHEME_V->print_flag = 1;
4700 s_goto (OP_P0LIST);
4701 }
4702 else
4703 {
4704 putstr (SCHEME_A_ "\n");
4705
4706 if (SCHEME_V->interactive_repl)
4707 s_goto (OP_T0LVL);
4708 else
4709 return -1;
4710 }
4711
4712 case OP_REVERSE: /* reverse */
4713 s_return (reverse (SCHEME_A_ a));
4714
4715 case OP_LIST_STAR: /* list* */
4716 s_return (list_star (SCHEME_A_ SCHEME_V->args));
4717
4718 case OP_APPEND: /* append */
4719 x = NIL;
4720 y = args;
4721
4722 if (y == x)
4723 s_return (x);
4724
4725 /* cdr() in the while condition is not a typo. If car() */
4726 /* is used (append '() 'a) will return the wrong result. */
4727 while (cdr (y) != NIL)
4728 {
4729 x = revappend (SCHEME_A_ x, car (y));
4730 y = cdr (y);
4731
4732 if (x == S_F)
4733 Error_0 ("non-list argument to append");
4734 }
4735
4736 s_return (reverse_in_place (SCHEME_A_ car (y), x));
4737
4738 #if USE_PLIST
4739
4740 case OP_PUT: /* put */
4741 if (!hasprop (a) || !hasprop (cadr (args)))
4742 Error_0 ("illegal use of put");
4743
4744 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4745 {
4746 if (caar (x) == y)
4747 break;
4748 }
4749
4750 if (x != NIL)
4751 cdar (x) = caddr (args);
4752 else
4753 symprop (a) = cons (cons (y, caddr (args)), symprop (a));
4754
4755 s_return (S_T);
4756
4757 case OP_GET: /* get */
4758 if (!hasprop (a) || !hasprop (cadr (args)))
4759 Error_0 ("illegal use of get");
4760
4761 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4762 if (caar (x) == y)
4763 break;
4764
4765 if (x != NIL)
4766 s_return (cdar (x));
4767 else
4768 s_return (NIL);
4769
4770 #endif /* USE_PLIST */
4771
4772 case OP_QUIT: /* quit */
4773 if (is_pair (args))
4774 SCHEME_V->retcode = ivalue (a);
4775
4776 return -1;
4777
4778 case OP_GC: /* gc */
4779 gc (SCHEME_A_ NIL, NIL);
4780 s_return (S_T);
4781
4782 case OP_GCVERB: /* gc-verbose */
4783 {
4784 int was = SCHEME_V->gc_verbose;
4785
4786 SCHEME_V->gc_verbose = (a != S_F);
4787 s_retbool (was);
4788 }
4789
4790 case OP_NEWSEGMENT: /* new-segment */
4791 if (!is_pair (args) || !is_number (a))
4792 Error_0 ("new-segment: argument must be a number");
4793
4794 alloc_cellseg (SCHEME_A_ ivalue (a));
4795
4796 s_return (S_T);
4797
4798 case OP_OBLIST: /* oblist */
4799 s_return (oblist_all_symbols (SCHEME_A));
4800
4801 #if USE_PORTS
4802
4803 case OP_CURR_INPORT: /* current-input-port */
4804 s_return (SCHEME_V->inport);
4805
4806 case OP_CURR_OUTPORT: /* current-output-port */
4807 s_return (SCHEME_V->outport);
4808
4809 case OP_OPEN_INFILE: /* open-input-file */
4810 case OP_OPEN_OUTFILE: /* open-output-file */
4811 case OP_OPEN_INOUTFILE: /* open-input-output-file */
4812 {
4813 int prop = 0;
4814 pointer p;
4815
4816 switch (op)
4817 {
4818 case OP_OPEN_INFILE:
4819 prop = port_input;
4820 break;
4821
4822 case OP_OPEN_OUTFILE:
4823 prop = port_output;
4824 break;
4825
4826 case OP_OPEN_INOUTFILE:
4827 prop = port_input | port_output;
4828 break;
4829 }
4830
4831 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
4832
4833 s_return (p == NIL ? S_F : p);
4834 }
4835
4836 # if USE_STRING_PORTS
4837
4838 case OP_OPEN_INSTRING: /* open-input-string */
4839 case OP_OPEN_INOUTSTRING: /* open-input-output-string */
4840 {
4841 int prop = 0;
4842 pointer p;
4843
4844 switch (op)
4845 {
4846 case OP_OPEN_INSTRING:
4847 prop = port_input;
4848 break;
4849
4850 case OP_OPEN_INOUTSTRING:
4851 prop = port_input | port_output;
4852 break;
4853 }
4854
4855 p = port_from_string (SCHEME_A_ strvalue (a),
4856 strvalue (a) + strlength (a), prop);
4857
4858 s_return (p == NIL ? S_F : p);
4859 }
4860
4861 case OP_OPEN_OUTSTRING: /* open-output-string */
4862 {
4863 pointer p;
4864
4865 if (a == NIL)
4866 p = port_from_scratch (SCHEME_A);
4867 else
4868 p = port_from_string (SCHEME_A_ strvalue (a),
4869 strvalue (a) + strlength (a), port_output);
4870
4871 s_return (p == NIL ? S_F : p);
4872 }
4873
4874 case OP_GET_OUTSTRING: /* get-output-string */
4875 {
4876 port *p;
4877
4878 if ((p = a->object.port)->kind & port_string)
4879 {
4880 off_t size;
4881 char *str;
4882
4883 size = p->rep.string.curr - p->rep.string.start + 1;
4884 str = malloc (size);
4885
4886 if (str != NULL)
4887 {
4888 pointer s;
4889
4890 memcpy (str, p->rep.string.start, size - 1);
4891 str[size - 1] = '\0';
4892 s = mk_string (SCHEME_A_ str);
4893 free (str);
4894 s_return (s);
4895 }
4896 }
4897
4898 s_return (S_F);
4899 }
4900
4901 # endif
4902
4903 case OP_CLOSE_INPORT: /* close-input-port */
4904 port_close (SCHEME_A_ a, port_input);
4905 s_return (S_T);
4906
4907 case OP_CLOSE_OUTPORT: /* close-output-port */
4908 port_close (SCHEME_A_ a, port_output);
4909 s_return (S_T);
4910 #endif
4911
4912 case OP_INT_ENV: /* interaction-environment */
4913 s_return (SCHEME_V->global_env);
4914
4915 case OP_CURR_ENV: /* current-environment */
4916 s_return (SCHEME_V->envir);
4917
4918 }
4919
4920 if (USE_ERROR_CHECKING) abort ();
4921 }
4922
4923 static int
4924 opexe_5 (SCHEME_P_ enum scheme_opcodes op)
4925 {
4926 pointer args = SCHEME_V->args;
4927 pointer x;
4928
4929 if (SCHEME_V->nesting != 0)
4930 {
4931 int n = SCHEME_V->nesting;
4932
4933 SCHEME_V->nesting = 0;
4934 SCHEME_V->retcode = -1;
4935 Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
4936 }
4937
4938 switch (op)
4939 {
4940 /* ========== reading part ========== */
4941 #if USE_PORTS
4942 case OP_READ:
4943 if (!is_pair (args))
4944 s_goto (OP_READ_INTERNAL);
4945
4946 if (!is_inport (car (args)))
4947 Error_1 ("read: not an input port:", car (args));
4948
4949 if (car (args) == SCHEME_V->inport)
4950 s_goto (OP_READ_INTERNAL);
4951
4952 x = SCHEME_V->inport;
4953 SCHEME_V->inport = car (args);
4954 x = cons (x, NIL);
4955 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4956 s_goto (OP_READ_INTERNAL);
4957
4958 case OP_READ_CHAR: /* read-char */
4959 case OP_PEEK_CHAR: /* peek-char */
4960 {
4961 int c;
4962
4963 if (is_pair (args))
4964 {
4965 if (car (args) != SCHEME_V->inport)
4966 {
4967 x = SCHEME_V->inport;
4968 x = cons (x, NIL);
4969 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4970 SCHEME_V->inport = car (args);
4971 }
4972 }
4973
4974 c = inchar (SCHEME_A);
4975
4976 if (c == EOF)
4977 s_return (S_EOF);
4978
4979 if (SCHEME_V->op == OP_PEEK_CHAR)
4980 backchar (SCHEME_A_ c);
4981
4982 s_return (mk_character (SCHEME_A_ c));
4983 }
4984
4985 case OP_CHAR_READY: /* char-ready? */
4986 {
4987 pointer p = SCHEME_V->inport;
4988 int res;
4989
4990 if (is_pair (args))
4991 p = car (args);
4992
4993 res = p->object.port->kind & port_string;
4994
4995 s_retbool (res);
4996 }
4997
4998 case OP_SET_INPORT: /* set-input-port */
4999 SCHEME_V->inport = car (args);
5000 s_return (SCHEME_V->value);
5001
5002 case OP_SET_OUTPORT: /* set-output-port */
5003 SCHEME_V->outport = car (args);
5004 s_return (SCHEME_V->value);
5005 #endif
5006
5007 case OP_RDSEXPR:
5008 switch (SCHEME_V->tok)
5009 {
5010 case TOK_EOF:
5011 s_return (S_EOF);
5012 /* NOTREACHED */
5013
5014 case TOK_VEC:
5015 s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
5016 /* fall through */
5017
5018 case TOK_LPAREN:
5019 SCHEME_V->tok = token (SCHEME_A);
5020
5021 if (SCHEME_V->tok == TOK_RPAREN)
5022 s_return (NIL);
5023 else if (SCHEME_V->tok == TOK_DOT)
5024 Error_0 ("syntax error: illegal dot expression");
5025 else
5026 {
5027 SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
5028 s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
5029 s_goto (OP_RDSEXPR);
5030 }
5031
5032 case TOK_QUOTE:
5033 s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
5034 SCHEME_V->tok = token (SCHEME_A);
5035 s_goto (OP_RDSEXPR);
5036
5037 case TOK_BQUOTE:
5038 SCHEME_V->tok = token (SCHEME_A);
5039
5040 if (SCHEME_V->tok == TOK_VEC)
5041 {
5042 s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
5043 SCHEME_V->tok = TOK_LPAREN;
5044 s_goto (OP_RDSEXPR);
5045 }
5046 else
5047 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
5048
5049 s_goto (OP_RDSEXPR);
5050
5051 case TOK_COMMA:
5052 s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
5053 SCHEME_V->tok = token (SCHEME_A);
5054 s_goto (OP_RDSEXPR);
5055
5056 case TOK_ATMARK:
5057 s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
5058 SCHEME_V->tok = token (SCHEME_A);
5059 s_goto (OP_RDSEXPR);
5060
5061 case TOK_ATOM:
5062 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS)));
5063
5064 case TOK_DOTATOM:
5065 SCHEME_V->strbuff[0] = '.';
5066 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ 1, DELIMITERS)));
5067
5068 case TOK_STRATOM:
5069 x = readstrexp (SCHEME_A_ '|');
5070 //TODO: haven't checked whether the garbage collector could interfere
5071 s_return (mk_atom (SCHEME_A_ strvalue (x)));
5072
5073 case TOK_DQUOTE:
5074 x = readstrexp (SCHEME_A_ '"');
5075
5076 if (x == S_F)
5077 Error_0 ("Error reading string");
5078
5079 setimmutable (x);
5080 s_return (x);
5081
5082 case TOK_SHARP:
5083 {
5084 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
5085
5086 if (f == NIL)
5087 Error_0 ("undefined sharp expression");
5088 else
5089 {
5090 SCHEME_V->code = cons (slot_value_in_env (f), NIL);
5091 s_goto (OP_EVAL);
5092 }
5093 }
5094
5095 case TOK_SHARP_CONST:
5096 if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS))) == NIL)
5097 Error_0 ("undefined sharp expression");
5098 else
5099 s_return (x);
5100
5101 default:
5102 Error_0 ("syntax error: illegal token");
5103 }
5104
5105 break;
5106
5107 case OP_RDLIST:
5108 SCHEME_V->args = cons (SCHEME_V->value, args);
5109 SCHEME_V->tok = token (SCHEME_A);
5110
5111 switch (SCHEME_V->tok)
5112 {
5113 case TOK_EOF:
5114 s_return (S_EOF);
5115
5116 case TOK_RPAREN:
5117 {
5118 int c = inchar (SCHEME_A);
5119
5120 if (c != '\n')
5121 backchar (SCHEME_A_ c);
5122 #if SHOW_ERROR_LINE
5123 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5124 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5125 #endif
5126
5127 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5128 s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5129 }
5130
5131 case TOK_DOT:
5132 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5133 SCHEME_V->tok = token (SCHEME_A);
5134 s_goto (OP_RDSEXPR);
5135
5136 default:
5137 s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5138 s_goto (OP_RDSEXPR);
5139 }
5140
5141 case OP_RDDOT:
5142 if (token (SCHEME_A) != TOK_RPAREN)
5143 Error_0 ("syntax error: illegal dot expression");
5144
5145 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5146 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5147
5148 case OP_RDQUOTE:
5149 s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5150
5151 case OP_RDQQUOTE:
5152 s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5153
5154 case OP_RDQQUOTEVEC:
5155 s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5156 cons (mk_symbol (SCHEME_A_ "vector"),
5157 cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5158
5159 case OP_RDUNQUOTE:
5160 s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5161
5162 case OP_RDUQTSP:
5163 s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5164
5165 case OP_RDVEC:
5166 /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5167 s_goto(OP_EVAL); Cannot be quoted */
5168 /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5169 s_return(x); Cannot be part of pairs */
5170 /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5171 SCHEME_V->args=SCHEME_V->value;
5172 s_goto(OP_APPLY); */
5173 SCHEME_V->args = SCHEME_V->value;
5174 s_goto (OP_VECTOR);
5175
5176 /* ========== printing part ========== */
5177 case OP_P0LIST:
5178 if (is_vector (args))
5179 {
5180 putstr (SCHEME_A_ "#(");
5181 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5182 s_goto (OP_PVECFROM);
5183 }
5184 else if (is_environment (args))
5185 {
5186 putstr (SCHEME_A_ "#<ENVIRONMENT>");
5187 s_return (S_T);
5188 }
5189 else if (!is_pair (args))
5190 {
5191 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5192 s_return (S_T);
5193 }
5194 else
5195 {
5196 pointer a = car (args);
5197 pointer b = cdr (args);
5198 int ok_abbr = ok_abbrev (b);
5199 SCHEME_V->args = car (b);
5200
5201 if (a == SCHEME_V->QUOTE && ok_abbr)
5202 putstr (SCHEME_A_ "'");
5203 else if (a == SCHEME_V->QQUOTE && ok_abbr)
5204 putstr (SCHEME_A_ "`");
5205 else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5206 putstr (SCHEME_A_ ",");
5207 else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5208 putstr (SCHEME_A_ ",@");
5209 else
5210 {
5211 putstr (SCHEME_A_ "(");
5212 s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5213 SCHEME_V->args = a;
5214 }
5215
5216 s_goto (OP_P0LIST);
5217 }
5218
5219 case OP_P1LIST:
5220 if (is_pair (args))
5221 {
5222 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5223 putstr (SCHEME_A_ " ");
5224 SCHEME_V->args = car (args);
5225 s_goto (OP_P0LIST);
5226 }
5227 else if (is_vector (args))
5228 {
5229 s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5230 putstr (SCHEME_A_ " . ");
5231 s_goto (OP_P0LIST);
5232 }
5233 else
5234 {
5235 if (args != NIL)
5236 {
5237 putstr (SCHEME_A_ " . ");
5238 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5239 }
5240
5241 putstr (SCHEME_A_ ")");
5242 s_return (S_T);
5243 }
5244
5245 case OP_PVECFROM:
5246 {
5247 int i = ivalue_unchecked (cdr (args));
5248 pointer vec = car (args);
5249 int len = veclength (vec);
5250
5251 if (i == len)
5252 {
5253 putstr (SCHEME_A_ ")");
5254 s_return (S_T);
5255 }
5256 else
5257 {
5258 pointer elem = vector_get (vec, i);
5259
5260 ivalue_unchecked (cdr (args)) = i + 1;
5261 s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5262 SCHEME_V->args = elem;
5263
5264 if (i > 0)
5265 putstr (SCHEME_A_ " ");
5266
5267 s_goto (OP_P0LIST);
5268 }
5269 }
5270 }
5271
5272 if (USE_ERROR_CHECKING) abort ();
5273 }
5274
5275 static int
5276 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5277 {
5278 pointer args = SCHEME_V->args;
5279 pointer a = car (args);
5280 pointer x, y;
5281
5282 switch (op)
5283 {
5284 case OP_LIST_LENGTH: /* length *//* a.k */
5285 {
5286 long v = list_length (SCHEME_A_ a);
5287
5288 if (v < 0)
5289 Error_1 ("length: not a list:", a);
5290
5291 s_return (mk_integer (SCHEME_A_ v));
5292 }
5293
5294 case OP_ASSQ: /* assq *//* a.k */
5295 x = a;
5296
5297 for (y = cadr (args); is_pair (y); y = cdr (y))
5298 {
5299 if (!is_pair (car (y)))
5300 Error_0 ("unable to handle non pair element");
5301
5302 if (x == caar (y))
5303 break;
5304 }
5305
5306 if (is_pair (y))
5307 s_return (car (y));
5308 else
5309 s_return (S_F);
5310
5311
5312 case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5313 SCHEME_V->args = a;
5314
5315 if (SCHEME_V->args == NIL)
5316 s_return (S_F);
5317 else if (is_closure (SCHEME_V->args))
5318 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5319 else if (is_macro (SCHEME_V->args))
5320 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5321 else
5322 s_return (S_F);
5323
5324 case OP_CLOSUREP: /* closure? */
5325 /*
5326 * Note, macro object is also a closure.
5327 * Therefore, (closure? <#MACRO>) ==> #t
5328 * (schmorp) well, obviously not, fix? TODO
5329 */
5330 s_retbool (is_closure (a));
5331
5332 case OP_MACROP: /* macro? */
5333 s_retbool (is_macro (a));
5334 }
5335
5336 if (USE_ERROR_CHECKING) abort ();
5337 }
5338
5339 /* dispatch functions (opexe_x) return new opcode, or 0 for same opcode, or -1 to stop */
5340 typedef int (*dispatch_func)(SCHEME_P_ enum scheme_opcodes);
5341
5342 typedef int (*test_predicate)(pointer);
5343 static int
5344 tst_any (pointer p)
5345 {
5346 return 1;
5347 }
5348
5349 static int
5350 tst_inonneg (pointer p)
5351 {
5352 return is_integer (p) && ivalue_unchecked (p) >= 0;
5353 }
5354
5355 static int
5356 tst_is_list (SCHEME_P_ pointer p)
5357 {
5358 return p == NIL || is_pair (p);
5359 }
5360
5361 /* Correspond carefully with following defines! */
5362 static struct
5363 {
5364 test_predicate fct;
5365 const char *kind;
5366 } tests[] = {
5367 { tst_any , 0 },
5368 { is_string , "string" },
5369 { is_symbol , "symbol" },
5370 { is_port , "port" },
5371 { is_inport , "input port" },
5372 { is_outport , "output port" },
5373 { is_environment, "environment" },
5374 { is_pair , "pair" },
5375 { 0 , "pair or '()" },
5376 { is_character , "character" },
5377 { is_vector , "vector" },
5378 { is_number , "number" },
5379 { is_integer , "integer" },
5380 { tst_inonneg , "non-negative integer" }
5381 };
5382
5383 #define TST_NONE 0 /* TST_NONE used for built-ins, 0 for internal ops */
5384 #define TST_ANY "\001"
5385 #define TST_STRING "\002"
5386 #define TST_SYMBOL "\003"
5387 #define TST_PORT "\004"
5388 #define TST_INPORT "\005"
5389 #define TST_OUTPORT "\006"
5390 #define TST_ENVIRONMENT "\007"
5391 #define TST_PAIR "\010"
5392 #define TST_LIST "\011"
5393 #define TST_CHAR "\012"
5394 #define TST_VECTOR "\013"
5395 #define TST_NUMBER "\014"
5396 #define TST_INTEGER "\015"
5397 #define TST_NATURAL "\016"
5398
5399 #define INF_ARG 0xff
5400 #define UNNAMED_OP ""
5401
5402 static const char opnames[] =
5403 #define OP_DEF(func,name,minarity,maxarity,argtest,op) name "\x00"
5404 #include "opdefines.h"
5405 #undef OP_DEF
5406 ;
5407
5408 static const char *
5409 opname (int idx)
5410 {
5411 const char *name = opnames;
5412
5413 /* should do this at compile time, but would require external program, right? */
5414 while (idx--)
5415 name += strlen (name) + 1;
5416
5417 return *name ? name : "ILLEGAL";
5418 }
5419
5420 static const char *
5421 procname (pointer x)
5422 {
5423 return opname (procnum (x));
5424 }
5425
5426 typedef struct
5427 {
5428 uint8_t func;
5429 /*dispatch_func func;*//*TODO: maybe optionally keep the pointer, for speed? */
5430 uint8_t builtin;
5431 #if USE_ERROR_CHECKING
5432 uint8_t min_arity;
5433 uint8_t max_arity;
5434 char arg_tests_encoding[3];
5435 #endif
5436 } op_code_info;
5437
5438 static const op_code_info dispatch_table[] = {
5439 #if USE_ERROR_CHECKING
5440 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1, minarity, maxarity, argtest },
5441 #else
5442 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1 },
5443 #endif
5444 #include "opdefines.h"
5445 #undef OP_DEF
5446 {0}
5447 };
5448
5449 /* kernel of this interpreter */
5450 static void ecb_hot
5451 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5452 {
5453 SCHEME_V->op = op;
5454
5455 for (;;)
5456 {
5457 const op_code_info *pcd = dispatch_table + SCHEME_V->op;
5458
5459 #if USE_ERROR_CHECKING
5460 if (pcd->builtin) /* if built-in function, check arguments */
5461 {
5462 char msg[STRBUFFSIZE];
5463 int n = list_length (SCHEME_A_ SCHEME_V->args);
5464
5465 /* Check number of arguments */
5466 if (ecb_expect_false (n < pcd->min_arity))
5467 {
5468 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5469 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5470 xError_1 (SCHEME_A_ msg, 0);
5471 continue;
5472 }
5473 else if (ecb_expect_false (n > pcd->max_arity && pcd->max_arity != INF_ARG))
5474 {
5475 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5476 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5477 xError_1 (SCHEME_A_ msg, 0);
5478 continue;
5479 }
5480 else
5481 {
5482 if (*pcd->arg_tests_encoding) /* literal 0 and TST_NONE treated the same */
5483 {
5484 int i = 0;
5485 int j;
5486 const char *t = pcd->arg_tests_encoding;
5487 pointer arglist = SCHEME_V->args;
5488
5489 do
5490 {
5491 pointer arg = car (arglist);
5492
5493 j = t[0];
5494
5495 /*TODO: tst_is_list has different prototype - fix if other tests acquire same prototype */
5496 if (j == TST_LIST[0])
5497 {
5498 if (!tst_is_list (SCHEME_A_ arg))
5499 break;
5500 }
5501 else
5502 {
5503 if (!tests[j - 1].fct (arg))
5504 break;
5505 }
5506
5507 if (t < pcd->arg_tests_encoding + sizeof (pcd->arg_tests_encoding) - 1 && t[1]) /* last test is replicated as necessary */
5508 t++;
5509
5510 arglist = cdr (arglist);
5511 i++;
5512 }
5513 while (i < n);
5514
5515 if (i < n)
5516 {
5517 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", opname (SCHEME_V->op), i + 1, tests[j].kind);
5518 xError_1 (SCHEME_A_ msg, 0);
5519 continue;
5520 }
5521 }
5522 }
5523 }
5524 #endif
5525
5526 ok_to_freely_gc (SCHEME_A);
5527
5528 static const dispatch_func dispatch_funcs[] = {
5529 opexe_0,
5530 opexe_1,
5531 opexe_2,
5532 opexe_3,
5533 opexe_4,
5534 opexe_5,
5535 opexe_6,
5536 };
5537
5538 if (ecb_expect_false (dispatch_funcs [pcd->func] (SCHEME_A_ SCHEME_V->op) != 0))
5539 return;
5540
5541 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5542 {
5543 xwrstr ("No memory!\n");
5544 return;
5545 }
5546 }
5547 }
5548
5549 /* ========== Initialization of internal keywords ========== */
5550
5551 static void
5552 assign_syntax (SCHEME_P_ const char *name)
5553 {
5554 pointer x = oblist_add_by_name (SCHEME_A_ name);
5555 set_typeflag (x, typeflag (x) | T_SYNTAX);
5556 }
5557
5558 static void
5559 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5560 {
5561 pointer x = mk_symbol (SCHEME_A_ name);
5562 pointer y = mk_proc (SCHEME_A_ op);
5563 new_slot_in_env (SCHEME_A_ x, y);
5564 }
5565
5566 static pointer
5567 mk_proc (SCHEME_P_ enum scheme_opcodes op)
5568 {
5569 pointer y = get_cell (SCHEME_A_ NIL, NIL);
5570 set_typeflag (y, (T_PROC | T_ATOM));
5571 ivalue_unchecked (y) = op;
5572 return y;
5573 }
5574
5575 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5576 static int
5577 syntaxnum (pointer p)
5578 {
5579 const char *s = strvalue (p);
5580
5581 switch (strlength (p))
5582 {
5583 case 2:
5584 if (s[0] == 'i')
5585 return OP_IF0; /* if */
5586 else
5587 return OP_OR0; /* or */
5588
5589 case 3:
5590 if (s[0] == 'a')
5591 return OP_AND0; /* and */
5592 else
5593 return OP_LET0; /* let */
5594
5595 case 4:
5596 switch (s[3])
5597 {
5598 case 'e':
5599 return OP_CASE0; /* case */
5600
5601 case 'd':
5602 return OP_COND0; /* cond */
5603
5604 case '*':
5605 return OP_LET0AST;/* let* */
5606
5607 default:
5608 return OP_SET0; /* set! */
5609 }
5610
5611 case 5:
5612 switch (s[2])
5613 {
5614 case 'g':
5615 return OP_BEGIN; /* begin */
5616
5617 case 'l':
5618 return OP_DELAY; /* delay */
5619
5620 case 'c':
5621 return OP_MACRO0; /* macro */
5622
5623 default:
5624 return OP_QUOTE; /* quote */
5625 }
5626
5627 case 6:
5628 switch (s[2])
5629 {
5630 case 'm':
5631 return OP_LAMBDA; /* lambda */
5632
5633 case 'f':
5634 return OP_DEF0; /* define */
5635
5636 default:
5637 return OP_LET0REC;/* letrec */
5638 }
5639
5640 default:
5641 return OP_C0STREAM; /* cons-stream */
5642 }
5643 }
5644
5645 #if USE_MULTIPLICITY
5646 ecb_cold scheme *
5647 scheme_init_new ()
5648 {
5649 scheme *sc = malloc (sizeof (scheme));
5650
5651 if (!scheme_init (SCHEME_A))
5652 {
5653 free (SCHEME_A);
5654 return 0;
5655 }
5656 else
5657 return sc;
5658 }
5659 #endif
5660
5661 ecb_cold int
5662 scheme_init (SCHEME_P)
5663 {
5664 int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5665 pointer x;
5666
5667 num_set_fixnum (num_zero, 1);
5668 num_set_ivalue (num_zero, 0);
5669 num_set_fixnum (num_one, 1);
5670 num_set_ivalue (num_one, 1);
5671
5672 #if USE_INTERFACE
5673 SCHEME_V->vptr = &vtbl;
5674 #endif
5675 SCHEME_V->gensym_cnt = 0;
5676 SCHEME_V->last_cell_seg = -1;
5677 SCHEME_V->free_cell = NIL;
5678 SCHEME_V->fcells = 0;
5679 SCHEME_V->no_memory = 0;
5680 SCHEME_V->inport = NIL;
5681 SCHEME_V->outport = NIL;
5682 SCHEME_V->save_inport = NIL;
5683 SCHEME_V->loadport = NIL;
5684 SCHEME_V->nesting = 0;
5685 SCHEME_V->interactive_repl = 0;
5686
5687 if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5688 {
5689 #if USE_ERROR_CHECKING
5690 SCHEME_V->no_memory = 1;
5691 return 0;
5692 #endif
5693 }
5694
5695 SCHEME_V->gc_verbose = 0;
5696 dump_stack_initialize (SCHEME_A);
5697 SCHEME_V->code = NIL;
5698 SCHEME_V->args = NIL;
5699 SCHEME_V->envir = NIL;
5700 SCHEME_V->tracing = 0;
5701
5702 /* init NIL */
5703 set_typeflag (NIL, T_ATOM | T_MARK);
5704 set_car (NIL, NIL);
5705 set_cdr (NIL, NIL);
5706 /* init T */
5707 set_typeflag (S_T, T_ATOM | T_MARK);
5708 set_car (S_T, S_T);
5709 set_cdr (S_T, S_T);
5710 /* init F */
5711 set_typeflag (S_F, T_ATOM | T_MARK);
5712 set_car (S_F, S_F);
5713 set_cdr (S_F, S_F);
5714 /* init EOF_OBJ */
5715 set_typeflag (S_EOF, T_ATOM | T_MARK);
5716 set_car (S_EOF, S_EOF);
5717 set_cdr (S_EOF, S_EOF);
5718 /* init sink */
5719 set_typeflag (S_SINK, T_PAIR | T_MARK);
5720 set_car (S_SINK, NIL);
5721
5722 /* init c_nest */
5723 SCHEME_V->c_nest = NIL;
5724
5725 SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5726 /* init global_env */
5727 new_frame_in_env (SCHEME_A_ NIL);
5728 SCHEME_V->global_env = SCHEME_V->envir;
5729 /* init else */
5730 x = mk_symbol (SCHEME_A_ "else");
5731 new_slot_in_env (SCHEME_A_ x, S_T);
5732
5733 {
5734 static const char *syntax_names[] = {
5735 "lambda", "quote", "define", "if", "begin", "set!",
5736 "let", "let*", "letrec", "cond", "delay", "and",
5737 "or", "cons-stream", "macro", "case"
5738 };
5739
5740 for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5741 assign_syntax (SCHEME_A_ syntax_names[i]);
5742 }
5743
5744 // TODO: should iterate via strlen, to avoid n² complexity
5745 for (i = 0; i < n; i++)
5746 if (dispatch_table[i].builtin)
5747 assign_proc (SCHEME_A_ i, opname (i));
5748
5749 /* initialization of global pointers to special symbols */
5750 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5751 SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5752 SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5753 SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5754 SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5755 SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5756 SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5757 SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5758 SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5759 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5760
5761 return !SCHEME_V->no_memory;
5762 }
5763
5764 #if USE_PORTS
5765 void
5766 scheme_set_input_port_file (SCHEME_P_ int fin)
5767 {
5768 SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5769 }
5770
5771 void
5772 scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5773 {
5774 SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5775 }
5776
5777 void
5778 scheme_set_output_port_file (SCHEME_P_ int fout)
5779 {
5780 SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5781 }
5782
5783 void
5784 scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5785 {
5786 SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5787 }
5788 #endif
5789
5790 void
5791 scheme_set_external_data (SCHEME_P_ void *p)
5792 {
5793 SCHEME_V->ext_data = p;
5794 }
5795
5796 ecb_cold void
5797 scheme_deinit (SCHEME_P)
5798 {
5799 int i;
5800
5801 #if SHOW_ERROR_LINE
5802 char *fname;
5803 #endif
5804
5805 SCHEME_V->oblist = NIL;
5806 SCHEME_V->global_env = NIL;
5807 dump_stack_free (SCHEME_A);
5808 SCHEME_V->envir = NIL;
5809 SCHEME_V->code = NIL;
5810 SCHEME_V->args = NIL;
5811 SCHEME_V->value = NIL;
5812
5813 if (is_port (SCHEME_V->inport))
5814 set_typeflag (SCHEME_V->inport, T_ATOM);
5815
5816 SCHEME_V->inport = NIL;
5817 SCHEME_V->outport = NIL;
5818
5819 if (is_port (SCHEME_V->save_inport))
5820 set_typeflag (SCHEME_V->save_inport, T_ATOM);
5821
5822 SCHEME_V->save_inport = NIL;
5823
5824 if (is_port (SCHEME_V->loadport))
5825 set_typeflag (SCHEME_V->loadport, T_ATOM);
5826
5827 SCHEME_V->loadport = NIL;
5828 SCHEME_V->gc_verbose = 0;
5829 gc (SCHEME_A_ NIL, NIL);
5830
5831 for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5832 free (SCHEME_V->alloc_seg[i]);
5833
5834 #if SHOW_ERROR_LINE
5835 for (i = 0; i <= SCHEME_V->file_i; i++)
5836 {
5837 if (SCHEME_V->load_stack[i].kind & port_file)
5838 {
5839 fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5840
5841 if (fname)
5842 free (fname);
5843 }
5844 }
5845 #endif
5846 }
5847
5848 void
5849 scheme_load_file (SCHEME_P_ int fin)
5850 {
5851 scheme_load_named_file (SCHEME_A_ fin, 0);
5852 }
5853
5854 void
5855 scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5856 {
5857 dump_stack_reset (SCHEME_A);
5858 SCHEME_V->envir = SCHEME_V->global_env;
5859 SCHEME_V->file_i = 0;
5860 SCHEME_V->load_stack[0].unget = -1;
5861 SCHEME_V->load_stack[0].kind = port_input | port_file;
5862 SCHEME_V->load_stack[0].rep.stdio.file = fin;
5863 #if USE_PORTS
5864 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5865 #endif
5866 SCHEME_V->retcode = 0;
5867
5868 #if USE_PORTS
5869 if (fin == STDIN_FILENO)
5870 SCHEME_V->interactive_repl = 1;
5871 #endif
5872
5873 #if USE_PORTS
5874 #if SHOW_ERROR_LINE
5875 SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5876
5877 if (fin != STDIN_FILENO && filename)
5878 SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5879 #endif
5880 #endif
5881
5882 SCHEME_V->inport = SCHEME_V->loadport;
5883 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5884 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5885 set_typeflag (SCHEME_V->loadport, T_ATOM);
5886
5887 if (SCHEME_V->retcode == 0)
5888 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5889 }
5890
5891 void
5892 scheme_load_string (SCHEME_P_ const char *cmd)
5893 {
5894 dump_stack_reset (SCHEME_A);
5895 SCHEME_V->envir = SCHEME_V->global_env;
5896 SCHEME_V->file_i = 0;
5897 SCHEME_V->load_stack[0].kind = port_input | port_string;
5898 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
5899 SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
5900 SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
5901 #if USE_PORTS
5902 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5903 #endif
5904 SCHEME_V->retcode = 0;
5905 SCHEME_V->interactive_repl = 0;
5906 SCHEME_V->inport = SCHEME_V->loadport;
5907 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5908 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5909 set_typeflag (SCHEME_V->loadport, T_ATOM);
5910
5911 if (SCHEME_V->retcode == 0)
5912 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5913 }
5914
5915 void
5916 scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
5917 {
5918 pointer x;
5919
5920 x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
5921
5922 if (x != NIL)
5923 set_slot_in_env (SCHEME_A_ x, value);
5924 else
5925 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
5926 }
5927
5928 #if !STANDALONE
5929
5930 void
5931 scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
5932 {
5933 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
5934 }
5935
5936 void
5937 scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
5938 {
5939 int i;
5940
5941 for (i = 0; i < count; i++)
5942 scheme_register_foreign_func (SCHEME_A_ list + i);
5943 }
5944
5945 pointer
5946 scheme_apply0 (SCHEME_P_ const char *procname)
5947 {
5948 return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
5949 }
5950
5951 void
5952 save_from_C_call (SCHEME_P)
5953 {
5954 pointer saved_data = cons (car (S_SINK),
5955 cons (SCHEME_V->envir,
5956 SCHEME_V->dump));
5957
5958 /* Push */
5959 SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
5960 /* Truncate the dump stack so TS will return here when done, not
5961 directly resume pre-C-call operations. */
5962 dump_stack_reset (SCHEME_A);
5963 }
5964
5965 void
5966 restore_from_C_call (SCHEME_P)
5967 {
5968 set_car (S_SINK, caar (SCHEME_V->c_nest));
5969 SCHEME_V->envir = cadar (SCHEME_V->c_nest);
5970 SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
5971 /* Pop */
5972 SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
5973 }
5974
5975 /* "func" and "args" are assumed to be already eval'ed. */
5976 pointer
5977 scheme_call (SCHEME_P_ pointer func, pointer args)
5978 {
5979 int old_repl = SCHEME_V->interactive_repl;
5980
5981 SCHEME_V->interactive_repl = 0;
5982 save_from_C_call (SCHEME_A);
5983 SCHEME_V->envir = SCHEME_V->global_env;
5984 SCHEME_V->args = args;
5985 SCHEME_V->code = func;
5986 SCHEME_V->retcode = 0;
5987 Eval_Cycle (SCHEME_A_ OP_APPLY);
5988 SCHEME_V->interactive_repl = old_repl;
5989 restore_from_C_call (SCHEME_A);
5990 return SCHEME_V->value;
5991 }
5992
5993 pointer
5994 scheme_eval (SCHEME_P_ pointer obj)
5995 {
5996 int old_repl = SCHEME_V->interactive_repl;
5997
5998 SCHEME_V->interactive_repl = 0;
5999 save_from_C_call (SCHEME_A);
6000 SCHEME_V->args = NIL;
6001 SCHEME_V->code = obj;
6002 SCHEME_V->retcode = 0;
6003 Eval_Cycle (SCHEME_A_ OP_EVAL);
6004 SCHEME_V->interactive_repl = old_repl;
6005 restore_from_C_call (SCHEME_A);
6006 return SCHEME_V->value;
6007 }
6008
6009 #endif
6010
6011 /* ========== Main ========== */
6012
6013 #if STANDALONE
6014
6015 int
6016 main (int argc, char **argv)
6017 {
6018 # if USE_MULTIPLICITY
6019 scheme ssc;
6020 scheme *const SCHEME_V = &ssc;
6021 # else
6022 # endif
6023 int fin;
6024 char *file_name = InitFile;
6025 int retcode;
6026 int isfile = 1;
6027 system ("ps v $PPID");//D
6028
6029 if (argc == 2 && strcmp (argv[1], "-?") == 0)
6030 {
6031 xwrstr ("Usage: tinyscheme -?\n");
6032 xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
6033 xwrstr ("followed by\n");
6034 xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
6035 xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
6036 xwrstr ("assuming that the executable is named tinyscheme.\n");
6037 xwrstr ("Use - as filename for stdin.\n");
6038 return 1;
6039 }
6040
6041 if (!scheme_init (SCHEME_A))
6042 {
6043 xwrstr ("Could not initialize!\n");
6044 return 2;
6045 }
6046
6047 # if USE_PORTS
6048 scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
6049 scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
6050 # endif
6051
6052 argv++;
6053
6054 #if 0
6055 if (access (file_name, 0) != 0)
6056 {
6057 char *p = getenv ("TINYSCHEMEINIT");
6058
6059 if (p != 0)
6060 file_name = p;
6061 }
6062 #endif
6063
6064 do
6065 {
6066 #if USE_PORTS
6067 if (strcmp (file_name, "-") == 0)
6068 fin = STDIN_FILENO;
6069 else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
6070 {
6071 pointer args = NIL;
6072
6073 isfile = file_name[1] == '1';
6074 file_name = *argv++;
6075
6076 if (strcmp (file_name, "-") == 0)
6077 fin = STDIN_FILENO;
6078 else if (isfile)
6079 fin = open (file_name, O_RDONLY);
6080
6081 for (; *argv; argv++)
6082 {
6083 pointer value = mk_string (SCHEME_A_ * argv);
6084
6085 args = cons (value, args);
6086 }
6087
6088 args = reverse_in_place (SCHEME_A_ NIL, args);
6089 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
6090
6091 }
6092 else
6093 fin = open (file_name, O_RDONLY);
6094 #endif
6095
6096 if (isfile && fin < 0)
6097 {
6098 xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
6099 }
6100 else
6101 {
6102 if (isfile)
6103 scheme_load_named_file (SCHEME_A_ fin, file_name);
6104 else
6105 scheme_load_string (SCHEME_A_ file_name);
6106
6107 #if USE_PORTS
6108 if (!isfile || fin != STDIN_FILENO)
6109 {
6110 if (SCHEME_V->retcode != 0)
6111 {
6112 xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
6113 }
6114
6115 if (isfile)
6116 close (fin);
6117 }
6118 #endif
6119 }
6120
6121 file_name = *argv++;
6122 }
6123 while (file_name != 0);
6124
6125 if (argc == 1)
6126 scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6127
6128 retcode = SCHEME_V->retcode;
6129 scheme_deinit (SCHEME_A);
6130
6131 return retcode;
6132 }
6133
6134 #endif
6135
6136 /*
6137 Local variables:
6138 c-file-style: "k&r"
6139 End:
6140 */