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