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

File Contents

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