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