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