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

File Contents

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