ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.52
Committed: Tue Dec 1 01:56:22 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.51: +2 -0 lines
Log Message:
*** empty log message ***

File Contents

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