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