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

File Contents

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