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