ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/microscheme/scheme.c
Revision: 1.61
Committed: Wed Dec 2 07:43:46 2015 UTC (8 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.60: +264 -166 lines
Log Message:
*** empty log message ***

File Contents

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