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