ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.68
Committed: Mon Dec 7 21:12:56 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.67: +5 -6 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_ 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 case OP_LAMBDA: /* lambda */
3616 {
3617 pointer formals = car (x);
3618 pointer body = cadr (x);
3619
3620 stream_put (s, syn == OP_LAMBDA ? BOP_LAMBDA : BOP_DELAY);
3621
3622 for (; is_pair (formals); formals = cdr (formals))
3623 stream_put_v (s, symbol_id (SCHEME_A_ car (formals)));
3624
3625 stream_put_v (s, 0);
3626 stream_put_v (s, formals == NIL ? 0 : symbol_id (SCHEME_A_ formals));
3627
3628 compile_expr (SCHEME_A_ s, body);
3629 }
3630 break;
3631
3632 case OP_C0STREAM:/* cons-stream */
3633 abort ();
3634 break;
3635 }
3636
3637 return;
3638 }
3639
3640 pointer m = lookup (SCHEME_A_ head);
3641
3642 if (is_macro (m))
3643 {
3644 s_save (SCHEME_A_ OP_DEBUG2, SCHEME_V->args, SCHEME_V->code);
3645 SCHEME_V->code = m;
3646 SCHEME_V->args = cons (x, NIL);
3647 Eval_Cycle (SCHEME_A_ OP_APPLY);
3648 x = SCHEME_V->value;
3649 compile_expr (SCHEME_A_ s, SCHEME_V->value);
3650 return;
3651 }
3652
3653 stream_put (s, BOP_LIST_BEG);
3654
3655 for (; x != NIL; x = cdr (x))
3656 compile_expr (SCHEME_A_ s, car (x));
3657
3658 stream_put (s, BOP_LIST_END);
3659 return;
3660 }
3661
3662 switch (type (x))
3663 {
3664 case T_INTEGER:
3665 {
3666 IVALUE iv = ivalue_unchecked (x);
3667 iv = iv < 0 ? ((~(uint32_t)iv) << 1) | 1 : (uint32_t)iv << 1;
3668 stream_put_tv (s, BOP_INTEGER, iv);
3669 }
3670 return;
3671
3672 case T_SYMBOL:
3673 if (0)
3674 {
3675 // no can do without more analysis
3676 pointer m = lookup (SCHEME_A_ x);
3677
3678 if (is_proc (m))
3679 {
3680 printf ("compile proc %s %d\n", procname(m), procnum(m));
3681 stream_put_tv (s, BOP_SYMBOL, BOP_OP + procnum (m));
3682 }
3683 else
3684 stream_put_tv (s, BOP_SYMBOL, symbol_id (SCHEME_A_ x));
3685 }
3686
3687 stream_put_tv (s, BOP_SYMBOL, symbol_id (SCHEME_A_ x));
3688 return;
3689
3690 default:
3691 stream_put_tv (s, BOP_DATUM, cell_id (SCHEME_A_ x));
3692 break;
3693 }
3694 }
3695
3696 ecb_cold static int
3697 compile_closure (SCHEME_P_ pointer p)
3698 {
3699 stream s = stream_init ();
3700
3701 compile_list (SCHEME_A_ s, cdar (p));
3702
3703 FILE *xxd = popen ("xxd", "we");
3704 fwrite (stream_data (s), 1, stream_size (s), xxd);
3705 fclose (xxd);
3706
3707 return stream_size (s);
3708 }
3709
3710 #endif
3711
3712 /* syntax, eval, core, ... */
3713 ecb_hot static int
3714 opexe_0 (SCHEME_P_ enum scheme_opcodes op)
3715 {
3716 pointer args = SCHEME_V->args;
3717 pointer x, y;
3718
3719 switch (op)
3720 {
3721 #if EXPERIMENT //D
3722 case OP_DEBUG:
3723 {
3724 uint32_t len = compile_closure (SCHEME_A_ car (args));
3725 printf ("len = %d\n", len);
3726 printf ("\n");
3727 s_return (S_T);
3728 }
3729
3730 case OP_DEBUG2:
3731 return -1;
3732 #endif
3733
3734 case OP_LOAD: /* load */
3735 if (file_interactive (SCHEME_A))
3736 {
3737 putstr (SCHEME_A_ "Loading ");
3738 putstr (SCHEME_A_ strvalue (car (args)));
3739 putcharacter (SCHEME_A_ '\n');
3740 }
3741
3742 if (!file_push (SCHEME_A_ strvalue (car (args))))
3743 Error_1 ("unable to open", car (args));
3744
3745 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
3746 s_goto (OP_T0LVL);
3747
3748 case OP_T0LVL: /* top level */
3749
3750 /* If we reached the end of file, this loop is done. */
3751 if (port (SCHEME_V->loadport)->kind & port_saw_EOF)
3752 {
3753 if (SCHEME_V->file_i == 0)
3754 {
3755 SCHEME_V->args = NIL;
3756 s_goto (OP_QUIT);
3757 }
3758 else
3759 {
3760 file_pop (SCHEME_A);
3761 s_return (SCHEME_V->value);
3762 }
3763
3764 /* NOTREACHED */
3765 }
3766
3767 /* If interactive, be nice to user. */
3768 if (file_interactive (SCHEME_A))
3769 {
3770 SCHEME_V->envir = SCHEME_V->global_env;
3771 dump_stack_reset (SCHEME_A);
3772 putcharacter (SCHEME_A_ '\n');
3773 #if EXPERIMENT
3774 system ("ps v $PPID");
3775 #endif
3776 putstr (SCHEME_A_ prompt);
3777 }
3778
3779 /* Set up another iteration of REPL */
3780 SCHEME_V->nesting = 0;
3781 SCHEME_V->save_inport = SCHEME_V->inport;
3782 SCHEME_V->inport = SCHEME_V->loadport;
3783 s_save (SCHEME_A_ OP_T0LVL, NIL, NIL);
3784 s_save (SCHEME_A_ OP_VALUEPRINT, NIL, NIL);
3785 s_save (SCHEME_A_ OP_T1LVL, NIL, NIL);
3786 s_goto (OP_READ_INTERNAL);
3787
3788 case OP_T1LVL: /* top level */
3789 SCHEME_V->code = SCHEME_V->value;
3790 SCHEME_V->inport = SCHEME_V->save_inport;
3791 s_goto (OP_EVAL);
3792
3793 case OP_READ_INTERNAL: /* internal read */
3794 SCHEME_V->tok = token (SCHEME_A);
3795
3796 if (SCHEME_V->tok == TOK_EOF)
3797 s_return (S_EOF);
3798
3799 s_goto (OP_RDSEXPR);
3800
3801 case OP_GENSYM:
3802 s_return (gensym (SCHEME_A));
3803
3804 case OP_VALUEPRINT: /* print evaluation result */
3805
3806 /* OP_VALUEPRINT is always pushed, because when changing from
3807 non-interactive to interactive mode, it needs to be
3808 already on the stack */
3809 #if USE_TRACING
3810 if (SCHEME_V->tracing)
3811 putstr (SCHEME_A_ "\nGives: ");
3812 #endif
3813
3814 if (file_interactive (SCHEME_A))
3815 {
3816 SCHEME_V->print_flag = 1;
3817 SCHEME_V->args = SCHEME_V->value;
3818 s_goto (OP_P0LIST);
3819 }
3820
3821 s_return (SCHEME_V->value);
3822
3823 case OP_EVAL: /* main part of evaluation */
3824 #if USE_TRACING
3825 if (SCHEME_V->tracing)
3826 {
3827 /*s_save(SCHEME_A_ OP_VALUEPRINT,NIL,NIL); */
3828 s_save (SCHEME_A_ OP_REAL_EVAL, args, SCHEME_V->code);
3829 SCHEME_V->args = SCHEME_V->code;
3830 putstr (SCHEME_A_ "\nEval: ");
3831 s_goto (OP_P0LIST);
3832 }
3833
3834 /* fall through */
3835
3836 case OP_REAL_EVAL:
3837 #endif
3838 if (is_symbol (SCHEME_V->code)) /* symbol */
3839 {
3840 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3841
3842 if (x == NIL)
3843 Error_1 ("eval: unbound variable:", SCHEME_V->code);
3844
3845 s_return (slot_value_in_env (x));
3846 }
3847 else if (is_pair (SCHEME_V->code))
3848 {
3849 x = car (SCHEME_V->code);
3850
3851 if (is_syntax (x)) /* SYNTAX */
3852 {
3853 SCHEME_V->code = cdr (SCHEME_V->code);
3854 s_goto (syntaxnum (x));
3855 }
3856 else /* first, eval top element and eval arguments */
3857 {
3858 s_save (SCHEME_A_ OP_E0ARGS, NIL, SCHEME_V->code);
3859 /* If no macros => s_save(SCHEME_A_ OP_E1ARGS, NIL, cdr(SCHEME_V->code)); */
3860 SCHEME_V->code = x;
3861 s_goto (OP_EVAL);
3862 }
3863 }
3864
3865 s_return (SCHEME_V->code);
3866
3867 case OP_E0ARGS: /* eval arguments */
3868 if (ecb_expect_false (is_macro (SCHEME_V->value))) /* macro expansion */
3869 {
3870 s_save (SCHEME_A_ OP_DOMACRO, NIL, NIL);
3871 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3872 SCHEME_V->code = SCHEME_V->value;
3873 s_goto (OP_APPLY);
3874 }
3875
3876 SCHEME_V->code = cdr (SCHEME_V->code);
3877 s_goto (OP_E1ARGS);
3878
3879 case OP_E1ARGS: /* eval arguments */
3880 args = cons (SCHEME_V->value, args);
3881
3882 if (is_pair (SCHEME_V->code)) /* continue */
3883 {
3884 s_save (SCHEME_A_ OP_E1ARGS, args, cdr (SCHEME_V->code));
3885 SCHEME_V->code = car (SCHEME_V->code);
3886 SCHEME_V->args = NIL;
3887 s_goto (OP_EVAL);
3888 }
3889 else /* end */
3890 {
3891 args = reverse_in_place (SCHEME_A_ NIL, args);
3892 SCHEME_V->code = car (args);
3893 SCHEME_V->args = cdr (args);
3894 s_goto (OP_APPLY);
3895 }
3896
3897 #if USE_TRACING
3898 case OP_TRACING:
3899 {
3900 int tr = SCHEME_V->tracing;
3901
3902 SCHEME_V->tracing = ivalue_unchecked (car (args));
3903 s_return (mk_integer (SCHEME_A_ tr));
3904 }
3905 #endif
3906
3907 case OP_APPLY: /* apply 'code' to 'args' */
3908 #if USE_TRACING
3909 if (SCHEME_V->tracing)
3910 {
3911 s_save (SCHEME_A_ OP_REAL_APPLY, args, SCHEME_V->code);
3912 SCHEME_V->print_flag = 1;
3913 /* args=cons(SCHEME_V->code,args); */
3914 putstr (SCHEME_A_ "\nApply to: ");
3915 s_goto (OP_P0LIST);
3916 }
3917
3918 /* fall through */
3919
3920 case OP_REAL_APPLY:
3921 #endif
3922 if (is_proc (SCHEME_V->code))
3923 s_goto (procnum (SCHEME_V->code)); /* PROCEDURE */
3924 else if (is_foreign (SCHEME_V->code))
3925 {
3926 /* Keep nested calls from GC'ing the arglist */
3927 push_recent_alloc (SCHEME_A_ args, NIL);
3928 x = CELL(SCHEME_V->code)->object.ff (SCHEME_A_ args);
3929
3930 s_return (x);
3931 }
3932 else if (is_closure (SCHEME_V->code) || is_macro (SCHEME_V->code) || is_promise (SCHEME_V->code)) /* CLOSURE */
3933 {
3934 /* Should not accept promise */
3935 /* make environment */
3936 new_frame_in_env (SCHEME_A_ closure_env (SCHEME_V->code));
3937
3938 for (x = car (closure_code (SCHEME_V->code)), y = args; is_pair (x); x = cdr (x), y = cdr (y))
3939 {
3940 if (y == NIL)
3941 Error_0 ("not enough arguments");
3942 else
3943 new_slot_in_env (SCHEME_A_ car (x), car (y));
3944 }
3945
3946 if (x == NIL)
3947 {
3948 /*--
3949 * if (y != NIL) {
3950 * Error_0("too many arguments");
3951 * }
3952 */
3953 }
3954 else if (is_symbol (x))
3955 new_slot_in_env (SCHEME_A_ x, y);
3956 else
3957 Error_1 ("syntax error in closure: not a symbol:", x);
3958
3959 SCHEME_V->code = cdr (closure_code (SCHEME_V->code));
3960 SCHEME_V->args = NIL;
3961 s_goto (OP_BEGIN);
3962 }
3963 else if (is_continuation (SCHEME_V->code)) /* CONTINUATION */
3964 {
3965 ss_set_cont (SCHEME_A_ cont_dump (SCHEME_V->code));
3966 s_return (args != NIL ? car (args) : NIL);
3967 }
3968
3969 Error_0 ("illegal function");
3970
3971 case OP_DOMACRO: /* do macro */
3972 SCHEME_V->code = SCHEME_V->value;
3973 s_goto (OP_EVAL);
3974
3975 case OP_LAMBDA: /* lambda */
3976 /* If the hook is defined, apply it to SCHEME_V->code, otherwise
3977 set SCHEME_V->value fall thru */
3978 {
3979 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->COMPILE_HOOK, 1);
3980
3981 if (f != NIL)
3982 {
3983 s_save (SCHEME_A_ OP_LAMBDA1, args, SCHEME_V->code);
3984 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3985 SCHEME_V->code = slot_value_in_env (f);
3986 s_goto (OP_APPLY);
3987 }
3988
3989 SCHEME_V->value = SCHEME_V->code;
3990 }
3991 /* Fallthru */
3992
3993 case OP_LAMBDA1:
3994 s_return (mk_closure (SCHEME_A_ SCHEME_V->value, SCHEME_V->envir));
3995
3996 case OP_MKCLOSURE: /* make-closure */
3997 x = car (args);
3998
3999 if (car (x) == SCHEME_V->LAMBDA)
4000 x = cdr (x);
4001
4002 if (cdr (args) == NIL)
4003 y = SCHEME_V->envir;
4004 else
4005 y = cadr (args);
4006
4007 s_return (mk_closure (SCHEME_A_ x, y));
4008
4009 case OP_QUOTE: /* quote */
4010 s_return (car (SCHEME_V->code));
4011
4012 case OP_DEF0: /* define */
4013 if (is_immutable (car (SCHEME_V->code)))
4014 Error_1 ("define: unable to alter immutable", car (SCHEME_V->code));
4015
4016 if (is_pair (car (SCHEME_V->code)))
4017 {
4018 x = caar (SCHEME_V->code);
4019 SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
4020 }
4021 else
4022 {
4023 x = car (SCHEME_V->code);
4024 SCHEME_V->code = cadr (SCHEME_V->code);
4025 }
4026
4027 if (!is_symbol (x))
4028 Error_0 ("variable is not a symbol");
4029
4030 s_save (SCHEME_A_ OP_DEF1, NIL, x);
4031 s_goto (OP_EVAL);
4032
4033 case OP_DEF1: /* define */
4034 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
4035
4036 if (x != NIL)
4037 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
4038 else
4039 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
4040
4041 s_return (SCHEME_V->code);
4042
4043 case OP_DEFP: /* defined? */
4044 x = SCHEME_V->envir;
4045
4046 if (cdr (args) != NIL)
4047 x = cadr (args);
4048
4049 s_retbool (find_slot_in_env (SCHEME_A_ x, car (args), 1) != NIL);
4050
4051 case OP_SET0: /* set! */
4052 if (is_immutable (car (SCHEME_V->code)))
4053 Error_1 ("set!: unable to alter immutable variable", car (SCHEME_V->code));
4054
4055 s_save (SCHEME_A_ OP_SET1, NIL, car (SCHEME_V->code));
4056 SCHEME_V->code = cadr (SCHEME_V->code);
4057 s_goto (OP_EVAL);
4058
4059 case OP_SET1: /* set! */
4060 y = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
4061
4062 if (y != NIL)
4063 {
4064 set_slot_in_env (SCHEME_A_ y, SCHEME_V->value);
4065 s_return (SCHEME_V->value);
4066 }
4067 else
4068 Error_1 ("set!: unbound variable:", SCHEME_V->code);
4069
4070 case OP_BEGIN: /* begin */
4071 if (!is_pair (SCHEME_V->code))
4072 s_return (SCHEME_V->code);
4073
4074 if (cdr (SCHEME_V->code) != NIL)
4075 s_save (SCHEME_A_ OP_BEGIN, NIL, cdr (SCHEME_V->code));
4076
4077 SCHEME_V->code = car (SCHEME_V->code);
4078 s_goto (OP_EVAL);
4079
4080 case OP_IF0: /* if */
4081 s_save (SCHEME_A_ OP_IF1, NIL, cdr (SCHEME_V->code));
4082 SCHEME_V->code = car (SCHEME_V->code);
4083 s_goto (OP_EVAL);
4084
4085 case OP_IF1: /* if */
4086 if (is_true (SCHEME_V->value))
4087 SCHEME_V->code = car (SCHEME_V->code);
4088 else
4089 SCHEME_V->code = cadr (SCHEME_V->code); /* (if #f 1) ==> () because * car(NIL) = NIL */
4090
4091 s_goto (OP_EVAL);
4092
4093 case OP_LET0: /* let */
4094 SCHEME_V->args = NIL;
4095 SCHEME_V->value = SCHEME_V->code;
4096 SCHEME_V->code = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code);
4097 s_goto (OP_LET1);
4098
4099 case OP_LET1: /* let (calculate parameters) */
4100 case OP_LET1REC: /* letrec (calculate parameters) */
4101 args = cons (SCHEME_V->value, args);
4102
4103 if (is_pair (SCHEME_V->code)) /* continue */
4104 {
4105 if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
4106 Error_1 ("Bad syntax of binding spec in let/letrec:", car (SCHEME_V->code));
4107
4108 s_save (SCHEME_A_ op, args, cdr (SCHEME_V->code));
4109 SCHEME_V->code = cadar (SCHEME_V->code);
4110 SCHEME_V->args = NIL;
4111 s_goto (OP_EVAL);
4112 }
4113
4114 /* end */
4115 args = reverse_in_place (SCHEME_A_ NIL, args);
4116 SCHEME_V->code = car (args);
4117 SCHEME_V->args = cdr (args);
4118 s_goto (op == OP_LET1 ? OP_LET2 : OP_LET2REC);
4119
4120 case OP_LET2: /* let */
4121 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
4122
4123 for (x = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code), y = args;
4124 y != NIL; x = cdr (x), y = cdr (y))
4125 new_slot_in_env (SCHEME_A_ caar (x), car (y));
4126
4127 if (is_symbol (car (SCHEME_V->code))) /* named let */
4128 {
4129 for (x = cadr (SCHEME_V->code), args = NIL; x != NIL; x = cdr (x))
4130 {
4131 if (!is_pair (x))
4132 Error_1 ("Bad syntax of binding in let:", x);
4133
4134 if (!is_list (SCHEME_A_ car (x)))
4135 Error_1 ("Bad syntax of binding in let:", car (x));
4136
4137 args = cons (caar (x), args);
4138 }
4139
4140 x = mk_closure (SCHEME_A_ cons (reverse_in_place (SCHEME_A_ NIL, args), cddr (SCHEME_V->code)),
4141 SCHEME_V->envir);
4142 new_slot_in_env (SCHEME_A_ car (SCHEME_V->code), x);
4143 SCHEME_V->code = cddr (SCHEME_V->code);
4144 }
4145 else
4146 {
4147 SCHEME_V->code = cdr (SCHEME_V->code);
4148 }
4149
4150 SCHEME_V->args = NIL;
4151 s_goto (OP_BEGIN);
4152
4153 case OP_LET0AST: /* let* */
4154 if (car (SCHEME_V->code) == NIL)
4155 {
4156 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
4157 SCHEME_V->code = cdr (SCHEME_V->code);
4158 s_goto (OP_BEGIN);
4159 }
4160
4161 if (!is_pair (car (SCHEME_V->code)) || !is_pair (caar (SCHEME_V->code)) || !is_pair (cdaar (SCHEME_V->code)))
4162 Error_1 ("Bad syntax of binding spec in let*:", car (SCHEME_V->code));
4163
4164 s_save (SCHEME_A_ OP_LET1AST, cdr (SCHEME_V->code), car (SCHEME_V->code));
4165 SCHEME_V->code = car (cdaar (SCHEME_V->code));
4166 s_goto (OP_EVAL);
4167
4168 case OP_LET1AST: /* let* (make new frame) */
4169 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
4170 s_goto (OP_LET2AST);
4171
4172 case OP_LET2AST: /* let* (calculate parameters) */
4173 new_slot_in_env (SCHEME_A_ caar (SCHEME_V->code), SCHEME_V->value);
4174 SCHEME_V->code = cdr (SCHEME_V->code);
4175
4176 if (is_pair (SCHEME_V->code)) /* continue */
4177 {
4178 s_save (SCHEME_A_ OP_LET2AST, args, SCHEME_V->code);
4179 SCHEME_V->code = cadar (SCHEME_V->code);
4180 SCHEME_V->args = NIL;
4181 s_goto (OP_EVAL);
4182 }
4183
4184 /* end */
4185
4186 SCHEME_V->code = args;
4187 SCHEME_V->args = NIL;
4188 s_goto (OP_BEGIN);
4189
4190 case OP_LET0REC: /* letrec */
4191 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
4192 SCHEME_V->args = NIL;
4193 SCHEME_V->value = SCHEME_V->code;
4194 SCHEME_V->code = car (SCHEME_V->code);
4195 s_goto (OP_LET1REC);
4196
4197 /* OP_LET1REC handled by OP_LET1 */
4198
4199 case OP_LET2REC: /* letrec */
4200 for (x = car (SCHEME_V->code), y = args; y != NIL; x = cdr (x), y = cdr (y))
4201 new_slot_in_env (SCHEME_A_ caar (x), car (y));
4202
4203 SCHEME_V->code = cdr (SCHEME_V->code);
4204 SCHEME_V->args = NIL;
4205 s_goto (OP_BEGIN);
4206
4207 case OP_COND0: /* cond */
4208 if (!is_pair (SCHEME_V->code))
4209 Error_0 ("syntax error in cond");
4210
4211 s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
4212 SCHEME_V->code = caar (SCHEME_V->code);
4213 s_goto (OP_EVAL);
4214
4215 case OP_COND1: /* cond */
4216 if (is_true (SCHEME_V->value))
4217 {
4218 if ((SCHEME_V->code = cdar (SCHEME_V->code)) == NIL)
4219 s_return (SCHEME_V->value);
4220
4221 if (car (SCHEME_V->code) == SCHEME_V->FEED_TO)
4222 {
4223 if (!is_pair (cdr (SCHEME_V->code)))
4224 Error_0 ("syntax error in cond");
4225
4226 x = cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL));
4227 SCHEME_V->code = cons (cadr (SCHEME_V->code), cons (x, NIL));
4228 s_goto (OP_EVAL);
4229 }
4230
4231 s_goto (OP_BEGIN);
4232 }
4233 else
4234 {
4235 if ((SCHEME_V->code = cdr (SCHEME_V->code)) == NIL)
4236 s_return (NIL);
4237
4238 s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
4239 SCHEME_V->code = caar (SCHEME_V->code);
4240 s_goto (OP_EVAL);
4241 }
4242
4243 case OP_DELAY: /* delay */
4244 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
4245 set_typeflag (x, T_PROMISE);
4246 s_return (x);
4247
4248 case OP_AND0: /* and */
4249 if (SCHEME_V->code == NIL)
4250 s_return (S_T);
4251
4252 s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
4253 SCHEME_V->code = car (SCHEME_V->code);
4254 s_goto (OP_EVAL);
4255
4256 case OP_AND1: /* and */
4257 if (is_false (SCHEME_V->value))
4258 s_return (SCHEME_V->value);
4259 else if (SCHEME_V->code == NIL)
4260 s_return (SCHEME_V->value);
4261
4262 s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
4263 SCHEME_V->code = car (SCHEME_V->code);
4264 s_goto (OP_EVAL);
4265
4266 case OP_OR0: /* or */
4267 if (SCHEME_V->code == NIL)
4268 s_return (S_F);
4269
4270 s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
4271 SCHEME_V->code = car (SCHEME_V->code);
4272 s_goto (OP_EVAL);
4273
4274 case OP_OR1: /* or */
4275 if (is_true (SCHEME_V->value))
4276 s_return (SCHEME_V->value);
4277 else if (SCHEME_V->code == NIL)
4278 s_return (SCHEME_V->value);
4279
4280 s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
4281 SCHEME_V->code = car (SCHEME_V->code);
4282 s_goto (OP_EVAL);
4283
4284 case OP_C0STREAM: /* cons-stream */
4285 s_save (SCHEME_A_ OP_C1STREAM, NIL, cdr (SCHEME_V->code));
4286 SCHEME_V->code = car (SCHEME_V->code);
4287 s_goto (OP_EVAL);
4288
4289 case OP_C1STREAM: /* cons-stream */
4290 SCHEME_V->args = SCHEME_V->value; /* save SCHEME_V->value to register args for gc */
4291 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
4292 set_typeflag (x, T_PROMISE);
4293 s_return (cons (args, x));
4294
4295 case OP_MACRO0: /* macro */
4296 if (is_pair (car (SCHEME_V->code)))
4297 {
4298 x = caar (SCHEME_V->code);
4299 SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
4300 }
4301 else
4302 {
4303 x = car (SCHEME_V->code);
4304 SCHEME_V->code = cadr (SCHEME_V->code);
4305 }
4306
4307 if (!is_symbol (x))
4308 Error_0 ("variable is not a symbol");
4309
4310 s_save (SCHEME_A_ OP_MACRO1, NIL, x);
4311 s_goto (OP_EVAL);
4312
4313 case OP_MACRO1: /* macro */
4314 set_typeflag (SCHEME_V->value, T_MACRO);
4315 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
4316
4317 if (x != NIL)
4318 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
4319 else
4320 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
4321
4322 s_return (SCHEME_V->code);
4323
4324 case OP_CASE0: /* case */
4325 s_save (SCHEME_A_ OP_CASE1, NIL, cdr (SCHEME_V->code));
4326 SCHEME_V->code = car (SCHEME_V->code);
4327 s_goto (OP_EVAL);
4328
4329 case OP_CASE1: /* case */
4330 for (x = SCHEME_V->code; x != NIL; x = cdr (x))
4331 {
4332 if (!is_pair (y = caar (x)))
4333 break;
4334
4335 for (; y != NIL; y = cdr (y))
4336 if (eqv (car (y), SCHEME_V->value))
4337 break;
4338
4339 if (y != NIL)
4340 break;
4341 }
4342
4343 if (x != NIL)
4344 {
4345 if (is_pair (caar (x)))
4346 {
4347 SCHEME_V->code = cdar (x);
4348 s_goto (OP_BEGIN);
4349 }
4350 else /* else */
4351 {
4352 s_save (SCHEME_A_ OP_CASE2, NIL, cdar (x));
4353 SCHEME_V->code = caar (x);
4354 s_goto (OP_EVAL);
4355 }
4356 }
4357
4358 s_return (NIL);
4359
4360 case OP_CASE2: /* case */
4361 if (is_true (SCHEME_V->value))
4362 s_goto (OP_BEGIN);
4363
4364 s_return (NIL);
4365
4366 case OP_PAPPLY: /* apply */
4367 SCHEME_V->code = car (args);
4368 SCHEME_V->args = list_star (SCHEME_A_ cdr (args));
4369 /*SCHEME_V->args = cadr(args); */
4370 s_goto (OP_APPLY);
4371
4372 case OP_PEVAL: /* eval */
4373 if (cdr (args) != NIL)
4374 SCHEME_V->envir = cadr (args);
4375
4376 SCHEME_V->code = car (args);
4377 s_goto (OP_EVAL);
4378
4379 case OP_CONTINUATION: /* call-with-current-continuation */
4380 SCHEME_V->code = car (args);
4381 SCHEME_V->args = cons (mk_continuation (SCHEME_A_ ss_get_cont (SCHEME_A)), NIL);
4382 s_goto (OP_APPLY);
4383 }
4384
4385 if (USE_ERROR_CHECKING) abort ();
4386 }
4387
4388 /* math, cxr */
4389 ecb_hot static int
4390 opexe_1 (SCHEME_P_ enum scheme_opcodes op)
4391 {
4392 pointer args = SCHEME_V->args;
4393 pointer x = car (args);
4394 num v;
4395
4396 switch (op)
4397 {
4398 #if USE_MATH
4399 case OP_INEX2EX: /* inexact->exact */
4400 if (!is_integer (x))
4401 {
4402 RVALUE r = rvalue_unchecked (x);
4403
4404 if (r == (RVALUE)(IVALUE)r)
4405 x = mk_integer (SCHEME_A_ rvalue_unchecked (x));
4406 else
4407 Error_1 ("inexact->exact: not integral:", x);
4408 }
4409
4410 s_return (x);
4411
4412 case OP_FLOOR: s_return (mk_real (SCHEME_A_ floor (rvalue (x))));
4413 case OP_CEILING: s_return (mk_real (SCHEME_A_ ceil (rvalue (x))));
4414 case OP_TRUNCATE: s_return (mk_real (SCHEME_A_ trunc (rvalue (x))));
4415 case OP_ROUND: s_return (mk_real (SCHEME_A_ nearbyint (rvalue (x))));
4416
4417 case OP_SQRT: s_return (mk_real (SCHEME_A_ sqrt (rvalue (x))));
4418 case OP_EXP: s_return (mk_real (SCHEME_A_ exp (rvalue (x))));
4419 case OP_LOG: s_return (mk_real (SCHEME_A_ log (rvalue (x))
4420 / (cadr (args) == NIL ? 1 : log (rvalue (cadr (args))))));
4421 case OP_SIN: s_return (mk_real (SCHEME_A_ sin (rvalue (x))));
4422 case OP_COS: s_return (mk_real (SCHEME_A_ cos (rvalue (x))));
4423 case OP_TAN: s_return (mk_real (SCHEME_A_ tan (rvalue (x))));
4424 case OP_ASIN: s_return (mk_real (SCHEME_A_ asin (rvalue (x))));
4425 case OP_ACOS: s_return (mk_real (SCHEME_A_ acos (rvalue (x))));
4426
4427 case OP_ATAN:
4428 s_return (mk_real (SCHEME_A_
4429 cdr (args) == NIL
4430 ? atan (rvalue (x))
4431 : atan2 (rvalue (x), rvalue (cadr (args)))));
4432
4433 case OP_EXPT:
4434 {
4435 RVALUE result;
4436 int real_result = 1;
4437 pointer y = cadr (args);
4438
4439 if (is_integer (x) && is_integer (y))
4440 real_result = 0;
4441
4442 /* This 'if' is an R5RS compatibility fix. */
4443 /* NOTE: Remove this 'if' fix for R6RS. */
4444 if (rvalue (x) == 0 && rvalue (y) < 0)
4445 result = 0;
4446 else
4447 result = pow (rvalue (x), rvalue (y));
4448
4449 /* Before returning integer result make sure we can. */
4450 /* If the test fails, result is too big for integer. */
4451 if (!real_result)
4452 {
4453 long result_as_long = result;
4454
4455 if (result != result_as_long)
4456 real_result = 1;
4457 }
4458
4459 if (real_result)
4460 s_return (mk_real (SCHEME_A_ result));
4461 else
4462 s_return (mk_integer (SCHEME_A_ result));
4463 }
4464 #endif
4465
4466 case OP_ADD: /* + */
4467 v = num_zero;
4468
4469 for (x = args; x != NIL; x = cdr (x))
4470 v = num_op (NUM_ADD, v, nvalue (car (x)));
4471
4472 s_return (mk_number (SCHEME_A_ v));
4473
4474 case OP_MUL: /* * */
4475 v = num_one;
4476
4477 for (x = args; x != NIL; x = cdr (x))
4478 v = num_op (NUM_MUL, v, nvalue (car (x)));
4479
4480 s_return (mk_number (SCHEME_A_ v));
4481
4482 case OP_SUB: /* - */
4483 if (cdr (args) == NIL)
4484 {
4485 x = args;
4486 v = num_zero;
4487 }
4488 else
4489 {
4490 x = cdr (args);
4491 v = nvalue (car (args));
4492 }
4493
4494 for (; x != NIL; x = cdr (x))
4495 v = num_op (NUM_SUB, v, nvalue (car (x)));
4496
4497 s_return (mk_number (SCHEME_A_ v));
4498
4499 case OP_DIV: /* / */
4500 if (cdr (args) == NIL)
4501 {
4502 x = args;
4503 v = num_one;
4504 }
4505 else
4506 {
4507 x = cdr (args);
4508 v = nvalue (car (args));
4509 }
4510
4511 for (; x != NIL; x = cdr (x))
4512 if (!is_zero_rvalue (rvalue (car (x))))
4513 v = num_div (v, nvalue (car (x)));
4514 else
4515 Error_0 ("/: division by zero");
4516
4517 s_return (mk_number (SCHEME_A_ v));
4518
4519 case OP_INTDIV: /* quotient */
4520 if (cdr (args) == NIL)
4521 {
4522 x = args;
4523 v = num_one;
4524 }
4525 else
4526 {
4527 x = cdr (args);
4528 v = nvalue (car (args));
4529 }
4530
4531 for (; x != NIL; x = cdr (x))
4532 {
4533 if (ivalue (car (x)) != 0)
4534 v = num_op (NUM_INTDIV, v, nvalue (car (x)));
4535 else
4536 Error_0 ("quotient: division by zero");
4537 }
4538
4539 s_return (mk_number (SCHEME_A_ v));
4540
4541 case OP_REM: /* remainder */
4542 v = nvalue (x);
4543
4544 if (ivalue (cadr (args)) != 0)
4545 v = num_rem (v, nvalue (cadr (args)));
4546 else
4547 Error_0 ("remainder: division by zero");
4548
4549 s_return (mk_number (SCHEME_A_ v));
4550
4551 case OP_MOD: /* modulo */
4552 v = nvalue (x);
4553
4554 if (ivalue (cadr (args)) != 0)
4555 v = num_mod (v, nvalue (cadr (args)));
4556 else
4557 Error_0 ("modulo: division by zero");
4558
4559 s_return (mk_number (SCHEME_A_ v));
4560
4561 /* the compiler will optimize this mess... */
4562 case OP_CAR: op_car: s_return (car (x));
4563 case OP_CDR: op_cdr: s_return (cdr (x));
4564 case OP_CAAR: op_caar: x = car (x); goto op_car;
4565 case OP_CADR: op_cadr: x = cdr (x); goto op_car;
4566 case OP_CDAR: op_cdar: x = car (x); goto op_cdr;
4567 case OP_CDDR: op_cddr: x = cdr (x); goto op_cdr;
4568 case OP_CAAAR: op_caaar: x = car (x); goto op_caar;
4569 case OP_CAADR: op_caadr: x = cdr (x); goto op_caar;
4570 case OP_CADAR: op_cadar: x = car (x); goto op_cadr;
4571 case OP_CADDR: op_caddr: x = cdr (x); goto op_cadr;
4572 case OP_CDAAR: op_cdaar: x = car (x); goto op_cdar;
4573 case OP_CDADR: op_cdadr: x = cdr (x); goto op_cdar;
4574 case OP_CDDAR: op_cddar: x = car (x); goto op_cddr;
4575 case OP_CDDDR: op_cdddr: x = cdr (x); goto op_cddr;
4576 case OP_CAAAAR: x = car (x); goto op_caaar;
4577 case OP_CAAADR: x = cdr (x); goto op_caaar;
4578 case OP_CAADAR: x = car (x); goto op_caadr;
4579 case OP_CAADDR: x = cdr (x); goto op_caadr;
4580 case OP_CADAAR: x = car (x); goto op_cadar;
4581 case OP_CADADR: x = cdr (x); goto op_cadar;
4582 case OP_CADDAR: x = car (x); goto op_caddr;
4583 case OP_CADDDR: x = cdr (x); goto op_caddr;
4584 case OP_CDAAAR: x = car (x); goto op_cdaar;
4585 case OP_CDAADR: x = cdr (x); goto op_cdaar;
4586 case OP_CDADAR: x = car (x); goto op_cdadr;
4587 case OP_CDADDR: x = cdr (x); goto op_cdadr;
4588 case OP_CDDAAR: x = car (x); goto op_cddar;
4589 case OP_CDDADR: x = cdr (x); goto op_cddar;
4590 case OP_CDDDAR: x = car (x); goto op_cdddr;
4591 case OP_CDDDDR: x = cdr (x); goto op_cdddr;
4592
4593 case OP_CONS: /* cons */
4594 set_cdr (args, cadr (args));
4595 s_return (args);
4596
4597 case OP_SETCAR: /* set-car! */
4598 if (!is_immutable (x))
4599 {
4600 set_car (x, cadr (args));
4601 s_return (car (args));
4602 }
4603 else
4604 Error_0 ("set-car!: unable to alter immutable pair");
4605
4606 case OP_SETCDR: /* set-cdr! */
4607 if (!is_immutable (x))
4608 {
4609 set_cdr (x, cadr (args));
4610 s_return (car (args));
4611 }
4612 else
4613 Error_0 ("set-cdr!: unable to alter immutable pair");
4614
4615 case OP_CHAR2INT: /* char->integer */
4616 s_return (mk_integer (SCHEME_A_ ivalue_unchecked (x)));
4617
4618 case OP_INT2CHAR: /* integer->char */
4619 s_return (mk_character (SCHEME_A_ ivalue_unchecked (x)));
4620
4621 case OP_CHARUPCASE:
4622 {
4623 unsigned char c = ivalue_unchecked (x);
4624 c = toupper (c);
4625 s_return (mk_character (SCHEME_A_ c));
4626 }
4627
4628 case OP_CHARDNCASE:
4629 {
4630 unsigned char c = ivalue_unchecked (x);
4631 c = tolower (c);
4632 s_return (mk_character (SCHEME_A_ c));
4633 }
4634
4635 case OP_STR2SYM: /* string->symbol */
4636 s_return (mk_symbol (SCHEME_A_ strvalue (x)));
4637
4638 case OP_STR2ATOM: /* string->atom */
4639 {
4640 char *s = strvalue (x);
4641 long pf = 0;
4642
4643 if (cdr (args) != NIL)
4644 {
4645 /* we know cadr(args) is a natural number */
4646 /* see if it is 2, 8, 10, or 16, or error */
4647 pf = ivalue_unchecked (cadr (args));
4648
4649 if (pf == 16 || pf == 10 || pf == 8 || pf == 2)
4650 {
4651 /* base is OK */
4652 }
4653 else
4654 pf = -1;
4655 }
4656
4657 if (pf < 0)
4658 Error_1 ("string->atom: bad base:", cadr (args));
4659 else if (*s == '#') /* no use of base! */
4660 s_return (mk_sharp_const (SCHEME_A_ s + 1));
4661 else
4662 {
4663 if (pf == 0 || pf == 10)
4664 s_return (mk_atom (SCHEME_A_ s));
4665 else
4666 {
4667 char *ep;
4668 long iv = strtol (s, &ep, (int) pf);
4669
4670 if (*ep == 0)
4671 s_return (mk_integer (SCHEME_A_ iv));
4672 else
4673 s_return (S_F);
4674 }
4675 }
4676 }
4677
4678 case OP_SYM2STR: /* symbol->string */
4679 x = mk_string (SCHEME_A_ symname (x));
4680 setimmutable (x);
4681 s_return (x);
4682
4683 case OP_ATOM2STR: /* atom->string */
4684 {
4685 long pf = 0;
4686
4687 if (cdr (args) != NIL)
4688 {
4689 /* we know cadr(args) is a natural number */
4690 /* see if it is 2, 8, 10, or 16, or error */
4691 pf = ivalue_unchecked (cadr (args));
4692
4693 if (is_number (x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2))
4694 {
4695 /* base is OK */
4696 }
4697 else
4698 pf = -1;
4699 }
4700
4701 if (pf < 0)
4702 Error_1 ("atom->string: bad base:", cadr (args));
4703 else if (is_number (x) || is_character (x) || is_string (x) || is_symbol (x))
4704 {
4705 char *p;
4706 int len;
4707
4708 atom2str (SCHEME_A_ x, pf, &p, &len);
4709 s_return (mk_counted_string (SCHEME_A_ p, len));
4710 }
4711 else
4712 Error_1 ("atom->string: not an atom:", x);
4713 }
4714
4715 case OP_MKSTRING: /* make-string */
4716 {
4717 int fill = cdr (args) != NIL ? charvalue (cadr (args)) : ' ';
4718 int len = ivalue_unchecked (x);
4719
4720 s_return (mk_empty_string (SCHEME_A_ len, fill));
4721 }
4722
4723 case OP_STRLEN: /* string-length */
4724 s_return (mk_integer (SCHEME_A_ strlength (x)));
4725
4726 case OP_STRREF: /* string-ref */
4727 {
4728 char *str = strvalue (x);
4729 int index = ivalue_unchecked (cadr (args));
4730
4731 if (index >= strlength (x))
4732 Error_1 ("string-ref: out of bounds:", cadr (args));
4733
4734 s_return (mk_character (SCHEME_A_ ((unsigned char *)str)[index]));
4735 }
4736
4737 case OP_STRSET: /* string-set! */
4738 {
4739 char *str = strvalue (x);
4740 int index = ivalue_unchecked (cadr (args));
4741 int c;
4742
4743 if (is_immutable (x))
4744 Error_1 ("string-set!: unable to alter immutable string:", x);
4745
4746 if (index >= strlength (x))
4747 Error_1 ("string-set!: out of bounds:", cadr (args));
4748
4749 c = charvalue (caddr (args));
4750
4751 str[index] = c;
4752 s_return (car (args));
4753 }
4754
4755 case OP_STRAPPEND: /* string-append */
4756 {
4757 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4758 int len = 0;
4759 pointer newstr;
4760 char *pos;
4761
4762 /* compute needed length for new string */
4763 for (x = args; x != NIL; x = cdr (x))
4764 len += strlength (car (x));
4765
4766 newstr = mk_empty_string (SCHEME_A_ len, ' ');
4767
4768 /* store the contents of the argument strings into the new string */
4769 for (pos = strvalue (newstr), x = args; x != NIL; pos += strlength (car (x)), x = cdr (x))
4770 memcpy (pos, strvalue (car (x)), strlength (car (x)));
4771
4772 s_return (newstr);
4773 }
4774
4775 case OP_STRING_COPY: /* substring/string-copy */
4776 {
4777 char *str = strvalue (x);
4778 int index0 = cadr (args) == NIL ? 0 : ivalue_unchecked (cadr (args));
4779 int index1;
4780 int len;
4781
4782 if (index0 > strlength (x))
4783 Error_1 ("string->copy: start out of bounds:", cadr (args));
4784
4785 if (cddr (args) != NIL)
4786 {
4787 index1 = ivalue_unchecked (caddr (args));
4788
4789 if (index1 > strlength (x) || index1 < index0)
4790 Error_1 ("string->copy: end out of bounds:", caddr (args));
4791 }
4792 else
4793 index1 = strlength (x);
4794
4795 len = index1 - index0;
4796 x = mk_counted_string (SCHEME_A_ str + index0, len);
4797
4798 s_return (x);
4799 }
4800
4801 case OP_VECTOR: /* vector */
4802 {
4803 int i;
4804 pointer vec;
4805 int len = list_length (SCHEME_A_ args);
4806
4807 if (len < 0)
4808 Error_1 ("vector: not a proper list:", args);
4809
4810 vec = mk_vector (SCHEME_A_ len);
4811
4812 #if USE_ERROR_CHECKING
4813 if (SCHEME_V->no_memory)
4814 s_return (S_SINK);
4815 #endif
4816
4817 for (x = args, i = 0; is_pair (x); x = cdr (x), i++)
4818 vector_set (vec, i, car (x));
4819
4820 s_return (vec);
4821 }
4822
4823 case OP_MKVECTOR: /* make-vector */
4824 {
4825 pointer fill = NIL;
4826 pointer vec;
4827 int len = ivalue_unchecked (x);
4828
4829 if (cdr (args) != NIL)
4830 fill = cadr (args);
4831
4832 vec = mk_vector (SCHEME_A_ len);
4833
4834 #if USE_ERROR_CHECKING
4835 if (SCHEME_V->no_memory)
4836 s_return (S_SINK);
4837 #endif
4838
4839 if (fill != NIL)
4840 fill_vector (vec, 0, fill);
4841
4842 s_return (vec);
4843 }
4844
4845 case OP_VECLEN: /* vector-length */
4846 s_return (mk_integer (SCHEME_A_ veclength (x)));
4847
4848 case OP_VECRESIZE:
4849 vector_resize (x, ivalue_unchecked (cadr (args)), caddr (args));
4850 s_return (x);
4851
4852 case OP_VECREF: /* vector-ref */
4853 {
4854 int index = ivalue_unchecked (cadr (args));
4855
4856 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4857 Error_1 ("vector-ref: out of bounds:", cadr (args));
4858
4859 s_return (vector_get (x, index));
4860 }
4861
4862 case OP_VECSET: /* vector-set! */
4863 {
4864 int index = ivalue_unchecked (cadr (args));
4865
4866 if (is_immutable (x))
4867 Error_1 ("vector-set!: unable to alter immutable vector:", x);
4868
4869 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4870 Error_1 ("vector-set!: out of bounds:", cadr (args));
4871
4872 vector_set (x, index, caddr (args));
4873 s_return (x);
4874 }
4875 }
4876
4877 if (USE_ERROR_CHECKING) abort ();
4878 }
4879
4880 /* relational ops */
4881 ecb_hot static int
4882 opexe_2 (SCHEME_P_ enum scheme_opcodes op)
4883 {
4884 pointer x = SCHEME_V->args;
4885
4886 for (;;)
4887 {
4888 num v = nvalue (car (x));
4889 x = cdr (x);
4890
4891 if (x == NIL)
4892 break;
4893
4894 int r = num_cmp (v, nvalue (car (x)));
4895
4896 switch (op)
4897 {
4898 case OP_NUMEQ: r = r == 0; break;
4899 case OP_LESS: r = r < 0; break;
4900 case OP_GRE: r = r > 0; break;
4901 case OP_LEQ: r = r <= 0; break;
4902 case OP_GEQ: r = r >= 0; break;
4903 }
4904
4905 if (!r)
4906 s_return (S_F);
4907 }
4908
4909 s_return (S_T);
4910 }
4911
4912 /* predicates */
4913 ecb_hot static int
4914 opexe_3 (SCHEME_P_ enum scheme_opcodes op)
4915 {
4916 pointer args = SCHEME_V->args;
4917 pointer a = car (args);
4918 pointer d = cdr (args);
4919 int r;
4920
4921 switch (op)
4922 {
4923 case OP_NOT: /* not */ r = is_false (a) ; break;
4924 case OP_BOOLP: /* boolean? */ r = a == S_F || a == S_T ; break;
4925 case OP_EOFOBJP: /* eof-object? */ r = a == S_EOF ; break;
4926 case OP_NULLP: /* null? */ r = a == NIL ; break;
4927 case OP_SYMBOLP: /* symbol? */ r = is_symbol (a) ; break;
4928 case OP_GENSYMP: /* gensym? */ r = is_gensym (SCHEME_A_ a); break;
4929 case OP_NUMBERP: /* number? */ r = is_number (a) ; break;
4930 case OP_STRINGP: /* string? */ r = is_string (a) ; break;
4931 case OP_INTEGERP: /* integer? */ r = is_integer (a) ; break;
4932 case OP_REALP: /* real? */ r = is_number (a) ; break; /* all numbers are real */
4933 case OP_CHARP: /* char? */ r = is_character (a) ; break;
4934
4935 #if USE_CHAR_CLASSIFIERS
4936 case OP_CHARAP: /* char-alphabetic? */ r = Cisalpha (ivalue_unchecked (a)); break;
4937 case OP_CHARNP: /* char-numeric? */ r = Cisdigit (ivalue_unchecked (a)); break;
4938 case OP_CHARWP: /* char-whitespace? */ r = Cisspace (ivalue_unchecked (a)); break;
4939 case OP_CHARUP: /* char-upper-case? */ r = Cisupper (ivalue_unchecked (a)); break;
4940 case OP_CHARLP: /* char-lower-case? */ r = Cislower (ivalue_unchecked (a)); break;
4941 #endif
4942
4943 #if USE_PORTS
4944 case OP_PORTP: /* port? */ r = is_port (a) ; break;
4945 case OP_INPORTP: /* input-port? */ r = is_inport (a) ; break;
4946 case OP_OUTPORTP: /* output-port? */ r = is_outport (a); break;
4947 #endif
4948
4949 case OP_PROCP: /* procedure? */
4950
4951 /*--
4952 * continuation should be procedure by the example
4953 * (call-with-current-continuation procedure?) ==> #t
4954 * in R^3 report sec. 6.9
4955 */
4956 r = is_proc (a) || is_closure (a) || is_continuation (a) || is_foreign (a);
4957 break;
4958
4959 case OP_PAIRP: /* pair? */ r = is_pair (a) ; break;
4960 case OP_LISTP: /* list? */ r = list_length (SCHEME_A_ a) >= 0; break;
4961 case OP_ENVP: /* environment? */ r = is_environment (a) ; break;
4962 case OP_VECTORP: /* vector? */ r = is_vector (a) ; break;
4963 case OP_EQ: /* eq? */ r = a == cadr (args) ; break;
4964 case OP_EQV: /* eqv? */ r = eqv (a, cadr (args)) ; break;
4965 }
4966
4967 s_retbool (r);
4968 }
4969
4970 /* promises, list ops, ports */
4971 ecb_hot static int
4972 opexe_4 (SCHEME_P_ enum scheme_opcodes op)
4973 {
4974 pointer args = SCHEME_V->args;
4975 pointer a = car (args);
4976 pointer x, y;
4977
4978 switch (op)
4979 {
4980 case OP_FORCE: /* force */
4981 SCHEME_V->code = a;
4982
4983 if (is_promise (SCHEME_V->code))
4984 {
4985 /* Should change type to closure here */
4986 s_save (SCHEME_A_ OP_SAVE_FORCED, NIL, SCHEME_V->code);
4987 SCHEME_V->args = NIL;
4988 s_goto (OP_APPLY);
4989 }
4990 else
4991 s_return (SCHEME_V->code);
4992
4993 case OP_SAVE_FORCED: /* Save forced value replacing promise */
4994 *CELL (SCHEME_V->code) = *CELL (SCHEME_V->value);
4995 s_return (SCHEME_V->value);
4996
4997 #if USE_PORTS
4998
4999 case OP_EOF_OBJECT: /* eof-object */
5000 s_return (S_EOF);
5001
5002 case OP_WRITE: /* write */
5003 case OP_DISPLAY: /* display */
5004 case OP_WRITE_CHAR: /* write-char */
5005 if (is_pair (cdr (SCHEME_V->args)))
5006 {
5007 if (cadr (SCHEME_V->args) != SCHEME_V->outport)
5008 {
5009 x = cons (SCHEME_V->outport, NIL);
5010 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
5011 SCHEME_V->outport = cadr (SCHEME_V->args);
5012 }
5013 }
5014
5015 SCHEME_V->args = a;
5016
5017 if (op == OP_WRITE)
5018 SCHEME_V->print_flag = 1;
5019 else
5020 SCHEME_V->print_flag = 0;
5021
5022 s_goto (OP_P0LIST);
5023
5024 //TODO: move to scheme
5025 case OP_NEWLINE: /* newline */
5026 if (is_pair (args))
5027 {
5028 if (a != SCHEME_V->outport)
5029 {
5030 x = cons (SCHEME_V->outport, NIL);
5031 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
5032 SCHEME_V->outport = a;
5033 }
5034 }
5035
5036 putcharacter (SCHEME_A_ '\n');
5037 s_return (S_T);
5038 #endif
5039
5040 case OP_ERR0: /* error */
5041 SCHEME_V->retcode = -1;
5042
5043 if (!is_string (a))
5044 {
5045 args = cons (mk_string (SCHEME_A_ " -- "), args);
5046 setimmutable (car (args));
5047 }
5048
5049 putstr (SCHEME_A_ "Error: ");
5050 putstr (SCHEME_A_ strvalue (car (args)));
5051 SCHEME_V->args = cdr (args);
5052 s_goto (OP_ERR1);
5053
5054 case OP_ERR1: /* error */
5055 putcharacter (SCHEME_A_ ' ');
5056
5057 if (args != NIL)
5058 {
5059 s_save (SCHEME_A_ OP_ERR1, cdr (args), NIL);
5060 SCHEME_V->args = a;
5061 SCHEME_V->print_flag = 1;
5062 s_goto (OP_P0LIST);
5063 }
5064 else
5065 {
5066 putcharacter (SCHEME_A_ '\n');
5067
5068 if (SCHEME_V->interactive_repl)
5069 s_goto (OP_T0LVL);
5070 else
5071 return -1;
5072 }
5073
5074 case OP_REVERSE: /* reverse */
5075 s_return (reverse (SCHEME_A_ a));
5076
5077 case OP_LIST_STAR: /* list* */
5078 s_return (list_star (SCHEME_A_ SCHEME_V->args));
5079
5080 case OP_APPEND: /* append */
5081 x = NIL;
5082 y = args;
5083
5084 if (y == x)
5085 s_return (x);
5086
5087 /* cdr() in the while condition is not a typo. If car() */
5088 /* is used (append '() 'a) will return the wrong result. */
5089 while (cdr (y) != NIL)
5090 {
5091 x = revappend (SCHEME_A_ x, car (y));
5092 y = cdr (y);
5093
5094 if (x == S_F)
5095 Error_0 ("non-list argument to append");
5096 }
5097
5098 s_return (reverse_in_place (SCHEME_A_ car (y), x));
5099
5100 #if USE_PLIST
5101
5102 case OP_PUT: /* put */
5103 if (!hasprop (a) || !hasprop (cadr (args)))
5104 Error_0 ("illegal use of put");
5105
5106 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
5107 {
5108 if (caar (x) == y)
5109 break;
5110 }
5111
5112 if (x != NIL)
5113 cdar (x) = caddr (args);
5114 else
5115 symprop (a) = cons (cons (y, caddr (args)), symprop (a));
5116
5117 s_return (S_T);
5118
5119 case OP_GET: /* get */
5120 if (!hasprop (a) || !hasprop (cadr (args)))
5121 Error_0 ("illegal use of get");
5122
5123 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
5124 if (caar (x) == y)
5125 break;
5126
5127 if (x != NIL)
5128 s_return (cdar (x));
5129 else
5130 s_return (NIL);
5131
5132 #endif /* USE_PLIST */
5133
5134 case OP_QUIT: /* quit */
5135 if (is_pair (args))
5136 SCHEME_V->retcode = ivalue (a);
5137
5138 return -1;
5139
5140 case OP_GC: /* gc */
5141 gc (SCHEME_A_ NIL, NIL);
5142 s_return (S_T);
5143
5144 case OP_GCVERB: /* gc-verbose */
5145 {
5146 int was = SCHEME_V->gc_verbose;
5147
5148 SCHEME_V->gc_verbose = (a != S_F);
5149 s_retbool (was);
5150 }
5151
5152 case OP_NEWSEGMENT: /* new-segment */
5153 #if 0
5154 if (!is_pair (args) || !is_number (a))
5155 Error_0 ("new-segment: argument must be a number");
5156 #endif
5157 s_retbool (alloc_cellseg (SCHEME_A));
5158
5159 case OP_OBLIST: /* oblist */
5160 s_return (oblist_all_symbols (SCHEME_A));
5161
5162 #if USE_PORTS
5163
5164 case OP_CURR_INPORT: /* current-input-port */
5165 s_return (SCHEME_V->inport);
5166
5167 case OP_CURR_OUTPORT: /* current-output-port */
5168 s_return (SCHEME_V->outport);
5169
5170 case OP_OPEN_INFILE: /* open-input-file */
5171 case OP_OPEN_OUTFILE: /* open-output-file */
5172 case OP_OPEN_INOUTFILE: /* open-input-output-file */
5173 {
5174 int prop = 0;
5175 pointer p;
5176
5177 switch (op)
5178 {
5179 case OP_OPEN_INFILE:
5180 prop = port_input;
5181 break;
5182
5183 case OP_OPEN_OUTFILE:
5184 prop = port_output;
5185 break;
5186
5187 case OP_OPEN_INOUTFILE:
5188 prop = port_input | port_output;
5189 break;
5190 }
5191
5192 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
5193
5194 s_return (p == NIL ? S_F : p);
5195 }
5196
5197 # if USE_STRING_PORTS
5198
5199 case OP_OPEN_INSTRING: /* open-input-string */
5200 case OP_OPEN_INOUTSTRING: /* open-input-output-string */
5201 {
5202 int prop = 0;
5203 pointer p;
5204
5205 switch (op)
5206 {
5207 case OP_OPEN_INSTRING:
5208 prop = port_input;
5209 break;
5210
5211 case OP_OPEN_INOUTSTRING:
5212 prop = port_input | port_output;
5213 break;
5214 }
5215
5216 p = port_from_string (SCHEME_A_ strvalue (a),
5217 strvalue (a) + strlength (a), prop);
5218
5219 s_return (p == NIL ? S_F : p);
5220 }
5221
5222 case OP_OPEN_OUTSTRING: /* open-output-string */
5223 {
5224 pointer p;
5225
5226 if (a == NIL)
5227 p = port_from_scratch (SCHEME_A);
5228 else
5229 p = port_from_string (SCHEME_A_ strvalue (a),
5230 strvalue (a) + strlength (a), port_output);
5231
5232 s_return (p == NIL ? S_F : p);
5233 }
5234
5235 case OP_GET_OUTSTRING: /* get-output-string */
5236 {
5237 port *p = port (a);
5238
5239 if (p->kind & port_string)
5240 {
5241 off_t size;
5242 char *str;
5243
5244 size = p->rep.string.curr - p->rep.string.start + 1;
5245 str = malloc (size);
5246
5247 if (str != NULL)
5248 {
5249 pointer s;
5250
5251 memcpy (str, p->rep.string.start, size - 1);
5252 str[size - 1] = '\0';
5253 s = mk_string (SCHEME_A_ str);
5254 free (str);
5255 s_return (s);
5256 }
5257 }
5258
5259 s_return (S_F);
5260 }
5261
5262 # endif
5263
5264 case OP_CLOSE_INPORT: /* close-input-port */
5265 port_close (SCHEME_A_ a, port_input);
5266 s_return (S_T);
5267
5268 case OP_CLOSE_OUTPORT: /* close-output-port */
5269 port_close (SCHEME_A_ a, port_output);
5270 s_return (S_T);
5271 #endif
5272
5273 case OP_INT_ENV: /* interaction-environment */
5274 s_return (SCHEME_V->global_env);
5275
5276 case OP_CURR_ENV: /* current-environment */
5277 s_return (SCHEME_V->envir);
5278
5279 }
5280
5281 if (USE_ERROR_CHECKING) abort ();
5282 }
5283
5284 /* reading */
5285 ecb_cold static int
5286 opexe_5 (SCHEME_P_ enum scheme_opcodes op)
5287 {
5288 pointer args = SCHEME_V->args;
5289 pointer x;
5290
5291 if (SCHEME_V->nesting != 0)
5292 {
5293 int n = SCHEME_V->nesting;
5294
5295 SCHEME_V->nesting = 0;
5296 SCHEME_V->retcode = -1;
5297 Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
5298 }
5299
5300 switch (op)
5301 {
5302 /* ========== reading part ========== */
5303 #if USE_PORTS
5304 case OP_READ:
5305 if (!is_pair (args))
5306 s_goto (OP_READ_INTERNAL);
5307
5308 if (!is_inport (car (args)))
5309 Error_1 ("read: not an input port:", car (args));
5310
5311 if (car (args) == SCHEME_V->inport)
5312 s_goto (OP_READ_INTERNAL);
5313
5314 x = SCHEME_V->inport;
5315 SCHEME_V->inport = car (args);
5316 x = cons (x, NIL);
5317 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
5318 s_goto (OP_READ_INTERNAL);
5319
5320 case OP_READ_CHAR: /* read-char */
5321 case OP_PEEK_CHAR: /* peek-char */
5322 {
5323 int c;
5324
5325 if (is_pair (args))
5326 {
5327 if (car (args) != SCHEME_V->inport)
5328 {
5329 x = SCHEME_V->inport;
5330 x = cons (x, NIL);
5331 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
5332 SCHEME_V->inport = car (args);
5333 }
5334 }
5335
5336 c = inchar (SCHEME_A);
5337
5338 if (c == EOF)
5339 s_return (S_EOF);
5340
5341 if (SCHEME_V->op == OP_PEEK_CHAR)
5342 backchar (SCHEME_A_ c);
5343
5344 s_return (mk_character (SCHEME_A_ c));
5345 }
5346
5347 case OP_CHAR_READY: /* char-ready? */
5348 {
5349 pointer p = SCHEME_V->inport;
5350 int res;
5351
5352 if (is_pair (args))
5353 p = car (args);
5354
5355 res = port (p)->kind & port_string;
5356
5357 s_retbool (res);
5358 }
5359
5360 case OP_SET_INPORT: /* set-input-port */
5361 SCHEME_V->inport = car (args);
5362 s_return (SCHEME_V->value);
5363
5364 case OP_SET_OUTPORT: /* set-output-port */
5365 SCHEME_V->outport = car (args);
5366 s_return (SCHEME_V->value);
5367 #endif
5368
5369 case OP_RDSEXPR:
5370 switch (SCHEME_V->tok)
5371 {
5372 case TOK_EOF:
5373 s_return (S_EOF);
5374
5375 case TOK_VEC:
5376 s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
5377 /* fall through */
5378
5379 case TOK_LPAREN:
5380 SCHEME_V->tok = token (SCHEME_A);
5381
5382 if (SCHEME_V->tok == TOK_RPAREN)
5383 s_return (NIL);
5384 else if (SCHEME_V->tok == TOK_DOT)
5385 Error_0 ("syntax error: illegal dot expression");
5386
5387 SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
5388 s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
5389 s_goto (OP_RDSEXPR);
5390
5391 case TOK_QUOTE:
5392 s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
5393 SCHEME_V->tok = token (SCHEME_A);
5394 s_goto (OP_RDSEXPR);
5395
5396 case TOK_BQUOTE:
5397 SCHEME_V->tok = token (SCHEME_A);
5398
5399 if (SCHEME_V->tok == TOK_VEC)
5400 {
5401 s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
5402 SCHEME_V->tok = TOK_LPAREN;
5403 s_goto (OP_RDSEXPR);
5404 }
5405
5406 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
5407 s_goto (OP_RDSEXPR);
5408
5409 case TOK_COMMA:
5410 s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
5411 SCHEME_V->tok = token (SCHEME_A);
5412 s_goto (OP_RDSEXPR);
5413
5414 case TOK_ATMARK:
5415 s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
5416 SCHEME_V->tok = token (SCHEME_A);
5417 s_goto (OP_RDSEXPR);
5418
5419 case TOK_ATOM:
5420 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS)));
5421
5422 case TOK_DOTATOM:
5423 SCHEME_V->strbuff[0] = '.';
5424 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ 1, DELIMITERS)));
5425
5426 case TOK_STRATOM:
5427 //TODO: haven't checked whether the garbage collector could interfere and free x
5428 gc (SCHEME_A_ NIL, NIL); //TODO: superheavyhanded
5429 x = readstrexp (SCHEME_A_ '|');
5430 s_return (mk_atom (SCHEME_A_ strvalue (x)));
5431
5432 case TOK_DQUOTE:
5433 x = readstrexp (SCHEME_A_ '"');
5434
5435 if (x == S_F)
5436 Error_0 ("Error reading string");
5437
5438 setimmutable (x);
5439 s_return (x);
5440
5441 case TOK_SHARP:
5442 {
5443 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
5444
5445 if (f == NIL)
5446 Error_0 ("undefined sharp expression");
5447
5448 SCHEME_V->code = cons (slot_value_in_env (f), NIL);
5449 s_goto (OP_EVAL);
5450 }
5451
5452 case TOK_SHARP_CONST:
5453 if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS))) == NIL)
5454 Error_0 ("undefined sharp expression");
5455
5456 s_return (x);
5457
5458 default:
5459 Error_0 ("syntax error: illegal token");
5460 }
5461
5462 break;
5463
5464 case OP_RDLIST:
5465 SCHEME_V->args = cons (SCHEME_V->value, args);
5466 SCHEME_V->tok = token (SCHEME_A);
5467
5468 switch (SCHEME_V->tok)
5469 {
5470 case TOK_EOF:
5471 s_return (S_EOF);
5472
5473 case TOK_RPAREN:
5474 {
5475 int c = inchar (SCHEME_A);
5476
5477 if (c != '\n')
5478 backchar (SCHEME_A_ c);
5479 #if SHOW_ERROR_LINE
5480 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5481 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5482 #endif
5483
5484 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5485 s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5486 }
5487
5488 case TOK_DOT:
5489 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5490 SCHEME_V->tok = token (SCHEME_A);
5491 s_goto (OP_RDSEXPR);
5492
5493 default:
5494 s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5495 s_goto (OP_RDSEXPR);
5496 }
5497
5498 case OP_RDDOT:
5499 if (token (SCHEME_A) != TOK_RPAREN)
5500 Error_0 ("syntax error: illegal dot expression");
5501
5502 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5503 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5504
5505 case OP_RDQUOTE:
5506 s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5507
5508 case OP_RDQQUOTE:
5509 s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5510
5511 case OP_RDQQUOTEVEC:
5512 s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5513 cons (mk_symbol (SCHEME_A_ "vector"),
5514 cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5515
5516 case OP_RDUNQUOTE:
5517 s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5518
5519 case OP_RDUQTSP:
5520 s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5521
5522 case OP_RDVEC:
5523 /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5524 s_goto(OP_EVAL); Cannot be quoted */
5525 /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5526 s_return(x); Cannot be part of pairs */
5527 /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5528 SCHEME_V->args=SCHEME_V->value;
5529 s_goto(OP_APPLY); */
5530 SCHEME_V->args = SCHEME_V->value;
5531 s_goto (OP_VECTOR);
5532
5533 /* ========== printing part ========== */
5534 case OP_P0LIST:
5535 if (is_vector (args))
5536 {
5537 putstr (SCHEME_A_ "#(");
5538 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5539 s_goto (OP_PVECFROM);
5540 }
5541 else if (is_environment (args))
5542 {
5543 putstr (SCHEME_A_ "#<ENVIRONMENT>");
5544 s_return (S_T);
5545 }
5546 else if (!is_pair (args))
5547 {
5548 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5549 s_return (S_T);
5550 }
5551 else
5552 {
5553 pointer a = car (args);
5554 pointer b = cdr (args);
5555 int ok_abbr = ok_abbrev (b);
5556 SCHEME_V->args = car (b);
5557
5558 if (a == SCHEME_V->QUOTE && ok_abbr)
5559 putcharacter (SCHEME_A_ '\'');
5560 else if (a == SCHEME_V->QQUOTE && ok_abbr)
5561 putcharacter (SCHEME_A_ '`');
5562 else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5563 putcharacter (SCHEME_A_ ',');
5564 else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5565 putstr (SCHEME_A_ ",@");
5566 else
5567 {
5568 putcharacter (SCHEME_A_ '(');
5569 s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5570 SCHEME_V->args = a;
5571 }
5572
5573 s_goto (OP_P0LIST);
5574 }
5575
5576 case OP_P1LIST:
5577 if (is_pair (args))
5578 {
5579 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5580 putcharacter (SCHEME_A_ ' ');
5581 SCHEME_V->args = car (args);
5582 s_goto (OP_P0LIST);
5583 }
5584 else if (is_vector (args))
5585 {
5586 s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5587 putstr (SCHEME_A_ " . ");
5588 s_goto (OP_P0LIST);
5589 }
5590 else
5591 {
5592 if (args != NIL)
5593 {
5594 putstr (SCHEME_A_ " . ");
5595 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5596 }
5597
5598 putcharacter (SCHEME_A_ ')');
5599 s_return (S_T);
5600 }
5601
5602 case OP_PVECFROM:
5603 {
5604 IVALUE i = ivalue_unchecked (cdr (args));
5605 pointer vec = car (args);
5606 uint32_t len = veclength (vec);
5607
5608 if (i == len)
5609 {
5610 putcharacter (SCHEME_A_ ')');
5611 s_return (S_T);
5612 }
5613 else
5614 {
5615 pointer elem = vector_get (vec, i);
5616
5617 set_cdr (args, mk_integer (SCHEME_A_ i + 1));
5618 s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5619 SCHEME_V->args = elem;
5620
5621 if (i > 0)
5622 putcharacter (SCHEME_A_ ' ');
5623
5624 s_goto (OP_P0LIST);
5625 }
5626 }
5627 }
5628
5629 if (USE_ERROR_CHECKING) abort ();
5630 }
5631
5632 /* list ops */
5633 ecb_hot static int
5634 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5635 {
5636 pointer args = SCHEME_V->args;
5637 pointer a = car (args);
5638 pointer x, y;
5639
5640 switch (op)
5641 {
5642 case OP_LIST_LENGTH: /* length *//* a.k */
5643 {
5644 long v = list_length (SCHEME_A_ a);
5645
5646 if (v < 0)
5647 Error_1 ("length: not a list:", a);
5648
5649 s_return (mk_integer (SCHEME_A_ v));
5650 }
5651
5652 case OP_ASSQ: /* assq *//* a.k */
5653 x = a;
5654
5655 for (y = cadr (args); is_pair (y); y = cdr (y))
5656 {
5657 if (!is_pair (car (y)))
5658 Error_0 ("unable to handle non pair element");
5659
5660 if (x == caar (y))
5661 break;
5662 }
5663
5664 if (is_pair (y))
5665 s_return (car (y));
5666
5667 s_return (S_F);
5668
5669 case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5670 SCHEME_V->args = a;
5671
5672 if (SCHEME_V->args == NIL)
5673 s_return (S_F);
5674 else if (is_closure (SCHEME_V->args) || is_macro (SCHEME_V->args))
5675 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5676
5677 s_return (S_F);
5678
5679 case OP_CLOSUREP: /* closure? */
5680 /*
5681 * Note, macro object is also a closure.
5682 * Therefore, (closure? <#MACRO>) ==> #t
5683 * (schmorp) well, obviously not, fix? TODO
5684 */
5685 s_retbool (is_closure (a));
5686
5687 case OP_MACROP: /* macro? */
5688 s_retbool (is_macro (a));
5689 }
5690
5691 if (USE_ERROR_CHECKING) abort ();
5692 }
5693
5694 /* dispatch functions (opexe_x) return new opcode, or 0 for same opcode, or -1 to stop */
5695 typedef int (*dispatch_func)(SCHEME_P_ enum scheme_opcodes);
5696
5697 typedef int (*test_predicate)(pointer);
5698
5699 ecb_hot static int
5700 tst_any (pointer p)
5701 {
5702 return 1;
5703 }
5704
5705 ecb_hot static int
5706 tst_inonneg (pointer p)
5707 {
5708 return is_integer (p) && ivalue_unchecked (p) >= 0;
5709 }
5710
5711 ecb_hot static int
5712 tst_is_list (SCHEME_P_ pointer p)
5713 {
5714 return p == NIL || is_pair (p);
5715 }
5716
5717 /* Correspond carefully with following defines! */
5718 static struct
5719 {
5720 test_predicate fct;
5721 const char *kind;
5722 } tests[] = {
5723 { tst_any , 0 },
5724 { is_string , "string" },
5725 { is_symbol , "symbol" },
5726 { is_port , "port" },
5727 { is_inport , "input port" },
5728 { is_outport , "output port" },
5729 { is_environment, "environment" },
5730 { is_pair , "pair" },
5731 { 0 , "pair or '()" },
5732 { is_character , "character" },
5733 { is_vector , "vector" },
5734 { is_number , "number" },
5735 { is_integer , "integer" },
5736 { tst_inonneg , "non-negative integer" }
5737 };
5738
5739 #define TST_NONE 0 /* TST_NONE used for built-ins, 0 for internal ops */
5740 #define TST_ANY "\001"
5741 #define TST_STRING "\002"
5742 #define TST_SYMBOL "\003"
5743 #define TST_PORT "\004"
5744 #define TST_INPORT "\005"
5745 #define TST_OUTPORT "\006"
5746 #define TST_ENVIRONMENT "\007"
5747 #define TST_PAIR "\010"
5748 #define TST_LIST "\011"
5749 #define TST_CHAR "\012"
5750 #define TST_VECTOR "\013"
5751 #define TST_NUMBER "\014"
5752 #define TST_INTEGER "\015"
5753 #define TST_NATURAL "\016"
5754
5755 #define INF_ARG 0xff
5756 #define UNNAMED_OP ""
5757
5758 static const char opnames[] =
5759 #define OP_DEF(func,name,minarity,maxarity,argtest,op) name "\x00"
5760 #include "opdefines.h"
5761 #undef OP_DEF
5762 ;
5763
5764 ecb_cold static const char *
5765 opname (int idx)
5766 {
5767 const char *name = opnames;
5768
5769 /* should do this at compile time, but would require external program, right? */
5770 while (idx--)
5771 name += strlen (name) + 1;
5772
5773 return *name ? name : "ILLEGAL";
5774 }
5775
5776 ecb_cold static const char *
5777 procname (pointer x)
5778 {
5779 return opname (procnum (x));
5780 }
5781
5782 typedef struct
5783 {
5784 uint8_t func;
5785 /*dispatch_func func;*//*TODO: maybe optionally keep the pointer, for speed? */
5786 uint8_t builtin;
5787 #if USE_ERROR_CHECKING
5788 uint8_t min_arity;
5789 uint8_t max_arity;
5790 char arg_tests_encoding[3];
5791 #endif
5792 } op_code_info;
5793
5794 static const op_code_info dispatch_table[] = {
5795 #if USE_ERROR_CHECKING
5796 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1, minarity, maxarity, argtest },
5797 #else
5798 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1 },
5799 #endif
5800 #include "opdefines.h"
5801 #undef OP_DEF
5802 {0}
5803 };
5804
5805 /* kernel of this interpreter */
5806 ecb_hot static void
5807 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5808 {
5809 SCHEME_V->op = op;
5810
5811 for (;;)
5812 {
5813 const op_code_info *pcd = dispatch_table + SCHEME_V->op;
5814
5815 #if USE_ERROR_CHECKING
5816 if (pcd->builtin) /* if built-in function, check arguments */
5817 {
5818 char msg[STRBUFFSIZE];
5819 int n = list_length (SCHEME_A_ SCHEME_V->args);
5820
5821 /* Check number of arguments */
5822 if (ecb_expect_false (n < pcd->min_arity))
5823 {
5824 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5825 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5826 xError_1 (SCHEME_A_ msg, 0);
5827 continue;
5828 }
5829 else if (ecb_expect_false (n > pcd->max_arity && pcd->max_arity != INF_ARG))
5830 {
5831 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5832 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5833 xError_1 (SCHEME_A_ msg, 0);
5834 continue;
5835 }
5836 else
5837 {
5838 if (*pcd->arg_tests_encoding) /* literal 0 and TST_NONE treated the same */
5839 {
5840 int i = 0;
5841 int j;
5842 const char *t = pcd->arg_tests_encoding;
5843 pointer arglist = SCHEME_V->args;
5844
5845 do
5846 {
5847 pointer arg = car (arglist);
5848
5849 j = t[0];
5850
5851 /*TODO: tst_is_list has different prototype - fix if other tests acquire same prototype */
5852 if (j == TST_LIST[0])
5853 {
5854 if (!tst_is_list (SCHEME_A_ arg))
5855 break;
5856 }
5857 else
5858 {
5859 if (!tests[j - 1].fct (arg))
5860 break;
5861 }
5862
5863 if (t < pcd->arg_tests_encoding + sizeof (pcd->arg_tests_encoding) - 1 && t[1]) /* last test is replicated as necessary */
5864 t++;
5865
5866 arglist = cdr (arglist);
5867 i++;
5868 }
5869 while (i < n);
5870
5871 if (i < n)
5872 {
5873 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", opname (SCHEME_V->op), i + 1, tests[j].kind);
5874 xError_1 (SCHEME_A_ msg, 0);
5875 continue;
5876 }
5877 }
5878 }
5879 }
5880 #endif
5881
5882 ok_to_freely_gc (SCHEME_A);
5883
5884 static const dispatch_func dispatch_funcs[] = {
5885 opexe_0,
5886 opexe_1,
5887 opexe_2,
5888 opexe_3,
5889 opexe_4,
5890 opexe_5,
5891 opexe_6,
5892 };
5893
5894 if (ecb_expect_false (dispatch_funcs [pcd->func] (SCHEME_A_ SCHEME_V->op) != 0))
5895 return;
5896
5897 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5898 {
5899 putstr (SCHEME_A_ "No memory!\n");
5900 return;
5901 }
5902 }
5903 }
5904
5905 /* ========== Initialization of internal keywords ========== */
5906
5907 ecb_cold static void
5908 assign_syntax (SCHEME_P_ const char *name)
5909 {
5910 pointer x = oblist_add_by_name (SCHEME_A_ name);
5911 set_typeflag (x, typeflag (x) | T_SYNTAX);
5912 }
5913
5914 ecb_cold static void
5915 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5916 {
5917 pointer x = mk_symbol (SCHEME_A_ name);
5918 pointer y = mk_proc (SCHEME_A_ op);
5919 new_slot_in_env (SCHEME_A_ x, y);
5920 }
5921
5922 static pointer
5923 mk_proc (SCHEME_P_ enum scheme_opcodes op)
5924 {
5925 pointer y = get_cell (SCHEME_A_ NIL, NIL);
5926 set_typeflag (y, (T_PROC | T_ATOM));
5927 set_ivalue (y, op);
5928 return y;
5929 }
5930
5931 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5932 ecb_hot static int
5933 syntaxnum (pointer p)
5934 {
5935 const char *s = strvalue (p);
5936
5937 switch (strlength (p))
5938 {
5939 case 2:
5940 if (s[0] == 'i')
5941 return OP_IF0; /* if */
5942 else
5943 return OP_OR0; /* or */
5944
5945 case 3:
5946 if (s[0] == 'a')
5947 return OP_AND0; /* and */
5948 else
5949 return OP_LET0; /* let */
5950
5951 case 4:
5952 switch (s[3])
5953 {
5954 case 'e':
5955 return OP_CASE0; /* case */
5956
5957 case 'd':
5958 return OP_COND0; /* cond */
5959
5960 case '*':
5961 return OP_LET0AST;/* let* */
5962
5963 default:
5964 return OP_SET0; /* set! */
5965 }
5966
5967 case 5:
5968 switch (s[2])
5969 {
5970 case 'g':
5971 return OP_BEGIN; /* begin */
5972
5973 case 'l':
5974 return OP_DELAY; /* delay */
5975
5976 case 'c':
5977 return OP_MACRO0; /* macro */
5978
5979 default:
5980 return OP_QUOTE; /* quote */
5981 }
5982
5983 case 6:
5984 switch (s[2])
5985 {
5986 case 'm':
5987 return OP_LAMBDA; /* lambda */
5988
5989 case 'f':
5990 return OP_DEF0; /* define */
5991
5992 default:
5993 return OP_LET0REC;/* letrec */
5994 }
5995
5996 default:
5997 return OP_C0STREAM; /* cons-stream */
5998 }
5999 }
6000
6001 #if USE_MULTIPLICITY
6002 ecb_cold scheme *
6003 scheme_init_new ()
6004 {
6005 scheme *sc = malloc (sizeof (scheme));
6006
6007 if (!scheme_init (SCHEME_A))
6008 {
6009 free (SCHEME_A);
6010 return 0;
6011 }
6012 else
6013 return sc;
6014 }
6015 #endif
6016
6017 ecb_cold int
6018 scheme_init (SCHEME_P)
6019 {
6020 int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
6021
6022 /* this memset is not strictly correct, as we assume (intcache)
6023 * that memset 0 will also set pointers to 0, but memset does
6024 * of course not guarantee that. screw such systems.
6025 */
6026 memset (SCHEME_V, 0, sizeof (*SCHEME_V));
6027
6028 num_set_fixnum (num_zero, 1);
6029 num_set_ivalue (num_zero, 0);
6030 num_set_fixnum (num_one, 1);
6031 num_set_ivalue (num_one, 1);
6032
6033 #if USE_INTERFACE
6034 SCHEME_V->vptr = &vtbl;
6035 #endif
6036 SCHEME_V->gensym_cnt = 0;
6037 SCHEME_V->last_cell_seg = -1;
6038 SCHEME_V->free_cell = NIL;
6039 SCHEME_V->fcells = 0;
6040 SCHEME_V->no_memory = 0;
6041 SCHEME_V->inport = NIL;
6042 SCHEME_V->outport = NIL;
6043 SCHEME_V->save_inport = NIL;
6044 SCHEME_V->loadport = NIL;
6045 SCHEME_V->nesting = 0;
6046 SCHEME_V->interactive_repl = 0;
6047
6048 if (!alloc_cellseg (SCHEME_A))
6049 {
6050 #if USE_ERROR_CHECKING
6051 SCHEME_V->no_memory = 1;
6052 return 0;
6053 #endif
6054 }
6055
6056 SCHEME_V->gc_verbose = 0;
6057 dump_stack_initialize (SCHEME_A);
6058 SCHEME_V->code = NIL;
6059 SCHEME_V->args = NIL;
6060 SCHEME_V->envir = NIL;
6061 SCHEME_V->value = NIL;
6062 SCHEME_V->tracing = 0;
6063
6064 /* init NIL */
6065 set_typeflag (NIL, T_SPECIAL | T_ATOM);
6066 set_car (NIL, NIL);
6067 set_cdr (NIL, NIL);
6068 /* init T */
6069 set_typeflag (S_T, T_SPECIAL | T_ATOM);
6070 set_car (S_T, S_T);
6071 set_cdr (S_T, S_T);
6072 /* init F */
6073 set_typeflag (S_F, T_SPECIAL | T_ATOM);
6074 set_car (S_F, S_F);
6075 set_cdr (S_F, S_F);
6076 /* init EOF_OBJ */
6077 set_typeflag (S_EOF, T_SPECIAL | T_ATOM);
6078 set_car (S_EOF, S_EOF);
6079 set_cdr (S_EOF, S_EOF);
6080 /* init sink */
6081 set_typeflag (S_SINK, T_PAIR);
6082 set_car (S_SINK, NIL);
6083
6084 /* init c_nest */
6085 SCHEME_V->c_nest = NIL;
6086
6087 SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
6088 /* init global_env */
6089 new_frame_in_env (SCHEME_A_ NIL);
6090 SCHEME_V->global_env = SCHEME_V->envir;
6091 /* init else */
6092 new_slot_in_env (SCHEME_A_ mk_symbol (SCHEME_A_ "else"), S_T);
6093
6094 {
6095 static const char *syntax_names[] = {
6096 "lambda", "quote", "define", "if", "begin", "set!",
6097 "let", "let*", "letrec", "cond", "delay", "and",
6098 "or", "cons-stream", "macro", "case"
6099 };
6100
6101 for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
6102 assign_syntax (SCHEME_A_ syntax_names[i]);
6103 }
6104
6105 // TODO: should iterate via strlen, to avoid n² complexity
6106 for (i = 0; i < n; i++)
6107 if (dispatch_table[i].builtin)
6108 assign_proc (SCHEME_A_ i, opname (i));
6109
6110 /* initialization of global pointers to special symbols */
6111 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
6112 SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
6113 SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
6114 SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
6115 SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
6116 SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
6117 SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
6118 SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
6119 SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
6120 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
6121
6122 return !SCHEME_V->no_memory;
6123 }
6124
6125 #if USE_PORTS
6126 ecb_cold void
6127 scheme_set_input_port_file (SCHEME_P_ int fin)
6128 {
6129 SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
6130 }
6131
6132 ecb_cold void
6133 scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
6134 {
6135 SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
6136 }
6137
6138 ecb_cold void
6139 scheme_set_output_port_file (SCHEME_P_ int fout)
6140 {
6141 SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
6142 }
6143
6144 ecb_cold void
6145 scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
6146 {
6147 SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
6148 }
6149 #endif
6150
6151 ecb_cold void
6152 scheme_set_external_data (SCHEME_P_ void *p)
6153 {
6154 SCHEME_V->ext_data = p;
6155 }
6156
6157 ecb_cold void
6158 scheme_deinit (SCHEME_P)
6159 {
6160 int i;
6161
6162 #if SHOW_ERROR_LINE
6163 char *fname;
6164 #endif
6165
6166 SCHEME_V->oblist = NIL;
6167 SCHEME_V->global_env = NIL;
6168 dump_stack_free (SCHEME_A);
6169 SCHEME_V->envir = NIL;
6170 SCHEME_V->code = NIL;
6171 SCHEME_V->args = NIL;
6172 SCHEME_V->value = NIL;
6173
6174 if (is_port (SCHEME_V->inport))
6175 set_typeflag (SCHEME_V->inport, T_ATOM);
6176
6177 SCHEME_V->inport = NIL;
6178 SCHEME_V->outport = NIL;
6179
6180 if (is_port (SCHEME_V->save_inport))
6181 set_typeflag (SCHEME_V->save_inport, T_ATOM);
6182
6183 SCHEME_V->save_inport = NIL;
6184
6185 if (is_port (SCHEME_V->loadport))
6186 set_typeflag (SCHEME_V->loadport, T_ATOM);
6187
6188 SCHEME_V->loadport = NIL;
6189 SCHEME_V->gc_verbose = 0;
6190 gc (SCHEME_A_ NIL, NIL);
6191
6192 for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
6193 free (SCHEME_V->cell_seg[i]);
6194
6195 #if SHOW_ERROR_LINE
6196 for (i = 0; i <= SCHEME_V->file_i; i++)
6197 if (SCHEME_V->load_stack[i].kind & port_file)
6198 {
6199 fname = SCHEME_V->load_stack[i].rep.stdio.filename;
6200
6201 if (fname)
6202 free (fname);
6203 }
6204 #endif
6205 }
6206
6207 ecb_cold void
6208 scheme_load_file (SCHEME_P_ int fin)
6209 {
6210 scheme_load_named_file (SCHEME_A_ fin, 0);
6211 }
6212
6213 ecb_cold void
6214 scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
6215 {
6216 dump_stack_reset (SCHEME_A);
6217 SCHEME_V->envir = SCHEME_V->global_env;
6218 SCHEME_V->file_i = 0;
6219 SCHEME_V->load_stack[0].unget = -1;
6220 SCHEME_V->load_stack[0].kind = port_input | port_file;
6221 SCHEME_V->load_stack[0].rep.stdio.file = fin;
6222 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
6223 SCHEME_V->retcode = 0;
6224
6225 if (fin == STDIN_FILENO)
6226 SCHEME_V->interactive_repl = 1;
6227
6228 #if USE_PORTS
6229 #if SHOW_ERROR_LINE
6230 SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
6231
6232 if (fin != STDIN_FILENO && filename)
6233 SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
6234 #endif
6235 #endif
6236
6237 SCHEME_V->inport = SCHEME_V->loadport;
6238 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
6239 Eval_Cycle (SCHEME_A_ OP_T0LVL);
6240
6241 set_typeflag (SCHEME_V->loadport, T_ATOM);
6242
6243 if (SCHEME_V->retcode == 0)
6244 SCHEME_V->retcode = SCHEME_V->nesting != 0;
6245 }
6246
6247 ecb_cold void
6248 scheme_load_string (SCHEME_P_ const char *cmd)
6249 {
6250 #if USE_PORTs
6251 dump_stack_reset (SCHEME_A);
6252 SCHEME_V->envir = SCHEME_V->global_env;
6253 SCHEME_V->file_i = 0;
6254 SCHEME_V->load_stack[0].kind = port_input | port_string;
6255 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
6256 SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
6257 SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
6258 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
6259 SCHEME_V->retcode = 0;
6260 SCHEME_V->interactive_repl = 0;
6261 SCHEME_V->inport = SCHEME_V->loadport;
6262 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
6263 Eval_Cycle (SCHEME_A_ OP_T0LVL);
6264 set_typeflag (SCHEME_V->loadport, T_ATOM);
6265
6266 if (SCHEME_V->retcode == 0)
6267 SCHEME_V->retcode = SCHEME_V->nesting != 0;
6268 #else
6269 abort ();
6270 #endif
6271 }
6272
6273 ecb_cold void
6274 scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
6275 {
6276 pointer x;
6277
6278 x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
6279
6280 if (x != NIL)
6281 set_slot_in_env (SCHEME_A_ x, value);
6282 else
6283 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
6284 }
6285
6286 #if !STANDALONE
6287
6288 ecb_cold void
6289 scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
6290 {
6291 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
6292 }
6293
6294 ecb_cold void
6295 scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
6296 {
6297 int i;
6298
6299 for (i = 0; i < count; i++)
6300 scheme_register_foreign_func (SCHEME_A_ list + i);
6301 }
6302
6303 ecb_cold pointer
6304 scheme_apply0 (SCHEME_P_ const char *procname)
6305 {
6306 return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
6307 }
6308
6309 ecb_cold void
6310 save_from_C_call (SCHEME_P)
6311 {
6312 pointer saved_data = cons (car (S_SINK),
6313 cons (SCHEME_V->envir,
6314 SCHEME_V->dump));
6315
6316 /* Push */
6317 SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
6318 /* Truncate the dump stack so TS will return here when done, not
6319 directly resume pre-C-call operations. */
6320 dump_stack_reset (SCHEME_A);
6321 }
6322
6323 ecb_cold void
6324 restore_from_C_call (SCHEME_P)
6325 {
6326 set_car (S_SINK, caar (SCHEME_V->c_nest));
6327 SCHEME_V->envir = cadar (SCHEME_V->c_nest);
6328 SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
6329 /* Pop */
6330 SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
6331 }
6332
6333 /* "func" and "args" are assumed to be already eval'ed. */
6334 ecb_cold pointer
6335 scheme_call (SCHEME_P_ pointer func, pointer args)
6336 {
6337 int old_repl = SCHEME_V->interactive_repl;
6338
6339 SCHEME_V->interactive_repl = 0;
6340 save_from_C_call (SCHEME_A);
6341 SCHEME_V->envir = SCHEME_V->global_env;
6342 SCHEME_V->args = args;
6343 SCHEME_V->code = func;
6344 SCHEME_V->retcode = 0;
6345 Eval_Cycle (SCHEME_A_ OP_APPLY);
6346 SCHEME_V->interactive_repl = old_repl;
6347 restore_from_C_call (SCHEME_A);
6348 return SCHEME_V->value;
6349 }
6350
6351 ecb_cold pointer
6352 scheme_eval (SCHEME_P_ pointer obj)
6353 {
6354 int old_repl = SCHEME_V->interactive_repl;
6355
6356 SCHEME_V->interactive_repl = 0;
6357 save_from_C_call (SCHEME_A);
6358 SCHEME_V->args = NIL;
6359 SCHEME_V->code = obj;
6360 SCHEME_V->retcode = 0;
6361 Eval_Cycle (SCHEME_A_ OP_EVAL);
6362 SCHEME_V->interactive_repl = old_repl;
6363 restore_from_C_call (SCHEME_A);
6364 return SCHEME_V->value;
6365 }
6366
6367 #endif
6368
6369 /* ========== Main ========== */
6370
6371 #if STANDALONE
6372
6373 ecb_cold int
6374 main (int argc, char **argv)
6375 {
6376 # if USE_MULTIPLICITY
6377 scheme ssc;
6378 scheme *const SCHEME_V = &ssc;
6379 # else
6380 # endif
6381 int fin;
6382 char *file_name = InitFile;
6383 int retcode;
6384 int isfile = 1;
6385 #if EXPERIMENT
6386 system ("ps v $PPID");
6387 #endif
6388
6389 if (argc == 2 && strcmp (argv[1], "-?") == 0)
6390 {
6391 putstr (SCHEME_A_ "Usage: tinyscheme -?\n");
6392 putstr (SCHEME_A_ "or: tinyscheme [<file1> <file2> ...]\n");
6393 putstr (SCHEME_A_ "followed by\n");
6394 putstr (SCHEME_A_ " -1 <file> [<arg1> <arg2> ...]\n");
6395 putstr (SCHEME_A_ " -c <Scheme commands> [<arg1> <arg2> ...]\n");
6396 putstr (SCHEME_A_ "assuming that the executable is named tinyscheme.\n");
6397 putstr (SCHEME_A_ "Use - as filename for stdin.\n");
6398 return 1;
6399 }
6400
6401 if (!scheme_init (SCHEME_A))
6402 {
6403 putstr (SCHEME_A_ "Could not initialize!\n");
6404 return 2;
6405 }
6406
6407 # if USE_PORTS
6408 scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
6409 scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
6410 # endif
6411
6412 argv++;
6413
6414 #if 0
6415 if (access (file_name, 0) != 0)
6416 {
6417 char *p = getenv ("TINYSCHEMEINIT");
6418
6419 if (p != 0)
6420 file_name = p;
6421 }
6422 #endif
6423
6424 do
6425 {
6426 if (strcmp (file_name, "-") == 0)
6427 fin = STDIN_FILENO;
6428 else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
6429 {
6430 pointer args = NIL;
6431
6432 isfile = file_name[1] == '1';
6433 file_name = *argv++;
6434
6435 if (strcmp (file_name, "-") == 0)
6436 fin = STDIN_FILENO;
6437 else if (isfile)
6438 fin = open (file_name, O_RDONLY);
6439
6440 for (; *argv; argv++)
6441 {
6442 pointer value = mk_string (SCHEME_A_ * argv);
6443
6444 args = cons (value, args);
6445 }
6446
6447 args = reverse_in_place (SCHEME_A_ NIL, args);
6448 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
6449
6450 }
6451 else
6452 fin = open (file_name, O_RDONLY);
6453
6454 if (isfile && fin < 0)
6455 {
6456 putstr (SCHEME_A_ "Could not open file ");
6457 putstr (SCHEME_A_ file_name);
6458 putcharacter (SCHEME_A_ '\n');
6459 }
6460 else
6461 {
6462 if (isfile)
6463 scheme_load_named_file (SCHEME_A_ fin, file_name);
6464 else
6465 scheme_load_string (SCHEME_A_ file_name);
6466
6467 if (!isfile || fin != STDIN_FILENO)
6468 {
6469 if (SCHEME_V->retcode != 0)
6470 {
6471 putstr (SCHEME_A_ "Errors encountered reading ");
6472 putstr (SCHEME_A_ file_name);
6473 putcharacter (SCHEME_A_ '\n');
6474 }
6475
6476 if (isfile)
6477 close (fin);
6478 }
6479 }
6480
6481 file_name = *argv++;
6482 }
6483 while (file_name != 0);
6484
6485 if (argc == 1)
6486 scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6487
6488 retcode = SCHEME_V->retcode;
6489 scheme_deinit (SCHEME_A);
6490
6491 return retcode;
6492 }
6493
6494 #endif
6495
6496 /*
6497 Local variables:
6498 c-file-style: "k&r"
6499 End:
6500 */