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