ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.51
Committed: Tue Dec 1 01:54:27 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.50: +97 -102 lines
Log Message:
abstract pointer type

File Contents

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