ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.36
Committed: Sun Nov 29 05:04:29 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.35: +5 -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 pointer
1360 vector_get (pointer vec, uint32_t ielem)
1361 {
1362 return vecvalue(vec)[ielem];
1363 }
1364
1365 INTERFACE void
1366 vector_set (pointer vec, uint32_t ielem, pointer a)
1367 {
1368 vecvalue(vec)[ielem] = a;
1369 }
1370
1371 /* get new symbol */
1372 INTERFACE pointer
1373 mk_symbol (SCHEME_P_ const char *name)
1374 {
1375 /* first check oblist */
1376 pointer x = oblist_find_by_name (SCHEME_A_ name);
1377
1378 if (x == NIL)
1379 x = oblist_add_by_name (SCHEME_A_ name);
1380
1381 return x;
1382 }
1383
1384 INTERFACE pointer
1385 gensym (SCHEME_P)
1386 {
1387 pointer x;
1388 char name[40] = "gensym-";
1389 xnum (name + 7, SCHEME_V->gensym_cnt);
1390
1391 return generate_symbol (SCHEME_A_ name);
1392 }
1393
1394 /* make symbol or number atom from string */
1395 static pointer
1396 mk_atom (SCHEME_P_ char *q)
1397 {
1398 char c, *p;
1399 int has_dec_point = 0;
1400 int has_fp_exp = 0;
1401
1402 #if USE_COLON_HOOK
1403 if ((p = strstr (q, "::")) != 0)
1404 {
1405 *p = 0;
1406 return cons (SCHEME_V->COLON_HOOK,
1407 cons (cons (SCHEME_V->QUOTE,
1408 cons (mk_atom (SCHEME_A_ p + 2), NIL)), cons (mk_symbol (SCHEME_A_ strlwr (q)), NIL)));
1409 }
1410 #endif
1411
1412 p = q;
1413 c = *p++;
1414
1415 if ((c == '+') || (c == '-'))
1416 {
1417 c = *p++;
1418
1419 if (c == '.')
1420 {
1421 has_dec_point = 1;
1422 c = *p++;
1423 }
1424
1425 if (!isdigit (c))
1426 return mk_symbol (SCHEME_A_ strlwr (q));
1427 }
1428 else if (c == '.')
1429 {
1430 has_dec_point = 1;
1431 c = *p++;
1432
1433 if (!isdigit (c))
1434 return mk_symbol (SCHEME_A_ strlwr (q));
1435 }
1436 else if (!isdigit (c))
1437 return mk_symbol (SCHEME_A_ strlwr (q));
1438
1439 for (; (c = *p) != 0; ++p)
1440 {
1441 if (!isdigit (c))
1442 {
1443 if (c == '.')
1444 {
1445 if (!has_dec_point)
1446 {
1447 has_dec_point = 1;
1448 continue;
1449 }
1450 }
1451 else if ((c == 'e') || (c == 'E'))
1452 {
1453 if (!has_fp_exp)
1454 {
1455 has_dec_point = 1; /* decimal point illegal from now on */
1456 p++;
1457
1458 if ((*p == '-') || (*p == '+') || isdigit (*p))
1459 continue;
1460 }
1461 }
1462
1463 return mk_symbol (SCHEME_A_ strlwr (q));
1464 }
1465 }
1466
1467 #if USE_REAL
1468 if (has_dec_point)
1469 return mk_real (SCHEME_A_ atof (q));
1470 #endif
1471
1472 return mk_integer (SCHEME_A_ strtol (q, 0, 10));
1473 }
1474
1475 /* make constant */
1476 static pointer
1477 mk_sharp_const (SCHEME_P_ char *name)
1478 {
1479 if (!strcmp (name, "t"))
1480 return S_T;
1481 else if (!strcmp (name, "f"))
1482 return S_F;
1483 else if (*name == '\\') /* #\w (character) */
1484 {
1485 int c;
1486
1487 if (stricmp (name + 1, "space") == 0)
1488 c = ' ';
1489 else if (stricmp (name + 1, "newline") == 0)
1490 c = '\n';
1491 else if (stricmp (name + 1, "return") == 0)
1492 c = '\r';
1493 else if (stricmp (name + 1, "tab") == 0)
1494 c = '\t';
1495 else if (name[1] == 'x' && name[2] != 0)
1496 {
1497 long c1 = strtol (name + 2, 0, 16);
1498
1499 if (0 <= c1 && c1 <= UCHAR_MAX)
1500 c = c1;
1501 else
1502 return NIL;
1503 }
1504 #if USE_ASCII_NAMES
1505 else if (is_ascii_name (name + 1, &c))
1506 /* nothing */;
1507 #endif
1508 else if (name[2] == 0)
1509 c = name[1];
1510 else
1511 return NIL;
1512
1513 return mk_character (SCHEME_A_ c);
1514 }
1515 else
1516 {
1517 /* identify base by string index */
1518 const char baseidx[17] = "ffbf" "ffff" "ofdf" "ffff" "x";
1519 char *base = strchr (baseidx, *name);
1520
1521 if (base)
1522 return mk_integer (SCHEME_A_ strtol (name + 1, 0, base - baseidx));
1523
1524 return NIL;
1525 }
1526 }
1527
1528 /* ========== garbage collector ========== */
1529
1530 /*--
1531 * We use algorithm E (Knuth, The Art of Computer Programming Vol.1,
1532 * sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm,
1533 * for marking.
1534 *
1535 * The exception is vectors - vectors are currently marked recursively,
1536 * which is inherited form tinyscheme and could be fixed by having another
1537 * word of context in the vector
1538 */
1539 static void
1540 mark (pointer a)
1541 {
1542 pointer t, q, p;
1543
1544 t = 0;
1545 p = a;
1546 E2:
1547 setmark (p);
1548
1549 if (ecb_expect_false (is_vector (p)))
1550 {
1551 int i;
1552
1553 for (i = 0; i < veclength (p); i++)
1554 mark (vecvalue (p)[i]);
1555 }
1556
1557 if (is_atom (p))
1558 goto E6;
1559
1560 /* E4: down car */
1561 q = car (p);
1562
1563 if (q && !is_mark (q))
1564 {
1565 setatom (p); /* a note that we have moved car */
1566 set_car (p, t);
1567 t = p;
1568 p = q;
1569 goto E2;
1570 }
1571
1572 E5:
1573 q = cdr (p); /* down cdr */
1574
1575 if (q && !is_mark (q))
1576 {
1577 set_cdr (p, t);
1578 t = p;
1579 p = q;
1580 goto E2;
1581 }
1582
1583 E6: /* up. Undo the link switching from steps E4 and E5. */
1584 if (!t)
1585 return;
1586
1587 q = t;
1588
1589 if (is_atom (q))
1590 {
1591 clratom (q);
1592 t = car (q);
1593 set_car (q, p);
1594 p = q;
1595 goto E5;
1596 }
1597 else
1598 {
1599 t = cdr (q);
1600 set_cdr (q, p);
1601 p = q;
1602 goto E6;
1603 }
1604 }
1605
1606 /* garbage collection. parameter a, b is marked. */
1607 static void
1608 gc (SCHEME_P_ pointer a, pointer b)
1609 {
1610 pointer p;
1611 int i;
1612
1613 if (SCHEME_V->gc_verbose)
1614 putstr (SCHEME_A_ "gc...");
1615
1616 /* mark system globals */
1617 mark (SCHEME_V->oblist);
1618 mark (SCHEME_V->global_env);
1619
1620 /* mark current registers */
1621 mark (SCHEME_V->args);
1622 mark (SCHEME_V->envir);
1623 mark (SCHEME_V->code);
1624 dump_stack_mark (SCHEME_A);
1625 mark (SCHEME_V->value);
1626 mark (SCHEME_V->inport);
1627 mark (SCHEME_V->save_inport);
1628 mark (SCHEME_V->outport);
1629 mark (SCHEME_V->loadport);
1630
1631 /* Mark recent objects the interpreter doesn't know about yet. */
1632 mark (car (S_SINK));
1633 /* Mark any older stuff above nested C calls */
1634 mark (SCHEME_V->c_nest);
1635
1636 /* mark variables a, b */
1637 mark (a);
1638 mark (b);
1639
1640 /* garbage collect */
1641 clrmark (NIL);
1642 SCHEME_V->fcells = 0;
1643 SCHEME_V->free_cell = NIL;
1644
1645 /* free-list is kept sorted by address so as to maintain consecutive
1646 ranges, if possible, for use with vectors. Here we scan the cells
1647 (which are also kept sorted by address) downwards to build the
1648 free-list in sorted order.
1649 */
1650 for (i = SCHEME_V->last_cell_seg; i >= 0; i--)
1651 {
1652 p = SCHEME_V->cell_seg[i] + SCHEME_V->cell_segsize [i];
1653
1654 while (--p >= SCHEME_V->cell_seg[i])
1655 {
1656 if (is_mark (p))
1657 clrmark (p);
1658 else
1659 {
1660 /* reclaim cell */
1661 if (typeflag (p) != T_PAIR)
1662 {
1663 finalize_cell (SCHEME_A_ p);
1664 set_typeflag (p, T_PAIR);
1665 set_car (p, NIL);
1666 }
1667
1668 ++SCHEME_V->fcells;
1669 set_cdr (p, SCHEME_V->free_cell);
1670 SCHEME_V->free_cell = p;
1671 }
1672 }
1673 }
1674
1675 if (SCHEME_V->gc_verbose)
1676 {
1677 xwrstr ("done: "); xwrnum (SCHEME_V->fcells); xwrstr (" cells were recovered.\n");
1678 }
1679 }
1680
1681 static void
1682 finalize_cell (SCHEME_P_ pointer a)
1683 {
1684 /* TODO, fast bitmap check? */
1685 if (is_string (a))
1686 free (strvalue (a));
1687 else if (is_vector (a))
1688 free (vecvalue (a));
1689 #if USE_PORTS
1690 else if (is_port (a))
1691 {
1692 if (a->object.port->kind & port_file && a->object.port->rep.stdio.closeit)
1693 port_close (SCHEME_A_ a, port_input | port_output);
1694
1695 free (a->object.port);
1696 }
1697 #endif
1698 }
1699
1700 /* ========== Routines for Reading ========== */
1701
1702 static int
1703 file_push (SCHEME_P_ const char *fname)
1704 {
1705 #if USE_PORTS
1706 int fin;
1707
1708 if (SCHEME_V->file_i == MAXFIL - 1)
1709 return 0;
1710
1711 fin = open (fname, O_RDONLY);
1712
1713 if (fin >= 0)
1714 {
1715 SCHEME_V->file_i++;
1716 SCHEME_V->load_stack[SCHEME_V->file_i].unget = -1;
1717 SCHEME_V->load_stack[SCHEME_V->file_i].kind = port_file | port_input;
1718 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.file = fin;
1719 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.closeit = 1;
1720 SCHEME_V->nesting_stack[SCHEME_V->file_i] = 0;
1721 SCHEME_V->loadport->object.port = SCHEME_V->load_stack + SCHEME_V->file_i;
1722
1723 #if SHOW_ERROR_LINE
1724 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line = 0;
1725
1726 if (fname)
1727 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.filename = store_string (SCHEME_A_ strlen (fname), fname, 0);
1728 #endif
1729 }
1730
1731 return fin >= 0;
1732
1733 #else
1734 return 1;
1735 #endif
1736 }
1737
1738 static void
1739 file_pop (SCHEME_P)
1740 {
1741 if (SCHEME_V->file_i != 0)
1742 {
1743 SCHEME_V->nesting = SCHEME_V->nesting_stack[SCHEME_V->file_i];
1744 #if USE_PORTS
1745 port_close (SCHEME_A_ SCHEME_V->loadport, port_input);
1746 #endif
1747 SCHEME_V->file_i--;
1748 SCHEME_V->loadport->object.port = SCHEME_V->load_stack + SCHEME_V->file_i;
1749 }
1750 }
1751
1752 static int
1753 file_interactive (SCHEME_P)
1754 {
1755 #if USE_PORTS
1756 return SCHEME_V->file_i == 0
1757 && SCHEME_V->load_stack[0].rep.stdio.file == STDIN_FILENO
1758 && (SCHEME_V->inport->object.port->kind & port_file);
1759 #else
1760 return 0;
1761 #endif
1762 }
1763
1764 #if USE_PORTS
1765 static port *
1766 port_rep_from_filename (SCHEME_P_ const char *fn, int prop)
1767 {
1768 int fd;
1769 int flags;
1770 char *rw;
1771 port *pt;
1772
1773 if (prop == (port_input | port_output))
1774 flags = O_RDWR | O_APPEND | O_CREAT;
1775 else if (prop == port_output)
1776 flags = O_WRONLY | O_TRUNC | O_CREAT;
1777 else
1778 flags = O_RDONLY;
1779
1780 fd = open (fn, flags, 0666);
1781
1782 if (fd < 0)
1783 return 0;
1784
1785 pt = port_rep_from_file (SCHEME_A_ fd, prop);
1786 pt->rep.stdio.closeit = 1;
1787
1788 # if SHOW_ERROR_LINE
1789 if (fn)
1790 pt->rep.stdio.filename = store_string (SCHEME_A_ strlen (fn), fn, 0);
1791
1792 pt->rep.stdio.curr_line = 0;
1793 # endif
1794
1795 return pt;
1796 }
1797
1798 static pointer
1799 port_from_filename (SCHEME_P_ const char *fn, int prop)
1800 {
1801 port *pt = port_rep_from_filename (SCHEME_A_ fn, prop);
1802
1803 if (!pt && USE_ERROR_CHECKING)
1804 return NIL;
1805
1806 return mk_port (SCHEME_A_ pt);
1807 }
1808
1809 static port *
1810 port_rep_from_file (SCHEME_P_ int f, int prop)
1811 {
1812 port *pt = malloc (sizeof *pt);
1813
1814 if (!pt && USE_ERROR_CHECKING)
1815 return NULL;
1816
1817 pt->unget = -1;
1818 pt->kind = port_file | prop;
1819 pt->rep.stdio.file = f;
1820 pt->rep.stdio.closeit = 0;
1821 return pt;
1822 }
1823
1824 static pointer
1825 port_from_file (SCHEME_P_ int f, int prop)
1826 {
1827 port *pt = port_rep_from_file (SCHEME_A_ f, prop);
1828
1829 if (!pt && USE_ERROR_CHECKING)
1830 return NIL;
1831
1832 return mk_port (SCHEME_A_ pt);
1833 }
1834
1835 static port *
1836 port_rep_from_string (SCHEME_P_ char *start, char *past_the_end, int prop)
1837 {
1838 port *pt = malloc (sizeof (port));
1839
1840 if (!pt && USE_ERROR_CHECKING)
1841 return 0;
1842
1843 pt->unget = -1;
1844 pt->kind = port_string | prop;
1845 pt->rep.string.start = start;
1846 pt->rep.string.curr = start;
1847 pt->rep.string.past_the_end = past_the_end;
1848 return pt;
1849 }
1850
1851 static pointer
1852 port_from_string (SCHEME_P_ char *start, char *past_the_end, int prop)
1853 {
1854 port *pt = port_rep_from_string (SCHEME_A_ start, past_the_end, prop);
1855
1856 if (!pt && USE_ERROR_CHECKING)
1857 return NIL;
1858
1859 return mk_port (SCHEME_A_ pt);
1860 }
1861
1862 # define BLOCK_SIZE 256
1863
1864 static port *
1865 port_rep_from_scratch (SCHEME_P)
1866 {
1867 char *start;
1868 port *pt = malloc (sizeof (port));
1869
1870 if (!pt && USE_ERROR_CHECKING)
1871 return 0;
1872
1873 start = malloc (BLOCK_SIZE);
1874
1875 if (start == 0)
1876 return 0;
1877
1878 memset (start, ' ', BLOCK_SIZE - 1);
1879 start[BLOCK_SIZE - 1] = '\0';
1880 pt->unget = -1;
1881 pt->kind = port_string | port_output | port_srfi6;
1882 pt->rep.string.start = start;
1883 pt->rep.string.curr = start;
1884 pt->rep.string.past_the_end = start + BLOCK_SIZE - 1;
1885 return pt;
1886 }
1887
1888 static pointer
1889 port_from_scratch (SCHEME_P)
1890 {
1891 port *pt = port_rep_from_scratch (SCHEME_A);
1892
1893 if (!pt && USE_ERROR_CHECKING)
1894 return NIL;
1895
1896 return mk_port (SCHEME_A_ pt);
1897 }
1898
1899 static void
1900 port_close (SCHEME_P_ pointer p, int flag)
1901 {
1902 port *pt = p->object.port;
1903
1904 pt->kind &= ~flag;
1905
1906 if ((pt->kind & (port_input | port_output)) == 0)
1907 {
1908 if (pt->kind & port_file)
1909 {
1910
1911 # if SHOW_ERROR_LINE
1912 /* Cleanup is here so (close-*-port) functions could work too */
1913 pt->rep.stdio.curr_line = 0;
1914
1915 if (pt->rep.stdio.filename)
1916 free (pt->rep.stdio.filename);
1917
1918 # endif
1919
1920 close (pt->rep.stdio.file);
1921 }
1922
1923 pt->kind = port_free;
1924 }
1925 }
1926 #endif
1927
1928 /* get new character from input file */
1929 static int
1930 inchar (SCHEME_P)
1931 {
1932 int c;
1933 port *pt;
1934
1935 pt = SCHEME_V->inport->object.port;
1936
1937 if (pt->kind & port_saw_EOF)
1938 return EOF;
1939
1940 c = basic_inchar (pt);
1941
1942 if (c == EOF && SCHEME_V->inport == SCHEME_V->loadport)
1943 {
1944 /* Instead, set port_saw_EOF */
1945 pt->kind |= port_saw_EOF;
1946
1947 /* file_pop(SCHEME_A); */
1948 return EOF;
1949 /* NOTREACHED */
1950 }
1951
1952 return c;
1953 }
1954
1955 static int ungot = -1;
1956
1957 static int
1958 basic_inchar (port *pt)
1959 {
1960 #if USE_PORTS
1961 if (pt->unget != -1)
1962 {
1963 int r = pt->unget;
1964 pt->unget = -1;
1965 return r;
1966 }
1967
1968 if (pt->kind & port_file)
1969 {
1970 char c;
1971
1972 if (!read (pt->rep.stdio.file, &c, 1))
1973 return EOF;
1974
1975 return c;
1976 }
1977 else
1978 {
1979 if (*pt->rep.string.curr == 0 || pt->rep.string.curr == pt->rep.string.past_the_end)
1980 return EOF;
1981 else
1982 return *pt->rep.string.curr++;
1983 }
1984 #else
1985 if (ungot == -1)
1986 {
1987 char c;
1988 if (!read (0, &c, 1))
1989 return EOF;
1990
1991 ungot = c;
1992 }
1993
1994 {
1995 int r = ungot;
1996 ungot = -1;
1997 return r;
1998 }
1999 #endif
2000 }
2001
2002 /* back character to input buffer */
2003 static void
2004 backchar (SCHEME_P_ int c)
2005 {
2006 #if USE_PORTS
2007 port *pt;
2008
2009 if (c == EOF)
2010 return;
2011
2012 pt = SCHEME_V->inport->object.port;
2013 pt->unget = c;
2014 #else
2015 if (c == EOF)
2016 return;
2017
2018 ungot = c;
2019 #endif
2020 }
2021
2022 #if USE_PORTS
2023 static int
2024 realloc_port_string (SCHEME_P_ port *p)
2025 {
2026 char *start = p->rep.string.start;
2027 size_t new_size = p->rep.string.past_the_end - start + 1 + BLOCK_SIZE;
2028 char *str = malloc (new_size);
2029
2030 if (str)
2031 {
2032 memset (str, ' ', new_size - 1);
2033 str[new_size - 1] = '\0';
2034 strcpy (str, start);
2035 p->rep.string.start = str;
2036 p->rep.string.past_the_end = str + new_size - 1;
2037 p->rep.string.curr -= start - str;
2038 free (start);
2039 return 1;
2040 }
2041 else
2042 return 0;
2043 }
2044 #endif
2045
2046 INTERFACE void
2047 putstr (SCHEME_P_ const char *s)
2048 {
2049 #if USE_PORTS
2050 port *pt = SCHEME_V->outport->object.port;
2051
2052 if (pt->kind & port_file)
2053 write (pt->rep.stdio.file, s, strlen (s));
2054 else
2055 for (; *s; s++)
2056 if (pt->rep.string.curr != pt->rep.string.past_the_end)
2057 *pt->rep.string.curr++ = *s;
2058 else if (pt->kind & port_srfi6 && realloc_port_string (SCHEME_A_ pt))
2059 *pt->rep.string.curr++ = *s;
2060
2061 #else
2062 xwrstr (s);
2063 #endif
2064 }
2065
2066 static void
2067 putchars (SCHEME_P_ const char *s, int len)
2068 {
2069 #if USE_PORTS
2070 port *pt = SCHEME_V->outport->object.port;
2071
2072 if (pt->kind & port_file)
2073 write (pt->rep.stdio.file, s, len);
2074 else
2075 {
2076 for (; len; len--)
2077 {
2078 if (pt->rep.string.curr != pt->rep.string.past_the_end)
2079 *pt->rep.string.curr++ = *s++;
2080 else if (pt->kind & port_srfi6 && realloc_port_string (SCHEME_A_ pt))
2081 *pt->rep.string.curr++ = *s++;
2082 }
2083 }
2084
2085 #else
2086 write (1, s, len);
2087 #endif
2088 }
2089
2090 INTERFACE void
2091 putcharacter (SCHEME_P_ int c)
2092 {
2093 #if USE_PORTS
2094 port *pt = SCHEME_V->outport->object.port;
2095
2096 if (pt->kind & port_file)
2097 {
2098 char cc = c;
2099 write (pt->rep.stdio.file, &cc, 1);
2100 }
2101 else
2102 {
2103 if (pt->rep.string.curr != pt->rep.string.past_the_end)
2104 *pt->rep.string.curr++ = c;
2105 else if (pt->kind & port_srfi6 && realloc_port_string (SCHEME_A_ pt))
2106 *pt->rep.string.curr++ = c;
2107 }
2108
2109 #else
2110 char cc = c;
2111 write (1, &c, 1);
2112 #endif
2113 }
2114
2115 /* read characters up to delimiter, but cater to character constants */
2116 static char *
2117 readstr_upto (SCHEME_P_ int skip, const char *delim)
2118 {
2119 char *p = SCHEME_V->strbuff + skip;
2120
2121 while ((p - SCHEME_V->strbuff < sizeof (SCHEME_V->strbuff)) && !is_one_of (delim, (*p++ = inchar (SCHEME_A))));
2122
2123 if (p == SCHEME_V->strbuff + 2 && p[-2] == '\\')
2124 *p = 0;
2125 else
2126 {
2127 backchar (SCHEME_A_ p[-1]);
2128 *--p = '\0';
2129 }
2130
2131 return SCHEME_V->strbuff;
2132 }
2133
2134 /* read string expression "xxx...xxx" */
2135 static pointer
2136 readstrexp (SCHEME_P_ char delim)
2137 {
2138 char *p = SCHEME_V->strbuff;
2139 int c;
2140 int c1 = 0;
2141 enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state = st_ok;
2142
2143 for (;;)
2144 {
2145 c = inchar (SCHEME_A);
2146
2147 if (c == EOF || p - SCHEME_V->strbuff > sizeof (SCHEME_V->strbuff) - 1)
2148 return S_F;
2149
2150 switch (state)
2151 {
2152 case st_ok:
2153 if (ecb_expect_false (c == delim))
2154 return mk_counted_string (SCHEME_A_ SCHEME_V->strbuff, p - SCHEME_V->strbuff);
2155
2156 if (ecb_expect_false (c == '\\'))
2157 state = st_bsl;
2158 else
2159 *p++ = c;
2160
2161 break;
2162
2163 case st_bsl:
2164 switch (c)
2165 {
2166 case '0':
2167 case '1':
2168 case '2':
2169 case '3':
2170 case '4':
2171 case '5':
2172 case '6':
2173 case '7':
2174 state = st_oct1;
2175 c1 = c - '0';
2176 break;
2177
2178 case 'x':
2179 case 'X':
2180 state = st_x1;
2181 c1 = 0;
2182 break;
2183
2184 case 'n':
2185 *p++ = '\n';
2186 state = st_ok;
2187 break;
2188
2189 case 't':
2190 *p++ = '\t';
2191 state = st_ok;
2192 break;
2193
2194 case 'r':
2195 *p++ = '\r';
2196 state = st_ok;
2197 break;
2198
2199 default:
2200 *p++ = c;
2201 state = st_ok;
2202 break;
2203 }
2204
2205 break;
2206
2207 case st_x1:
2208 case st_x2:
2209 c = tolower (c);
2210
2211 if (c >= '0' && c <= '9')
2212 c1 = (c1 << 4) + c - '0';
2213 else if (c >= 'a' && c <= 'f')
2214 c1 = (c1 << 4) + c - 'a' + 10;
2215 else
2216 return S_F;
2217
2218 if (state == st_x1)
2219 state = st_x2;
2220 else
2221 {
2222 *p++ = c1;
2223 state = st_ok;
2224 }
2225
2226 break;
2227
2228 case st_oct1:
2229 case st_oct2:
2230 if (c < '0' || c > '7')
2231 {
2232 *p++ = c1;
2233 backchar (SCHEME_A_ c);
2234 state = st_ok;
2235 }
2236 else
2237 {
2238 if (state == st_oct2 && c1 >= ' ')
2239 return S_F;
2240
2241 c1 = (c1 << 3) + (c - '0');
2242
2243 if (state == st_oct1)
2244 state = st_oct2;
2245 else
2246 {
2247 *p++ = c1;
2248 state = st_ok;
2249 }
2250 }
2251
2252 break;
2253 }
2254 }
2255 }
2256
2257 /* check c is in chars */
2258 ecb_inline int
2259 is_one_of (const char *s, int c)
2260 {
2261 if (c == EOF)
2262 return 1;
2263
2264 return !!strchr (s, c);
2265 }
2266
2267 /* skip white characters */
2268 ecb_inline int
2269 skipspace (SCHEME_P)
2270 {
2271 int c, curr_line = 0;
2272
2273 do
2274 {
2275 c = inchar (SCHEME_A);
2276 #if SHOW_ERROR_LINE
2277 if (c == '\n')
2278 curr_line++;
2279 #endif
2280 }
2281 while (c == ' ' || c == '\n' || c == '\r' || c == '\t');
2282
2283 /* record it */
2284 #if SHOW_ERROR_LINE
2285 if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
2286 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line += curr_line;
2287 #endif
2288
2289 if (c != EOF)
2290 {
2291 backchar (SCHEME_A_ c);
2292 return 1;
2293 }
2294 else
2295 return EOF;
2296 }
2297
2298 /* get token */
2299 static int
2300 token (SCHEME_P)
2301 {
2302 int c = skipspace (SCHEME_A);
2303
2304 if (c == EOF)
2305 return TOK_EOF;
2306
2307 switch ((c = inchar (SCHEME_A)))
2308 {
2309 case EOF:
2310 return TOK_EOF;
2311
2312 case '(':
2313 return TOK_LPAREN;
2314
2315 case ')':
2316 return TOK_RPAREN;
2317
2318 case '.':
2319 c = inchar (SCHEME_A);
2320
2321 if (is_one_of (" \n\t", c))
2322 return TOK_DOT;
2323 else
2324 {
2325 backchar (SCHEME_A_ c);
2326 return TOK_DOTATOM;
2327 }
2328
2329 case '|':
2330 return TOK_STRATOM;
2331
2332 case '\'':
2333 return TOK_QUOTE;
2334
2335 case ';':
2336 while ((c = inchar (SCHEME_A)) != '\n' && c != EOF)
2337 ;
2338
2339 #if SHOW_ERROR_LINE
2340
2341 if (c == '\n' && SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
2342 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
2343
2344 #endif
2345
2346 if (c == EOF)
2347 return TOK_EOF;
2348 else
2349 return token (SCHEME_A);
2350
2351 case '"':
2352 return TOK_DQUOTE;
2353
2354 case BACKQUOTE:
2355 return TOK_BQUOTE;
2356
2357 case ',':
2358 if ((c = inchar (SCHEME_A)) == '@')
2359 return TOK_ATMARK;
2360 else
2361 {
2362 backchar (SCHEME_A_ c);
2363 return TOK_COMMA;
2364 }
2365
2366 case '#':
2367 c = inchar (SCHEME_A);
2368
2369 if (c == '(')
2370 return TOK_VEC;
2371 else if (c == '!')
2372 {
2373 while ((c = inchar (SCHEME_A)) != '\n' && c != EOF)
2374 ;
2375
2376 #if SHOW_ERROR_LINE
2377
2378 if (c == '\n' && SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
2379 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
2380
2381 #endif
2382
2383 if (c == EOF)
2384 return TOK_EOF;
2385 else
2386 return token (SCHEME_A);
2387 }
2388 else
2389 {
2390 backchar (SCHEME_A_ c);
2391
2392 if (is_one_of (" tfodxb\\", c))
2393 return TOK_SHARP_CONST;
2394 else
2395 return TOK_SHARP;
2396 }
2397
2398 default:
2399 backchar (SCHEME_A_ c);
2400 return TOK_ATOM;
2401 }
2402 }
2403
2404 /* ========== Routines for Printing ========== */
2405 #define ok_abbrev(x) (is_pair(x) && cdr(x) == NIL)
2406
2407 static void
2408 printslashstring (SCHEME_P_ char *p, int len)
2409 {
2410 int i;
2411 unsigned char *s = (unsigned char *) p;
2412
2413 putcharacter (SCHEME_A_ '"');
2414
2415 for (i = 0; i < len; i++)
2416 {
2417 if (*s == 0xff || *s == '"' || *s < ' ' || *s == '\\')
2418 {
2419 putcharacter (SCHEME_A_ '\\');
2420
2421 switch (*s)
2422 {
2423 case '"':
2424 putcharacter (SCHEME_A_ '"');
2425 break;
2426
2427 case '\n':
2428 putcharacter (SCHEME_A_ 'n');
2429 break;
2430
2431 case '\t':
2432 putcharacter (SCHEME_A_ 't');
2433 break;
2434
2435 case '\r':
2436 putcharacter (SCHEME_A_ 'r');
2437 break;
2438
2439 case '\\':
2440 putcharacter (SCHEME_A_ '\\');
2441 break;
2442
2443 default:
2444 {
2445 int d = *s / 16;
2446
2447 putcharacter (SCHEME_A_ 'x');
2448
2449 if (d < 10)
2450 putcharacter (SCHEME_A_ d + '0');
2451 else
2452 putcharacter (SCHEME_A_ d - 10 + 'A');
2453
2454 d = *s % 16;
2455
2456 if (d < 10)
2457 putcharacter (SCHEME_A_ d + '0');
2458 else
2459 putcharacter (SCHEME_A_ d - 10 + 'A');
2460 }
2461 }
2462 }
2463 else
2464 putcharacter (SCHEME_A_ * s);
2465
2466 s++;
2467 }
2468
2469 putcharacter (SCHEME_A_ '"');
2470 }
2471
2472
2473 /* print atoms */
2474 static void
2475 printatom (SCHEME_P_ pointer l, int f)
2476 {
2477 char *p;
2478 int len;
2479
2480 atom2str (SCHEME_A_ l, f, &p, &len);
2481 putchars (SCHEME_A_ p, len);
2482 }
2483
2484
2485 /* Uses internal buffer unless string pointer is already available */
2486 static void
2487 atom2str (SCHEME_P_ pointer l, int f, char **pp, int *plen)
2488 {
2489 char *p;
2490
2491 if (l == NIL)
2492 p = "()";
2493 else if (l == S_T)
2494 p = "#t";
2495 else if (l == S_F)
2496 p = "#f";
2497 else if (l == S_EOF)
2498 p = "#<EOF>";
2499 else if (is_port (l))
2500 p = "#<PORT>";
2501 else if (is_number (l))
2502 {
2503 p = SCHEME_V->strbuff;
2504
2505 if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */
2506 {
2507 if (is_integer (l))
2508 xnum (p, ivalue_unchecked (l));
2509 #if USE_REAL
2510 else
2511 {
2512 snprintf (p, STRBUFFSIZE, "%.10g", rvalue_unchecked (l));
2513 /* r5rs says there must be a '.' (unless 'e'?) */
2514 f = strcspn (p, ".e");
2515
2516 if (p[f] == 0)
2517 {
2518 p[f] = '.'; /* not found, so add '.0' at the end */
2519 p[f + 1] = '0';
2520 p[f + 2] = 0;
2521 }
2522 }
2523 #endif
2524 }
2525 else
2526 {
2527 long v = ivalue (l);
2528
2529 if (f == 16)
2530 xbase (p, v, 16);
2531 else if (f == 8)
2532 xbase (p, v, 8);
2533 else if (f == 2)
2534 {
2535 unsigned long b = (v < 0) ? -v : v;
2536
2537 p = &p[STRBUFFSIZE - 1];
2538 *p = 0;
2539
2540 do
2541 {
2542 *--p = (b & 1) ? '1' : '0';
2543 b >>= 1;
2544 }
2545 while (b != 0);
2546
2547 if (v < 0)
2548 *--p = '-';
2549 }
2550 }
2551 }
2552 else if (is_string (l))
2553 {
2554 if (!f)
2555 p = strvalue (l);
2556 else /* Hack, uses the fact that printing is needed */
2557 {
2558 *pp = SCHEME_V->strbuff;
2559 *plen = 0;
2560 printslashstring (SCHEME_A_ strvalue (l), strlength (l));
2561 return;
2562 }
2563 }
2564 else if (is_character (l))
2565 {
2566 int c = charvalue (l);
2567
2568 p = SCHEME_V->strbuff;
2569
2570 if (!f)
2571 {
2572 p[0] = c;
2573 p[1] = 0;
2574 }
2575 else
2576 {
2577 switch (c)
2578 {
2579 case ' ':
2580 p ="#\\space";
2581 break;
2582
2583 case '\n':
2584 p ="#\\newline";
2585 break;
2586
2587 case '\r':
2588 p ="#\\return";
2589 break;
2590
2591 case '\t':
2592 p ="#\\tab";
2593 break;
2594
2595 default:
2596 #if USE_ASCII_NAMES
2597 if (c == 127)
2598 {
2599 strcpy (p, "#\\del");
2600 break;
2601 }
2602 else if (c < 32)
2603 {
2604 strcpy (p, "#\\");
2605 strcpy (p + 2, charnames[c]);
2606 break;
2607 }
2608
2609 #else
2610
2611 if (c < 32)
2612 {
2613 strcpy (p, "#\\x");
2614 xbase (p + 3, c, 16);
2615 break;
2616 }
2617
2618 #endif
2619 strcpy (p, "#\\%");
2620 p[2] = c;
2621 break;
2622 }
2623 }
2624 }
2625 else if (is_symbol (l))
2626 p = symname (l);
2627 else if (is_proc (l))
2628 {
2629 #if USE_PRINTF
2630 p = SCHEME_V->strbuff;
2631 snprintf (p, STRBUFFSIZE, "#<%s PROCEDURE %ld>", procname (l), procnum (l));
2632 #else
2633 p = "#<PROCEDURE>";
2634 #endif
2635 }
2636 else if (is_macro (l))
2637 p = "#<MACRO>";
2638 else if (is_closure (l))
2639 p = "#<CLOSURE>";
2640 else if (is_promise (l))
2641 p = "#<PROMISE>";
2642 else if (is_foreign (l))
2643 {
2644 #if USE_PRINTF
2645 p = SCHEME_V->strbuff;
2646 snprintf (p, STRBUFFSIZE, "#<FOREIGN PROCEDURE %ld>", procnum (l));
2647 #else
2648 p = "#<FOREIGN PROCEDURE>";
2649 #endif
2650 }
2651 else if (is_continuation (l))
2652 p = "#<CONTINUATION>";
2653 else
2654 p = "#<ERROR>";
2655
2656 *pp = p;
2657 *plen = strlen (p);
2658 }
2659
2660 /* ========== Routines for Evaluation Cycle ========== */
2661
2662 /* make closure. c is code. e is environment */
2663 static pointer
2664 mk_closure (SCHEME_P_ pointer c, pointer e)
2665 {
2666 pointer x = get_cell (SCHEME_A_ c, e);
2667
2668 set_typeflag (x, T_CLOSURE);
2669 set_car (x, c);
2670 set_cdr (x, e);
2671 return x;
2672 }
2673
2674 /* make continuation. */
2675 static pointer
2676 mk_continuation (SCHEME_P_ pointer d)
2677 {
2678 pointer x = get_cell (SCHEME_A_ NIL, d);
2679
2680 set_typeflag (x, T_CONTINUATION);
2681 set_cont_dump (x, d);
2682 return x;
2683 }
2684
2685 static pointer
2686 list_star (SCHEME_P_ pointer d)
2687 {
2688 pointer p, q;
2689
2690 if (cdr (d) == NIL)
2691 return car (d);
2692
2693 p = cons (car (d), cdr (d));
2694 q = p;
2695
2696 while (cdr (cdr (p)) != NIL)
2697 {
2698 d = cons (car (p), cdr (p));
2699
2700 if (cdr (cdr (p)) != NIL)
2701 p = cdr (d);
2702 }
2703
2704 set_cdr (p, car (cdr (p)));
2705 return q;
2706 }
2707
2708 /* reverse list -- produce new list */
2709 static pointer
2710 reverse (SCHEME_P_ pointer a)
2711 {
2712 /* a must be checked by gc */
2713 pointer p = NIL;
2714
2715 for (; is_pair (a); a = cdr (a))
2716 p = cons (car (a), p);
2717
2718 return p;
2719 }
2720
2721 /* reverse list --- in-place */
2722 static pointer
2723 reverse_in_place (SCHEME_P_ pointer term, pointer list)
2724 {
2725 pointer result = term;
2726 pointer p = list;
2727
2728 while (p != NIL)
2729 {
2730 pointer q = cdr (p);
2731 set_cdr (p, result);
2732 result = p;
2733 p = q;
2734 }
2735
2736 return result;
2737 }
2738
2739 /* append list -- produce new list (in reverse order) */
2740 static pointer
2741 revappend (SCHEME_P_ pointer a, pointer b)
2742 {
2743 pointer result = a;
2744 pointer p = b;
2745
2746 while (is_pair (p))
2747 {
2748 result = cons (car (p), result);
2749 p = cdr (p);
2750 }
2751
2752 if (p == NIL)
2753 return result;
2754
2755 return S_F; /* signal an error */
2756 }
2757
2758 /* equivalence of atoms */
2759 int
2760 eqv (pointer a, pointer b)
2761 {
2762 if (is_string (a))
2763 {
2764 if (is_string (b))
2765 return strvalue (a) == strvalue (b);
2766 else
2767 return 0;
2768 }
2769 else if (is_number (a))
2770 {
2771 if (is_number (b))
2772 return num_cmp (nvalue (a), nvalue (b)) == 0;
2773
2774 return 0;
2775 }
2776 else if (is_character (a))
2777 {
2778 if (is_character (b))
2779 return charvalue (a) == charvalue (b);
2780 else
2781 return 0;
2782 }
2783 else if (is_port (a))
2784 {
2785 if (is_port (b))
2786 return a == b;
2787 else
2788 return 0;
2789 }
2790 else if (is_proc (a))
2791 {
2792 if (is_proc (b))
2793 return procnum (a) == procnum (b);
2794 else
2795 return 0;
2796 }
2797 else
2798 return a == b;
2799 }
2800
2801 /* true or false value macro */
2802
2803 /* () is #t in R5RS */
2804 #define is_true(p) ((p) != S_F)
2805 #define is_false(p) ((p) == S_F)
2806
2807 /* ========== Environment implementation ========== */
2808
2809 #ifndef USE_ALIST_ENV
2810
2811 /*
2812 * In this implementation, each frame of the environment may be
2813 * a hash table: a vector of alists hashed by variable name.
2814 * In practice, we use a vector only for the initial frame;
2815 * subsequent frames are too small and transient for the lookup
2816 * speed to out-weigh the cost of making a new vector.
2817 */
2818
2819 static void
2820 new_frame_in_env (SCHEME_P_ pointer old_env)
2821 {
2822 pointer new_frame;
2823
2824 /* The interaction-environment has about 300 variables in it. */
2825 if (old_env == NIL)
2826 new_frame = mk_vector (SCHEME_A_ 461);
2827 else
2828 new_frame = NIL;
2829
2830 SCHEME_V->envir = immutable_cons (new_frame, old_env);
2831 setenvironment (SCHEME_V->envir);
2832 }
2833
2834 static uint32_t
2835 sym_hash (pointer sym, uint32_t size)
2836 {
2837 uintptr_t ptr = (uintptr_t)sym;
2838
2839 #if 0
2840 /* table size is prime, so why mix */
2841 ptr += ptr >> 32;
2842 ptr += ptr >> 16;
2843 ptr += ptr >> 8;
2844 #endif
2845
2846 return ptr % size;
2847 }
2848
2849 ecb_inline void
2850 new_slot_spec_in_env (SCHEME_P_ pointer env, pointer variable, pointer value)
2851 {
2852 pointer slot = immutable_cons (variable, value);
2853
2854 if (is_vector (car (env)))
2855 {
2856 int location = sym_hash (variable, veclength (car (env)));
2857 vector_set (car (env), location, immutable_cons (slot, vector_get (car (env), location)));
2858 }
2859 else
2860 set_car (env, immutable_cons (slot, car (env)));
2861 }
2862
2863 static pointer
2864 find_slot_in_env (SCHEME_P_ pointer env, pointer hdl, int all)
2865 {
2866 pointer x, y;
2867
2868 for (x = env; x != NIL; x = cdr (x))
2869 {
2870 if (is_vector (car (x)))
2871 {
2872 int location = sym_hash (hdl, veclength (car (x)));
2873 y = vector_get (car (x), location);
2874 }
2875 else
2876 y = car (x);
2877
2878 for (; y != NIL; y = cdr (y))
2879 if (caar (y) == hdl)
2880 break;
2881
2882 if (y != NIL)
2883 return car (y);
2884
2885 if (!all)
2886 break;
2887 }
2888
2889 return NIL;
2890 }
2891
2892 #else /* USE_ALIST_ENV */
2893
2894 ecb_inline void
2895 new_frame_in_env (SCHEME_P_ pointer old_env)
2896 {
2897 SCHEME_V->envir = immutable_cons (NIL, old_env);
2898 setenvironment (SCHEME_V->envir);
2899 }
2900
2901 ecb_inline void
2902 new_slot_spec_in_env (SCHEME_P_ pointer env, pointer variable, pointer value)
2903 {
2904 set_car (env, immutable_cons (immutable_cons (variable, value), car (env)));
2905 }
2906
2907 static pointer
2908 find_slot_in_env (SCHEME_P_ pointer env, pointer hdl, int all)
2909 {
2910 pointer x, y;
2911
2912 for (x = env; x != NIL; x = cdr (x))
2913 {
2914 for (y = car (x); y != NIL; y = cdr (y))
2915 if (caar (y) == hdl)
2916 break;
2917
2918 if (y != NIL)
2919 return car (y);
2920 break;
2921
2922 if (!all)
2923 break;
2924 }
2925
2926 return NIL;
2927 }
2928
2929 #endif /* USE_ALIST_ENV else */
2930
2931 ecb_inline void
2932 new_slot_in_env (SCHEME_P_ pointer variable, pointer value)
2933 {
2934 new_slot_spec_in_env (SCHEME_A_ SCHEME_V->envir, variable, value);
2935 }
2936
2937 ecb_inline void
2938 set_slot_in_env (SCHEME_P_ pointer slot, pointer value)
2939 {
2940 set_cdr (slot, value);
2941 }
2942
2943 ecb_inline pointer
2944 slot_value_in_env (pointer slot)
2945 {
2946 return cdr (slot);
2947 }
2948
2949 /* ========== Evaluation Cycle ========== */
2950
2951 static int
2952 xError_1 (SCHEME_P_ const char *s, pointer a)
2953 {
2954 #if USE_ERROR_HOOK
2955 pointer x;
2956 pointer hdl = SCHEME_V->ERROR_HOOK;
2957 #endif
2958
2959 #if USE_PRINTF
2960 #if SHOW_ERROR_LINE
2961 char sbuf[STRBUFFSIZE];
2962
2963 /* make sure error is not in REPL */
2964 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)
2965 {
2966 int ln = SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line;
2967 const char *fname = SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.filename;
2968
2969 /* should never happen */
2970 if (!fname)
2971 fname = "<unknown>";
2972
2973 /* we started from 0 */
2974 ln++;
2975 snprintf (sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s);
2976
2977 s = sbuf;
2978 }
2979 #endif
2980 #endif
2981
2982 #if USE_ERROR_HOOK
2983 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, hdl, 1);
2984
2985 if (x != NIL)
2986 {
2987 pointer code = a
2988 ? cons (cons (SCHEME_V->QUOTE, cons (a, NIL)), NIL)
2989 : NIL;
2990
2991 code = cons (mk_string (SCHEME_A_ s), code);
2992 setimmutable (car (code));
2993 SCHEME_V->code = cons (slot_value_in_env (x), code);
2994 SCHEME_V->op = OP_EVAL;
2995
2996 return 0;
2997 }
2998 #endif
2999
3000 if (a)
3001 SCHEME_V->args = cons (a, NIL);
3002 else
3003 SCHEME_V->args = NIL;
3004
3005 SCHEME_V->args = cons (mk_string (SCHEME_A_ s), SCHEME_V->args);
3006 setimmutable (car (SCHEME_V->args));
3007 SCHEME_V->op = OP_ERR0;
3008
3009 return 0;
3010 }
3011
3012 #define Error_1(s, a) return xError_1(SCHEME_A_ USE_ERROR_CHECKING ? s : "", a)
3013 #define Error_0(s) Error_1 (s, 0)
3014
3015 /* Too small to turn into function */
3016 #define BEGIN do {
3017 #define END } while (0)
3018 #define s_goto(a) BEGIN \
3019 SCHEME_V->op = a; \
3020 return 0; END
3021
3022 #define s_return(a) return xs_return (SCHEME_A_ a)
3023
3024 #ifndef USE_SCHEME_STACK
3025
3026 /* this structure holds all the interpreter's registers */
3027 struct dump_stack_frame
3028 {
3029 enum scheme_opcodes op;
3030 pointer args;
3031 pointer envir;
3032 pointer code;
3033 };
3034
3035 # define STACK_GROWTH 3
3036
3037 static void
3038 s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3039 {
3040 int nframes = (uintptr_t)SCHEME_V->dump;
3041 struct dump_stack_frame *next_frame;
3042
3043 /* enough room for the next frame? */
3044 if (nframes >= SCHEME_V->dump_size)
3045 {
3046 SCHEME_V->dump_size += STACK_GROWTH;
3047 SCHEME_V->dump_base = realloc (SCHEME_V->dump_base, sizeof (struct dump_stack_frame) * SCHEME_V->dump_size);
3048 }
3049
3050 next_frame = SCHEME_V->dump_base + nframes;
3051
3052 next_frame->op = op;
3053 next_frame->args = args;
3054 next_frame->envir = SCHEME_V->envir;
3055 next_frame->code = code;
3056
3057 SCHEME_V->dump = (pointer)(uintptr_t)(nframes + 1);
3058 }
3059
3060 static int
3061 xs_return (SCHEME_P_ pointer a)
3062 {
3063 int nframes = (uintptr_t)SCHEME_V->dump;
3064 struct dump_stack_frame *frame;
3065
3066 SCHEME_V->value = a;
3067
3068 if (nframes <= 0)
3069 return -1;
3070
3071 frame = &SCHEME_V->dump_base[--nframes];
3072 SCHEME_V->op = frame->op;
3073 SCHEME_V->args = frame->args;
3074 SCHEME_V->envir = frame->envir;
3075 SCHEME_V->code = frame->code;
3076 SCHEME_V->dump = (pointer)(uintptr_t)nframes;
3077
3078 return 0;
3079 }
3080
3081 ecb_inline void
3082 dump_stack_reset (SCHEME_P)
3083 {
3084 /* in this implementation, SCHEME_V->dump is the number of frames on the stack */
3085 SCHEME_V->dump = (pointer)+0;
3086 }
3087
3088 ecb_inline void
3089 dump_stack_initialize (SCHEME_P)
3090 {
3091 SCHEME_V->dump_size = 0;
3092 SCHEME_V->dump_base = 0;
3093 dump_stack_reset (SCHEME_A);
3094 }
3095
3096 static void
3097 dump_stack_free (SCHEME_P)
3098 {
3099 free (SCHEME_V->dump_base);
3100 SCHEME_V->dump_base = 0;
3101 SCHEME_V->dump = (pointer)0;
3102 SCHEME_V->dump_size = 0;
3103 }
3104
3105 static void
3106 dump_stack_mark (SCHEME_P)
3107 {
3108 int nframes = (uintptr_t)SCHEME_V->dump;
3109 int i;
3110
3111 for (i = 0; i < nframes; i++)
3112 {
3113 struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3114
3115 mark (frame->args);
3116 mark (frame->envir);
3117 mark (frame->code);
3118 }
3119 }
3120
3121 static pointer
3122 ss_get_cont (SCHEME_P)
3123 {
3124 int nframes = (uintptr_t)SCHEME_V->dump;
3125 int i;
3126
3127 pointer cont = NIL;
3128
3129 for (i = nframes; i--; )
3130 {
3131 struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3132
3133 cont = cons (mk_integer (SCHEME_A_ frame->op),
3134 cons (frame->args,
3135 cons (frame->envir,
3136 cons (frame->code,
3137 cont))));
3138 }
3139
3140 return cont;
3141 }
3142
3143 static void
3144 ss_set_cont (SCHEME_P_ pointer cont)
3145 {
3146 int i = 0;
3147 struct dump_stack_frame *frame = SCHEME_V->dump_base;
3148
3149 while (cont != NIL)
3150 {
3151 frame->op = ivalue_unchecked (car (cont)); cont = cdr (cont);
3152 frame->args = car (cont) ; cont = cdr (cont);
3153 frame->envir = car (cont) ; cont = cdr (cont);
3154 frame->code = car (cont) ; cont = cdr (cont);
3155
3156 ++frame;
3157 ++i;
3158 }
3159
3160 SCHEME_V->dump = (pointer)(uintptr_t)i;
3161 }
3162
3163 #else
3164
3165 ecb_inline void
3166 dump_stack_reset (SCHEME_P)
3167 {
3168 SCHEME_V->dump = NIL;
3169 }
3170
3171 ecb_inline void
3172 dump_stack_initialize (SCHEME_P)
3173 {
3174 dump_stack_reset (SCHEME_A);
3175 }
3176
3177 static void
3178 dump_stack_free (SCHEME_P)
3179 {
3180 SCHEME_V->dump = NIL;
3181 }
3182
3183 static int
3184 xs_return (SCHEME_P_ pointer a)
3185 {
3186 pointer dump = SCHEME_V->dump;
3187
3188 SCHEME_V->value = a;
3189
3190 if (dump == NIL)
3191 return -1;
3192
3193 SCHEME_V->op = ivalue_unchecked (car (dump)); dump = cdr (dump);
3194 SCHEME_V->args = car (dump) ; dump = cdr (dump);
3195 SCHEME_V->envir = car (dump) ; dump = cdr (dump);
3196 SCHEME_V->code = car (dump) ; dump = cdr (dump);
3197
3198 SCHEME_V->dump = dump;
3199
3200 return 0;
3201 }
3202
3203 static void
3204 s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3205 {
3206 SCHEME_V->dump = cons (mk_integer (SCHEME_A_ op),
3207 cons (args,
3208 cons (SCHEME_V->envir,
3209 cons (code,
3210 SCHEME_V->dump))));
3211 }
3212
3213 static void
3214 dump_stack_mark (SCHEME_P)
3215 {
3216 mark (SCHEME_V->dump);
3217 }
3218
3219 static pointer
3220 ss_get_cont (SCHEME_P)
3221 {
3222 return SCHEME_V->dump;
3223 }
3224
3225 static void
3226 ss_set_cont (SCHEME_P_ pointer cont)
3227 {
3228 SCHEME_V->dump = cont;
3229 }
3230
3231 #endif
3232
3233 #define s_retbool(tf) s_return ((tf) ? S_T : S_F)
3234
3235 static int
3236 opexe_0 (SCHEME_P_ enum scheme_opcodes op)
3237 {
3238 pointer args = SCHEME_V->args;
3239 pointer x, y;
3240
3241 switch (op)
3242 {
3243 case OP_LOAD: /* load */
3244 if (file_interactive (SCHEME_A))
3245 {
3246 xwrstr ("Loading "); xwrstr (strvalue (car (args))); xwrstr ("\n");
3247 //D fprintf (SCHEME_V->outport->object.port->rep.stdio.file, "Loading %s\n", strvalue (car (args)));
3248 }
3249
3250 if (!file_push (SCHEME_A_ strvalue (car (args))))
3251 Error_1 ("unable to open", car (args));
3252 else
3253 {
3254 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
3255 s_goto (OP_T0LVL);
3256 }
3257
3258 case OP_T0LVL: /* top level */
3259
3260 /* If we reached the end of file, this loop is done. */
3261 if (SCHEME_V->loadport->object.port->kind & port_saw_EOF)
3262 {
3263 if (SCHEME_V->file_i == 0)
3264 {
3265 SCHEME_V->args = NIL;
3266 s_goto (OP_QUIT);
3267 }
3268 else
3269 {
3270 file_pop (SCHEME_A);
3271 s_return (SCHEME_V->value);
3272 }
3273
3274 /* NOTREACHED */
3275 }
3276
3277 /* If interactive, be nice to user. */
3278 if (file_interactive (SCHEME_A))
3279 {
3280 SCHEME_V->envir = SCHEME_V->global_env;
3281 dump_stack_reset (SCHEME_A);
3282 putstr (SCHEME_A_ "\n");
3283 putstr (SCHEME_A_ prompt);
3284 }
3285
3286 /* Set up another iteration of REPL */
3287 SCHEME_V->nesting = 0;
3288 SCHEME_V->save_inport = SCHEME_V->inport;
3289 SCHEME_V->inport = SCHEME_V->loadport;
3290 s_save (SCHEME_A_ OP_T0LVL, NIL, NIL);
3291 s_save (SCHEME_A_ OP_VALUEPRINT, NIL, NIL);
3292 s_save (SCHEME_A_ OP_T1LVL, NIL, NIL);
3293 s_goto (OP_READ_INTERNAL);
3294
3295 case OP_T1LVL: /* top level */
3296 SCHEME_V->code = SCHEME_V->value;
3297 SCHEME_V->inport = SCHEME_V->save_inport;
3298 s_goto (OP_EVAL);
3299
3300 case OP_READ_INTERNAL: /* internal read */
3301 SCHEME_V->tok = token (SCHEME_A);
3302
3303 if (SCHEME_V->tok == TOK_EOF)
3304 s_return (S_EOF);
3305
3306 s_goto (OP_RDSEXPR);
3307
3308 case OP_GENSYM:
3309 s_return (gensym (SCHEME_A));
3310
3311 case OP_VALUEPRINT: /* print evaluation result */
3312
3313 /* OP_VALUEPRINT is always pushed, because when changing from
3314 non-interactive to interactive mode, it needs to be
3315 already on the stack */
3316 #if USE_TRACING
3317 if (SCHEME_V->tracing)
3318 putstr (SCHEME_A_ "\nGives: ");
3319 #endif
3320
3321 if (file_interactive (SCHEME_A))
3322 {
3323 SCHEME_V->print_flag = 1;
3324 SCHEME_V->args = SCHEME_V->value;
3325 s_goto (OP_P0LIST);
3326 }
3327 else
3328 s_return (SCHEME_V->value);
3329
3330 case OP_EVAL: /* main part of evaluation */
3331 #if USE_TRACING
3332 if (SCHEME_V->tracing)
3333 {
3334 /*s_save(SCHEME_A_ OP_VALUEPRINT,NIL,NIL); */
3335 s_save (SCHEME_A_ OP_REAL_EVAL, args, SCHEME_V->code);
3336 SCHEME_V->args = SCHEME_V->code;
3337 putstr (SCHEME_A_ "\nEval: ");
3338 s_goto (OP_P0LIST);
3339 }
3340
3341 /* fall through */
3342
3343 case OP_REAL_EVAL:
3344 #endif
3345 if (is_symbol (SCHEME_V->code)) /* symbol */
3346 {
3347 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3348
3349 if (x != NIL)
3350 s_return (slot_value_in_env (x));
3351 else
3352 Error_1 ("eval: unbound variable:", SCHEME_V->code);
3353 }
3354 else if (is_pair (SCHEME_V->code))
3355 {
3356 x = car (SCHEME_V->code);
3357
3358 if (is_syntax (x)) /* SYNTAX */
3359 {
3360 SCHEME_V->code = cdr (SCHEME_V->code);
3361 s_goto (syntaxnum (x));
3362 }
3363 else /* first, eval top element and eval arguments */
3364 {
3365 s_save (SCHEME_A_ OP_E0ARGS, NIL, SCHEME_V->code);
3366 /* If no macros => s_save(SCHEME_A_ OP_E1ARGS, NIL, cdr(SCHEME_V->code)); */
3367 SCHEME_V->code = x;
3368 s_goto (OP_EVAL);
3369 }
3370 }
3371 else
3372 s_return (SCHEME_V->code);
3373
3374 case OP_E0ARGS: /* eval arguments */
3375 if (is_macro (SCHEME_V->value)) /* macro expansion */
3376 {
3377 s_save (SCHEME_A_ OP_DOMACRO, NIL, NIL);
3378 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3379 SCHEME_V->code = SCHEME_V->value;
3380 s_goto (OP_APPLY);
3381 }
3382 else
3383 {
3384 SCHEME_V->code = cdr (SCHEME_V->code);
3385 s_goto (OP_E1ARGS);
3386 }
3387
3388 case OP_E1ARGS: /* eval arguments */
3389 args = cons (SCHEME_V->value, args);
3390
3391 if (is_pair (SCHEME_V->code)) /* continue */
3392 {
3393 s_save (SCHEME_A_ OP_E1ARGS, args, cdr (SCHEME_V->code));
3394 SCHEME_V->code = car (SCHEME_V->code);
3395 SCHEME_V->args = NIL;
3396 s_goto (OP_EVAL);
3397 }
3398 else /* end */
3399 {
3400 args = reverse_in_place (SCHEME_A_ NIL, args);
3401 SCHEME_V->code = car (args);
3402 SCHEME_V->args = cdr (args);
3403 s_goto (OP_APPLY);
3404 }
3405
3406 #if USE_TRACING
3407
3408 case OP_TRACING:
3409 {
3410 int tr = SCHEME_V->tracing;
3411
3412 SCHEME_V->tracing = ivalue_unchecked (car (args));
3413 s_return (mk_integer (SCHEME_A_ tr));
3414 }
3415
3416 #endif
3417
3418 case OP_APPLY: /* apply 'code' to 'args' */
3419 #if USE_TRACING
3420 if (SCHEME_V->tracing)
3421 {
3422 s_save (SCHEME_A_ OP_REAL_APPLY, args, SCHEME_V->code);
3423 SCHEME_V->print_flag = 1;
3424 /* args=cons(SCHEME_V->code,args); */
3425 putstr (SCHEME_A_ "\nApply to: ");
3426 s_goto (OP_P0LIST);
3427 }
3428
3429 /* fall through */
3430
3431 case OP_REAL_APPLY:
3432 #endif
3433 if (is_proc (SCHEME_V->code))
3434 s_goto (procnum (SCHEME_V->code)); /* PROCEDURE */
3435 else if (is_foreign (SCHEME_V->code))
3436 {
3437 /* Keep nested calls from GC'ing the arglist */
3438 push_recent_alloc (SCHEME_A_ args, NIL);
3439 x = SCHEME_V->code->object.ff (SCHEME_A_ args);
3440
3441 s_return (x);
3442 }
3443 else if (is_closure (SCHEME_V->code) || is_macro (SCHEME_V->code) || is_promise (SCHEME_V->code)) /* CLOSURE */
3444 {
3445 /* Should not accept promise */
3446 /* make environment */
3447 new_frame_in_env (SCHEME_A_ closure_env (SCHEME_V->code));
3448
3449 for (x = car (closure_code (SCHEME_V->code)), y = args; is_pair (x); x = cdr (x), y = cdr (y))
3450 {
3451 if (y == NIL)
3452 Error_0 ("not enough arguments");
3453 else
3454 new_slot_in_env (SCHEME_A_ car (x), car (y));
3455 }
3456
3457 if (x == NIL)
3458 {
3459 /*--
3460 * if (y != NIL) {
3461 * Error_0("too many arguments");
3462 * }
3463 */
3464 }
3465 else if (is_symbol (x))
3466 new_slot_in_env (SCHEME_A_ x, y);
3467 else
3468 Error_1 ("syntax error in closure: not a symbol:", x);
3469
3470 SCHEME_V->code = cdr (closure_code (SCHEME_V->code));
3471 SCHEME_V->args = NIL;
3472 s_goto (OP_BEGIN);
3473 }
3474 else if (is_continuation (SCHEME_V->code)) /* CONTINUATION */
3475 {
3476 ss_set_cont (SCHEME_A_ cont_dump (SCHEME_V->code));
3477 s_return (args != NIL ? car (args) : NIL);
3478 }
3479 else
3480 Error_0 ("illegal function");
3481
3482 case OP_DOMACRO: /* do macro */
3483 SCHEME_V->code = SCHEME_V->value;
3484 s_goto (OP_EVAL);
3485
3486 #if 1
3487
3488 case OP_LAMBDA: /* lambda */
3489 /* If the hook is defined, apply it to SCHEME_V->code, otherwise
3490 set SCHEME_V->value fall thru */
3491 {
3492 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->COMPILE_HOOK, 1);
3493
3494 if (f != NIL)
3495 {
3496 s_save (SCHEME_A_ OP_LAMBDA1, args, SCHEME_V->code);
3497 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3498 SCHEME_V->code = slot_value_in_env (f);
3499 s_goto (OP_APPLY);
3500 }
3501
3502 SCHEME_V->value = SCHEME_V->code;
3503 /* Fallthru */
3504 }
3505
3506 case OP_LAMBDA1:
3507 s_return (mk_closure (SCHEME_A_ SCHEME_V->value, SCHEME_V->envir));
3508
3509 #else
3510
3511 case OP_LAMBDA: /* lambda */
3512 s_return (mk_closure (SCHEME_A_ SCHEME_V->code, SCHEME_V->envir));
3513
3514 #endif
3515
3516 case OP_MKCLOSURE: /* make-closure */
3517 x = car (args);
3518
3519 if (car (x) == SCHEME_V->LAMBDA)
3520 x = cdr (x);
3521
3522 if (cdr (args) == NIL)
3523 y = SCHEME_V->envir;
3524 else
3525 y = cadr (args);
3526
3527 s_return (mk_closure (SCHEME_A_ x, y));
3528
3529 case OP_QUOTE: /* quote */
3530 s_return (car (SCHEME_V->code));
3531
3532 case OP_DEF0: /* define */
3533 if (is_immutable (car (SCHEME_V->code)))
3534 Error_1 ("define: unable to alter immutable", car (SCHEME_V->code));
3535
3536 if (is_pair (car (SCHEME_V->code)))
3537 {
3538 x = caar (SCHEME_V->code);
3539 SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3540 }
3541 else
3542 {
3543 x = car (SCHEME_V->code);
3544 SCHEME_V->code = cadr (SCHEME_V->code);
3545 }
3546
3547 if (!is_symbol (x))
3548 Error_0 ("variable is not a symbol");
3549
3550 s_save (SCHEME_A_ OP_DEF1, NIL, x);
3551 s_goto (OP_EVAL);
3552
3553 case OP_DEF1: /* define */
3554 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3555
3556 if (x != NIL)
3557 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3558 else
3559 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3560
3561 s_return (SCHEME_V->code);
3562
3563
3564 case OP_DEFP: /* defined? */
3565 x = SCHEME_V->envir;
3566
3567 if (cdr (args) != NIL)
3568 x = cadr (args);
3569
3570 s_retbool (find_slot_in_env (SCHEME_A_ x, car (args), 1) != NIL);
3571
3572 case OP_SET0: /* set! */
3573 if (is_immutable (car (SCHEME_V->code)))
3574 Error_1 ("set!: unable to alter immutable variable", car (SCHEME_V->code));
3575
3576 s_save (SCHEME_A_ OP_SET1, NIL, car (SCHEME_V->code));
3577 SCHEME_V->code = cadr (SCHEME_V->code);
3578 s_goto (OP_EVAL);
3579
3580 case OP_SET1: /* set! */
3581 y = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3582
3583 if (y != NIL)
3584 {
3585 set_slot_in_env (SCHEME_A_ y, SCHEME_V->value);
3586 s_return (SCHEME_V->value);
3587 }
3588 else
3589 Error_1 ("set!: unbound variable:", SCHEME_V->code);
3590
3591
3592 case OP_BEGIN: /* begin */
3593 if (!is_pair (SCHEME_V->code))
3594 s_return (SCHEME_V->code);
3595
3596 if (cdr (SCHEME_V->code) != NIL)
3597 s_save (SCHEME_A_ OP_BEGIN, NIL, cdr (SCHEME_V->code));
3598
3599 SCHEME_V->code = car (SCHEME_V->code);
3600 s_goto (OP_EVAL);
3601
3602 case OP_IF0: /* if */
3603 s_save (SCHEME_A_ OP_IF1, NIL, cdr (SCHEME_V->code));
3604 SCHEME_V->code = car (SCHEME_V->code);
3605 s_goto (OP_EVAL);
3606
3607 case OP_IF1: /* if */
3608 if (is_true (SCHEME_V->value))
3609 SCHEME_V->code = car (SCHEME_V->code);
3610 else
3611 SCHEME_V->code = cadr (SCHEME_V->code); /* (if #f 1) ==> () because * car(NIL) = NIL */
3612 s_goto (OP_EVAL);
3613
3614 case OP_LET0: /* let */
3615 SCHEME_V->args = NIL;
3616 SCHEME_V->value = SCHEME_V->code;
3617 SCHEME_V->code = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code);
3618 s_goto (OP_LET1);
3619
3620 case OP_LET1: /* let (calculate parameters) */
3621 args = cons (SCHEME_V->value, args);
3622
3623 if (is_pair (SCHEME_V->code)) /* continue */
3624 {
3625 if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3626 Error_1 ("Bad syntax of binding spec in let :", car (SCHEME_V->code));
3627
3628 s_save (SCHEME_A_ OP_LET1, args, cdr (SCHEME_V->code));
3629 SCHEME_V->code = cadar (SCHEME_V->code);
3630 SCHEME_V->args = NIL;
3631 s_goto (OP_EVAL);
3632 }
3633 else /* end */
3634 {
3635 args = reverse_in_place (SCHEME_A_ NIL, args);
3636 SCHEME_V->code = car (args);
3637 SCHEME_V->args = cdr (args);
3638 s_goto (OP_LET2);
3639 }
3640
3641 case OP_LET2: /* let */
3642 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3643
3644 for (x = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code), y = args;
3645 y != NIL; x = cdr (x), y = cdr (y))
3646 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3647
3648 if (is_symbol (car (SCHEME_V->code))) /* named let */
3649 {
3650 for (x = cadr (SCHEME_V->code), args = NIL; x != NIL; x = cdr (x))
3651 {
3652 if (!is_pair (x))
3653 Error_1 ("Bad syntax of binding in let :", x);
3654
3655 if (!is_list (SCHEME_A_ car (x)))
3656 Error_1 ("Bad syntax of binding in let :", car (x));
3657
3658 args = cons (caar (x), args);
3659 }
3660
3661 x = mk_closure (SCHEME_A_ cons (reverse_in_place (SCHEME_A_ NIL, args), cddr (SCHEME_V->code)),
3662 SCHEME_V->envir);
3663 new_slot_in_env (SCHEME_A_ car (SCHEME_V->code), x);
3664 SCHEME_V->code = cddr (SCHEME_V->code);
3665 }
3666 else
3667 {
3668 SCHEME_V->code = cdr (SCHEME_V->code);
3669 }
3670
3671 SCHEME_V->args = NIL;
3672 s_goto (OP_BEGIN);
3673
3674 case OP_LET0AST: /* let* */
3675 if (car (SCHEME_V->code) == NIL)
3676 {
3677 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3678 SCHEME_V->code = cdr (SCHEME_V->code);
3679 s_goto (OP_BEGIN);
3680 }
3681
3682 if (!is_pair (car (SCHEME_V->code)) || !is_pair (caar (SCHEME_V->code)) || !is_pair (cdaar (SCHEME_V->code)))
3683 Error_1 ("Bad syntax of binding spec in let* :", car (SCHEME_V->code));
3684
3685 s_save (SCHEME_A_ OP_LET1AST, cdr (SCHEME_V->code), car (SCHEME_V->code));
3686 SCHEME_V->code = car (cdaar (SCHEME_V->code));
3687 s_goto (OP_EVAL);
3688
3689 case OP_LET1AST: /* let* (make new frame) */
3690 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3691 s_goto (OP_LET2AST);
3692
3693 case OP_LET2AST: /* let* (calculate parameters) */
3694 new_slot_in_env (SCHEME_A_ caar (SCHEME_V->code), SCHEME_V->value);
3695 SCHEME_V->code = cdr (SCHEME_V->code);
3696
3697 if (is_pair (SCHEME_V->code)) /* continue */
3698 {
3699 s_save (SCHEME_A_ OP_LET2AST, args, SCHEME_V->code);
3700 SCHEME_V->code = cadar (SCHEME_V->code);
3701 SCHEME_V->args = NIL;
3702 s_goto (OP_EVAL);
3703 }
3704 else /* end */
3705 {
3706 SCHEME_V->code = args;
3707 SCHEME_V->args = NIL;
3708 s_goto (OP_BEGIN);
3709 }
3710
3711 case OP_LET0REC: /* letrec */
3712 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3713 SCHEME_V->args = NIL;
3714 SCHEME_V->value = SCHEME_V->code;
3715 SCHEME_V->code = car (SCHEME_V->code);
3716 s_goto (OP_LET1REC);
3717
3718 case OP_LET1REC: /* letrec (calculate parameters) */
3719 args = cons (SCHEME_V->value, args);
3720
3721 if (is_pair (SCHEME_V->code)) /* continue */
3722 {
3723 if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3724 Error_1 ("Bad syntax of binding spec in letrec :", car (SCHEME_V->code));
3725
3726 s_save (SCHEME_A_ OP_LET1REC, args, cdr (SCHEME_V->code));
3727 SCHEME_V->code = cadar (SCHEME_V->code);
3728 SCHEME_V->args = NIL;
3729 s_goto (OP_EVAL);
3730 }
3731 else /* end */
3732 {
3733 args = reverse_in_place (SCHEME_A_ NIL, args);
3734 SCHEME_V->code = car (args);
3735 SCHEME_V->args = cdr (args);
3736 s_goto (OP_LET2REC);
3737 }
3738
3739 case OP_LET2REC: /* letrec */
3740 for (x = car (SCHEME_V->code), y = args; y != NIL; x = cdr (x), y = cdr (y))
3741 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3742
3743 SCHEME_V->code = cdr (SCHEME_V->code);
3744 SCHEME_V->args = NIL;
3745 s_goto (OP_BEGIN);
3746
3747 case OP_COND0: /* cond */
3748 if (!is_pair (SCHEME_V->code))
3749 Error_0 ("syntax error in cond");
3750
3751 s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3752 SCHEME_V->code = caar (SCHEME_V->code);
3753 s_goto (OP_EVAL);
3754
3755 case OP_COND1: /* cond */
3756 if (is_true (SCHEME_V->value))
3757 {
3758 if ((SCHEME_V->code = cdar (SCHEME_V->code)) == NIL)
3759 s_return (SCHEME_V->value);
3760
3761 if (car (SCHEME_V->code) == SCHEME_V->FEED_TO)
3762 {
3763 if (!is_pair (cdr (SCHEME_V->code)))
3764 Error_0 ("syntax error in cond");
3765
3766 x = cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL));
3767 SCHEME_V->code = cons (cadr (SCHEME_V->code), cons (x, NIL));
3768 s_goto (OP_EVAL);
3769 }
3770
3771 s_goto (OP_BEGIN);
3772 }
3773 else
3774 {
3775 if ((SCHEME_V->code = cdr (SCHEME_V->code)) == NIL)
3776 s_return (NIL);
3777 else
3778 {
3779 s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3780 SCHEME_V->code = caar (SCHEME_V->code);
3781 s_goto (OP_EVAL);
3782 }
3783 }
3784
3785 case OP_DELAY: /* delay */
3786 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3787 set_typeflag (x, T_PROMISE);
3788 s_return (x);
3789
3790 case OP_AND0: /* and */
3791 if (SCHEME_V->code == NIL)
3792 s_return (S_T);
3793
3794 s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3795 SCHEME_V->code = car (SCHEME_V->code);
3796 s_goto (OP_EVAL);
3797
3798 case OP_AND1: /* and */
3799 if (is_false (SCHEME_V->value))
3800 s_return (SCHEME_V->value);
3801 else if (SCHEME_V->code == NIL)
3802 s_return (SCHEME_V->value);
3803 else
3804 {
3805 s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3806 SCHEME_V->code = car (SCHEME_V->code);
3807 s_goto (OP_EVAL);
3808 }
3809
3810 case OP_OR0: /* or */
3811 if (SCHEME_V->code == NIL)
3812 s_return (S_F);
3813
3814 s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3815 SCHEME_V->code = car (SCHEME_V->code);
3816 s_goto (OP_EVAL);
3817
3818 case OP_OR1: /* or */
3819 if (is_true (SCHEME_V->value))
3820 s_return (SCHEME_V->value);
3821 else if (SCHEME_V->code == NIL)
3822 s_return (SCHEME_V->value);
3823 else
3824 {
3825 s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3826 SCHEME_V->code = car (SCHEME_V->code);
3827 s_goto (OP_EVAL);
3828 }
3829
3830 case OP_C0STREAM: /* cons-stream */
3831 s_save (SCHEME_A_ OP_C1STREAM, NIL, cdr (SCHEME_V->code));
3832 SCHEME_V->code = car (SCHEME_V->code);
3833 s_goto (OP_EVAL);
3834
3835 case OP_C1STREAM: /* cons-stream */
3836 SCHEME_V->args = SCHEME_V->value; /* save SCHEME_V->value to register args for gc */
3837 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3838 set_typeflag (x, T_PROMISE);
3839 s_return (cons (args, x));
3840
3841 case OP_MACRO0: /* macro */
3842 if (is_pair (car (SCHEME_V->code)))
3843 {
3844 x = caar (SCHEME_V->code);
3845 SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3846 }
3847 else
3848 {
3849 x = car (SCHEME_V->code);
3850 SCHEME_V->code = cadr (SCHEME_V->code);
3851 }
3852
3853 if (!is_symbol (x))
3854 Error_0 ("variable is not a symbol");
3855
3856 s_save (SCHEME_A_ OP_MACRO1, NIL, x);
3857 s_goto (OP_EVAL);
3858
3859 case OP_MACRO1: /* macro */
3860 set_typeflag (SCHEME_V->value, T_MACRO);
3861 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3862
3863 if (x != NIL)
3864 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3865 else
3866 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3867
3868 s_return (SCHEME_V->code);
3869
3870 case OP_CASE0: /* case */
3871 s_save (SCHEME_A_ OP_CASE1, NIL, cdr (SCHEME_V->code));
3872 SCHEME_V->code = car (SCHEME_V->code);
3873 s_goto (OP_EVAL);
3874
3875 case OP_CASE1: /* case */
3876 for (x = SCHEME_V->code; x != NIL; x = cdr (x))
3877 {
3878 if (!is_pair (y = caar (x)))
3879 break;
3880
3881 for (; y != NIL; y = cdr (y))
3882 if (eqv (car (y), SCHEME_V->value))
3883 break;
3884
3885 if (y != NIL)
3886 break;
3887 }
3888
3889 if (x != NIL)
3890 {
3891 if (is_pair (caar (x)))
3892 {
3893 SCHEME_V->code = cdar (x);
3894 s_goto (OP_BEGIN);
3895 }
3896 else /* else */
3897 {
3898 s_save (SCHEME_A_ OP_CASE2, NIL, cdar (x));
3899 SCHEME_V->code = caar (x);
3900 s_goto (OP_EVAL);
3901 }
3902 }
3903 else
3904 s_return (NIL);
3905
3906 case OP_CASE2: /* case */
3907 if (is_true (SCHEME_V->value))
3908 s_goto (OP_BEGIN);
3909 else
3910 s_return (NIL);
3911
3912 case OP_PAPPLY: /* apply */
3913 SCHEME_V->code = car (args);
3914 SCHEME_V->args = list_star (SCHEME_A_ cdr (args));
3915 /*SCHEME_V->args = cadr(args); */
3916 s_goto (OP_APPLY);
3917
3918 case OP_PEVAL: /* eval */
3919 if (cdr (args) != NIL)
3920 SCHEME_V->envir = cadr (args);
3921
3922 SCHEME_V->code = car (args);
3923 s_goto (OP_EVAL);
3924
3925 case OP_CONTINUATION: /* call-with-current-continuation */
3926 SCHEME_V->code = car (args);
3927 SCHEME_V->args = cons (mk_continuation (SCHEME_A_ ss_get_cont (SCHEME_A)), NIL);
3928 s_goto (OP_APPLY);
3929 }
3930
3931 if (USE_ERROR_CHECKING) abort ();
3932 }
3933
3934 static int
3935 opexe_1 (SCHEME_P_ enum scheme_opcodes op)
3936 {
3937 pointer args = SCHEME_V->args;
3938 pointer x = car (args);
3939 num v;
3940
3941 switch (op)
3942 {
3943 #if USE_MATH
3944 case OP_INEX2EX: /* inexact->exact */
3945 {
3946 if (is_integer (x))
3947 s_return (x);
3948
3949 RVALUE r = rvalue_unchecked (x);
3950
3951 if (r == (RVALUE)(IVALUE)r)
3952 s_return (mk_integer (SCHEME_A_ rvalue_unchecked (x)));
3953 else
3954 Error_1 ("inexact->exact: not integral:", x);
3955 }
3956
3957 case OP_EXP: s_return (mk_real (SCHEME_A_ exp (rvalue (x))));
3958 case OP_LOG: s_return (mk_real (SCHEME_A_ log (rvalue (x))));
3959 case OP_SIN: s_return (mk_real (SCHEME_A_ sin (rvalue (x))));
3960 case OP_COS: s_return (mk_real (SCHEME_A_ cos (rvalue (x))));
3961 case OP_TAN: s_return (mk_real (SCHEME_A_ tan (rvalue (x))));
3962 case OP_ASIN: s_return (mk_real (SCHEME_A_ asin (rvalue (x))));
3963 case OP_ACOS: s_return (mk_real (SCHEME_A_ acos (rvalue (x))));
3964
3965 case OP_ATAN:
3966 if (cdr (args) == NIL)
3967 s_return (mk_real (SCHEME_A_ atan (rvalue (x))));
3968 else
3969 {
3970 pointer y = cadr (args);
3971 s_return (mk_real (SCHEME_A_ atan2 (rvalue (x), rvalue (y))));
3972 }
3973
3974 case OP_SQRT:
3975 s_return (mk_real (SCHEME_A_ sqrt (rvalue (x))));
3976
3977 case OP_EXPT:
3978 {
3979 RVALUE result;
3980 int real_result = 1;
3981 pointer y = cadr (args);
3982
3983 if (is_integer (x) && is_integer (y))
3984 real_result = 0;
3985
3986 /* This 'if' is an R5RS compatibility fix. */
3987 /* NOTE: Remove this 'if' fix for R6RS. */
3988 if (rvalue (x) == 0 && rvalue (y) < 0)
3989 result = 0;
3990 else
3991 result = pow (rvalue (x), rvalue (y));
3992
3993 /* Before returning integer result make sure we can. */
3994 /* If the test fails, result is too big for integer. */
3995 if (!real_result)
3996 {
3997 long result_as_long = result;
3998
3999 if (result != result_as_long)
4000 real_result = 1;
4001 }
4002
4003 if (real_result)
4004 s_return (mk_real (SCHEME_A_ result));
4005 else
4006 s_return (mk_integer (SCHEME_A_ result));
4007 }
4008
4009 case OP_FLOOR: s_return (mk_real (SCHEME_A_ floor (rvalue (x))));
4010 case OP_CEILING: s_return (mk_real (SCHEME_A_ ceil (rvalue (x))));
4011
4012 case OP_TRUNCATE:
4013 {
4014 RVALUE n = rvalue (x);
4015 s_return (mk_real (SCHEME_A_ n > 0 ? floor (n) : ceil (n)));
4016 }
4017
4018 case OP_ROUND:
4019 if (is_integer (x))
4020 s_return (x);
4021
4022 s_return (mk_real (SCHEME_A_ round_per_R5RS (rvalue (x))));
4023 #endif
4024
4025 case OP_ADD: /* + */
4026 v = num_zero;
4027
4028 for (x = args; x != NIL; x = cdr (x))
4029 v = num_op (NUM_ADD, v, nvalue (car (x)));
4030
4031 s_return (mk_number (SCHEME_A_ v));
4032
4033 case OP_MUL: /* * */
4034 v = num_one;
4035
4036 for (x = args; x != NIL; x = cdr (x))
4037 v = num_op (NUM_MUL, v, nvalue (car (x)));
4038
4039 s_return (mk_number (SCHEME_A_ v));
4040
4041 case OP_SUB: /* - */
4042 if (cdr (args) == NIL)
4043 {
4044 x = args;
4045 v = num_zero;
4046 }
4047 else
4048 {
4049 x = cdr (args);
4050 v = nvalue (car (args));
4051 }
4052
4053 for (; x != NIL; x = cdr (x))
4054 v = num_op (NUM_SUB, v, nvalue (car (x)));
4055
4056 s_return (mk_number (SCHEME_A_ v));
4057
4058 case OP_DIV: /* / */
4059 if (cdr (args) == NIL)
4060 {
4061 x = args;
4062 v = num_one;
4063 }
4064 else
4065 {
4066 x = cdr (args);
4067 v = nvalue (car (args));
4068 }
4069
4070 for (; x != NIL; x = cdr (x))
4071 if (!is_zero_rvalue (rvalue (car (x))))
4072 v = num_div (v, nvalue (car (x)));
4073 else
4074 Error_0 ("/: division by zero");
4075
4076 s_return (mk_number (SCHEME_A_ v));
4077
4078 case OP_INTDIV: /* quotient */
4079 if (cdr (args) == NIL)
4080 {
4081 x = args;
4082 v = num_one;
4083 }
4084 else
4085 {
4086 x = cdr (args);
4087 v = nvalue (car (args));
4088 }
4089
4090 for (; x != NIL; x = cdr (x))
4091 {
4092 if (ivalue (car (x)) != 0)
4093 v = num_op (NUM_INTDIV, v, nvalue (car (x)));
4094 else
4095 Error_0 ("quotient: division by zero");
4096 }
4097
4098 s_return (mk_number (SCHEME_A_ v));
4099
4100 case OP_REM: /* remainder */
4101 v = nvalue (x);
4102
4103 if (ivalue (cadr (args)) != 0)
4104 v = num_rem (v, nvalue (cadr (args)));
4105 else
4106 Error_0 ("remainder: division by zero");
4107
4108 s_return (mk_number (SCHEME_A_ v));
4109
4110 case OP_MOD: /* modulo */
4111 v = nvalue (x);
4112
4113 if (ivalue (cadr (args)) != 0)
4114 v = num_mod (v, nvalue (cadr (args)));
4115 else
4116 Error_0 ("modulo: division by zero");
4117
4118 s_return (mk_number (SCHEME_A_ v));
4119
4120 case OP_CAR: /* car */
4121 s_return (caar (args));
4122
4123 case OP_CDR: /* cdr */
4124 s_return (cdar (args));
4125
4126 case OP_CONS: /* cons */
4127 set_cdr (args, cadr (args));
4128 s_return (args);
4129
4130 case OP_SETCAR: /* set-car! */
4131 if (!is_immutable (x))
4132 {
4133 set_car (x, cadr (args));
4134 s_return (car (args));
4135 }
4136 else
4137 Error_0 ("set-car!: unable to alter immutable pair");
4138
4139 case OP_SETCDR: /* set-cdr! */
4140 if (!is_immutable (x))
4141 {
4142 set_cdr (x, cadr (args));
4143 s_return (car (args));
4144 }
4145 else
4146 Error_0 ("set-cdr!: unable to alter immutable pair");
4147
4148 case OP_CHAR2INT: /* char->integer */
4149 s_return (mk_integer (SCHEME_A_ ivalue_unchecked (x)));
4150
4151 case OP_INT2CHAR: /* integer->char */
4152 s_return (mk_character (SCHEME_A_ ivalue_unchecked (x)));
4153
4154 case OP_CHARUPCASE:
4155 {
4156 unsigned char c = ivalue_unchecked (x);
4157 c = toupper (c);
4158 s_return (mk_character (SCHEME_A_ c));
4159 }
4160
4161 case OP_CHARDNCASE:
4162 {
4163 unsigned char c = ivalue_unchecked (x);
4164 c = tolower (c);
4165 s_return (mk_character (SCHEME_A_ c));
4166 }
4167
4168 case OP_STR2SYM: /* string->symbol */
4169 s_return (mk_symbol (SCHEME_A_ strvalue (x)));
4170
4171 case OP_STR2ATOM: /* string->atom */
4172 {
4173 char *s = strvalue (x);
4174 long pf = 0;
4175
4176 if (cdr (args) != NIL)
4177 {
4178 /* we know cadr(args) is a natural number */
4179 /* see if it is 2, 8, 10, or 16, or error */
4180 pf = ivalue_unchecked (cadr (args));
4181
4182 if (pf == 16 || pf == 10 || pf == 8 || pf == 2)
4183 {
4184 /* base is OK */
4185 }
4186 else
4187 pf = -1;
4188 }
4189
4190 if (pf < 0)
4191 Error_1 ("string->atom: bad base:", cadr (args));
4192 else if (*s == '#') /* no use of base! */
4193 s_return (mk_sharp_const (SCHEME_A_ s + 1));
4194 else
4195 {
4196 if (pf == 0 || pf == 10)
4197 s_return (mk_atom (SCHEME_A_ s));
4198 else
4199 {
4200 char *ep;
4201 long iv = strtol (s, &ep, (int) pf);
4202
4203 if (*ep == 0)
4204 s_return (mk_integer (SCHEME_A_ iv));
4205 else
4206 s_return (S_F);
4207 }
4208 }
4209 }
4210
4211 case OP_SYM2STR: /* symbol->string */
4212 x = mk_string (SCHEME_A_ symname (x));
4213 setimmutable (x);
4214 s_return (x);
4215
4216 case OP_ATOM2STR: /* atom->string */
4217 {
4218 long pf = 0;
4219
4220 if (cdr (args) != NIL)
4221 {
4222 /* we know cadr(args) is a natural number */
4223 /* see if it is 2, 8, 10, or 16, or error */
4224 pf = ivalue_unchecked (cadr (args));
4225
4226 if (is_number (x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2))
4227 {
4228 /* base is OK */
4229 }
4230 else
4231 pf = -1;
4232 }
4233
4234 if (pf < 0)
4235 Error_1 ("atom->string: bad base:", cadr (args));
4236 else if (is_number (x) || is_character (x) || is_string (x) || is_symbol (x))
4237 {
4238 char *p;
4239 int len;
4240
4241 atom2str (SCHEME_A_ x, pf, &p, &len);
4242 s_return (mk_counted_string (SCHEME_A_ p, len));
4243 }
4244 else
4245 Error_1 ("atom->string: not an atom:", x);
4246 }
4247
4248 case OP_MKSTRING: /* make-string */
4249 {
4250 int fill = cdr (args) != NIL ? charvalue (cadr (args)) : ' ';
4251 int len = ivalue_unchecked (x);
4252
4253 s_return (mk_empty_string (SCHEME_A_ len, fill));
4254 }
4255
4256 case OP_STRLEN: /* string-length */
4257 s_return (mk_integer (SCHEME_A_ strlength (x)));
4258
4259 case OP_STRREF: /* string-ref */
4260 {
4261 char *str = strvalue (x);
4262 int index = ivalue_unchecked (cadr (args));
4263
4264 if (index >= strlength (x))
4265 Error_1 ("string-ref: out of bounds:", cadr (args));
4266
4267 s_return (mk_character (SCHEME_A_ ((unsigned char *)str)[index]));
4268 }
4269
4270 case OP_STRSET: /* string-set! */
4271 {
4272 char *str = strvalue (x);
4273 int index = ivalue_unchecked (cadr (args));
4274 int c;
4275
4276 if (is_immutable (x))
4277 Error_1 ("string-set!: unable to alter immutable string:", x);
4278
4279 if (index >= strlength (x))
4280 Error_1 ("string-set!: out of bounds:", cadr (args));
4281
4282 c = charvalue (caddr (args));
4283
4284 str[index] = c;
4285 s_return (car (args));
4286 }
4287
4288 case OP_STRAPPEND: /* string-append */
4289 {
4290 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4291 int len = 0;
4292 pointer newstr;
4293 char *pos;
4294
4295 /* compute needed length for new string */
4296 for (x = args; x != NIL; x = cdr (x))
4297 len += strlength (car (x));
4298
4299 newstr = mk_empty_string (SCHEME_A_ len, ' ');
4300
4301 /* store the contents of the argument strings into the new string */
4302 for (pos = strvalue (newstr), x = args; x != NIL; pos += strlength (car (x)), x = cdr (x))
4303 memcpy (pos, strvalue (car (x)), strlength (car (x)));
4304
4305 s_return (newstr);
4306 }
4307
4308 case OP_SUBSTR: /* substring */
4309 {
4310 char *str = strvalue (x);
4311 int index0 = ivalue_unchecked (cadr (args));
4312 int index1;
4313 int len;
4314
4315 if (index0 > strlength (x))
4316 Error_1 ("substring: start out of bounds:", cadr (args));
4317
4318 if (cddr (args) != NIL)
4319 {
4320 index1 = ivalue_unchecked (caddr (args));
4321
4322 if (index1 > strlength (x) || index1 < index0)
4323 Error_1 ("substring: end out of bounds:", caddr (args));
4324 }
4325 else
4326 index1 = strlength (x);
4327
4328 len = index1 - index0;
4329 x = mk_empty_string (SCHEME_A_ len, ' ');
4330 memcpy (strvalue (x), str + index0, len);
4331 strvalue (x)[len] = 0;
4332
4333 s_return (x);
4334 }
4335
4336 case OP_VECTOR: /* vector */
4337 {
4338 int i;
4339 pointer vec;
4340 int len = list_length (SCHEME_A_ args);
4341
4342 if (len < 0)
4343 Error_1 ("vector: not a proper list:", args);
4344
4345 vec = mk_vector (SCHEME_A_ len);
4346
4347 #if USE_ERROR_CHECKING
4348 if (SCHEME_V->no_memory)
4349 s_return (S_SINK);
4350 #endif
4351
4352 for (x = args, i = 0; is_pair (x); x = cdr (x), i++)
4353 vector_set (vec, i, car (x));
4354
4355 s_return (vec);
4356 }
4357
4358 case OP_MKVECTOR: /* make-vector */
4359 {
4360 pointer fill = NIL;
4361 pointer vec;
4362 int len = ivalue_unchecked (x);
4363
4364 if (cdr (args) != NIL)
4365 fill = cadr (args);
4366
4367 vec = mk_vector (SCHEME_A_ len);
4368
4369 #if USE_ERROR_CHECKING
4370 if (SCHEME_V->no_memory)
4371 s_return (S_SINK);
4372 #endif
4373
4374 if (fill != NIL)
4375 fill_vector (vec, 0, fill);
4376
4377 s_return (vec);
4378 }
4379
4380 case OP_VECLEN: /* vector-length */
4381 s_return (mk_integer (SCHEME_A_ veclength (x)));
4382
4383 case OP_VECREF: /* vector-ref */
4384 {
4385 int index = ivalue_unchecked (cadr (args));
4386
4387 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4388 Error_1 ("vector-ref: out of bounds:", cadr (args));
4389
4390 s_return (vector_get (x, index));
4391 }
4392
4393 case OP_VECSET: /* vector-set! */
4394 {
4395 int index = ivalue_unchecked (cadr (args));
4396
4397 if (is_immutable (x))
4398 Error_1 ("vector-set!: unable to alter immutable vector:", x);
4399
4400 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4401 Error_1 ("vector-set!: out of bounds:", cadr (args));
4402
4403 vector_set (x, index, caddr (args));
4404 s_return (x);
4405 }
4406 }
4407
4408 if (USE_ERROR_CHECKING) abort ();
4409 }
4410
4411 static int
4412 opexe_2 (SCHEME_P_ enum scheme_opcodes op)
4413 {
4414 pointer x = SCHEME_V->args;
4415
4416 for (;;)
4417 {
4418 num v = nvalue (car (x));
4419 x = cdr (x);
4420
4421 if (x == NIL)
4422 break;
4423
4424 int r = num_cmp (v, nvalue (car (x)));
4425
4426 switch (op)
4427 {
4428 case OP_NUMEQ: r = r == 0; break;
4429 case OP_LESS: r = r < 0; break;
4430 case OP_GRE: r = r > 0; break;
4431 case OP_LEQ: r = r <= 0; break;
4432 case OP_GEQ: r = r >= 0; break;
4433 }
4434
4435 if (!r)
4436 s_return (S_F);
4437 }
4438
4439 s_return (S_T);
4440 }
4441
4442 static int
4443 opexe_3 (SCHEME_P_ enum scheme_opcodes op)
4444 {
4445 pointer args = SCHEME_V->args;
4446 pointer a = car (args);
4447 pointer d = cdr (args);
4448 int r;
4449
4450 switch (op)
4451 {
4452 case OP_NOT: /* not */ r = is_false (a) ; break;
4453 case OP_BOOLP: /* boolean? */ r = a == S_F || a == S_T; break;
4454 case OP_EOFOBJP: /* eof-object? */ r = a == S_EOF ; break;
4455 case OP_NULLP: /* null? */ r = a == NIL ; break;
4456 case OP_SYMBOLP: /* symbol? */ r = is_symbol (a) ; break;
4457 case OP_NUMBERP: /* number? */ r = is_number (a) ; break;
4458 case OP_STRINGP: /* string? */ r = is_string (a) ; break;
4459 case OP_INTEGERP: /* integer? */ r = is_integer (a) ; break;
4460 case OP_REALP: /* real? */ r = is_number (a) ; break; /* all numbers are real */
4461 case OP_CHARP: /* char? */ r = is_character (a) ; break;
4462
4463 #if USE_CHAR_CLASSIFIERS
4464 case OP_CHARAP: /* char-alphabetic? */ r = Cisalpha (ivalue_unchecked (a)); break;
4465 case OP_CHARNP: /* char-numeric? */ r = Cisdigit (ivalue_unchecked (a)); break;
4466 case OP_CHARWP: /* char-whitespace? */ r = Cisspace (ivalue_unchecked (a)); break;
4467 case OP_CHARUP: /* char-upper-case? */ r = Cisupper (ivalue_unchecked (a)); break;
4468 case OP_CHARLP: /* char-lower-case? */ r = Cislower (ivalue_unchecked (a)); break;
4469 #endif
4470
4471 #if USE_PORTS
4472 case OP_PORTP: /* port? */ r = is_port (a) ; break;
4473 case OP_INPORTP: /* input-port? */ r = is_inport (a) ; break;
4474 case OP_OUTPORTP: /* output-port? */ r = is_outport (a); break;
4475 #endif
4476
4477 case OP_PROCP: /* procedure? */
4478
4479 /*--
4480 * continuation should be procedure by the example
4481 * (call-with-current-continuation procedure?) ==> #t
4482 * in R^3 report sec. 6.9
4483 */
4484 r = is_proc (a) || is_closure (a) || is_continuation (a) || is_foreign (a);
4485 break;
4486
4487 case OP_PAIRP: /* pair? */ r = is_pair (a) ; break;
4488 case OP_LISTP: /* list? */ r = list_length (SCHEME_A_ a) >= 0; break;
4489 case OP_ENVP: /* environment? */ r = is_environment (a) ; break;
4490 case OP_VECTORP: /* vector? */ r = is_vector (a) ; break;
4491 case OP_EQ: /* eq? */ r = a == cadr (args) ; break;
4492 case OP_EQV: /* eqv? */ r = eqv (a, cadr (args)) ; break;
4493 }
4494
4495 s_retbool (r);
4496 }
4497
4498 static int
4499 opexe_4 (SCHEME_P_ enum scheme_opcodes op)
4500 {
4501 pointer args = SCHEME_V->args;
4502 pointer a = car (args);
4503 pointer x, y;
4504
4505 switch (op)
4506 {
4507 case OP_FORCE: /* force */
4508 SCHEME_V->code = a;
4509
4510 if (is_promise (SCHEME_V->code))
4511 {
4512 /* Should change type to closure here */
4513 s_save (SCHEME_A_ OP_SAVE_FORCED, NIL, SCHEME_V->code);
4514 SCHEME_V->args = NIL;
4515 s_goto (OP_APPLY);
4516 }
4517 else
4518 s_return (SCHEME_V->code);
4519
4520 case OP_SAVE_FORCED: /* Save forced value replacing promise */
4521 memcpy (SCHEME_V->code, SCHEME_V->value, sizeof (struct cell));
4522 s_return (SCHEME_V->value);
4523
4524 #if USE_PORTS
4525
4526 case OP_WRITE: /* write */
4527 case OP_DISPLAY: /* display */
4528 case OP_WRITE_CHAR: /* write-char */
4529 if (is_pair (cdr (SCHEME_V->args)))
4530 {
4531 if (cadr (SCHEME_V->args) != SCHEME_V->outport)
4532 {
4533 x = cons (SCHEME_V->outport, NIL);
4534 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4535 SCHEME_V->outport = cadr (SCHEME_V->args);
4536 }
4537 }
4538
4539 SCHEME_V->args = a;
4540
4541 if (op == OP_WRITE)
4542 SCHEME_V->print_flag = 1;
4543 else
4544 SCHEME_V->print_flag = 0;
4545
4546 s_goto (OP_P0LIST);
4547
4548 case OP_NEWLINE: /* newline */
4549 if (is_pair (args))
4550 {
4551 if (a != SCHEME_V->outport)
4552 {
4553 x = cons (SCHEME_V->outport, NIL);
4554 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4555 SCHEME_V->outport = a;
4556 }
4557 }
4558
4559 putstr (SCHEME_A_ "\n");
4560 s_return (S_T);
4561 #endif
4562
4563 case OP_ERR0: /* error */
4564 SCHEME_V->retcode = -1;
4565
4566 if (!is_string (a))
4567 {
4568 args = cons (mk_string (SCHEME_A_ " -- "), args);
4569 setimmutable (car (args));
4570 }
4571
4572 putstr (SCHEME_A_ "Error: ");
4573 putstr (SCHEME_A_ strvalue (car (args)));
4574 SCHEME_V->args = cdr (args);
4575 s_goto (OP_ERR1);
4576
4577 case OP_ERR1: /* error */
4578 putstr (SCHEME_A_ " ");
4579
4580 if (args != NIL)
4581 {
4582 s_save (SCHEME_A_ OP_ERR1, cdr (args), NIL);
4583 SCHEME_V->args = a;
4584 SCHEME_V->print_flag = 1;
4585 s_goto (OP_P0LIST);
4586 }
4587 else
4588 {
4589 putstr (SCHEME_A_ "\n");
4590
4591 if (SCHEME_V->interactive_repl)
4592 s_goto (OP_T0LVL);
4593 else
4594 return -1;
4595 }
4596
4597 case OP_REVERSE: /* reverse */
4598 s_return (reverse (SCHEME_A_ a));
4599
4600 case OP_LIST_STAR: /* list* */
4601 s_return (list_star (SCHEME_A_ SCHEME_V->args));
4602
4603 case OP_APPEND: /* append */
4604 x = NIL;
4605 y = args;
4606
4607 if (y == x)
4608 s_return (x);
4609
4610 /* cdr() in the while condition is not a typo. If car() */
4611 /* is used (append '() 'a) will return the wrong result. */
4612 while (cdr (y) != NIL)
4613 {
4614 x = revappend (SCHEME_A_ x, car (y));
4615 y = cdr (y);
4616
4617 if (x == S_F)
4618 Error_0 ("non-list argument to append");
4619 }
4620
4621 s_return (reverse_in_place (SCHEME_A_ car (y), x));
4622
4623 #if USE_PLIST
4624
4625 case OP_PUT: /* put */
4626 if (!hasprop (a) || !hasprop (cadr (args)))
4627 Error_0 ("illegal use of put");
4628
4629 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4630 {
4631 if (caar (x) == y)
4632 break;
4633 }
4634
4635 if (x != NIL)
4636 cdar (x) = caddr (args);
4637 else
4638 symprop (a) = cons (cons (y, caddr (args)), symprop (a));
4639
4640 s_return (S_T);
4641
4642 case OP_GET: /* get */
4643 if (!hasprop (a) || !hasprop (cadr (args)))
4644 Error_0 ("illegal use of get");
4645
4646 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4647 if (caar (x) == y)
4648 break;
4649
4650 if (x != NIL)
4651 s_return (cdar (x));
4652 else
4653 s_return (NIL);
4654
4655 #endif /* USE_PLIST */
4656
4657 case OP_QUIT: /* quit */
4658 if (is_pair (args))
4659 SCHEME_V->retcode = ivalue (a);
4660
4661 return -1;
4662
4663 case OP_GC: /* gc */
4664 gc (SCHEME_A_ NIL, NIL);
4665 s_return (S_T);
4666
4667 case OP_GCVERB: /* gc-verbose */
4668 {
4669 int was = SCHEME_V->gc_verbose;
4670
4671 SCHEME_V->gc_verbose = (a != S_F);
4672 s_retbool (was);
4673 }
4674
4675 case OP_NEWSEGMENT: /* new-segment */
4676 if (!is_pair (args) || !is_number (a))
4677 Error_0 ("new-segment: argument must be a number");
4678
4679 alloc_cellseg (SCHEME_A_ ivalue (a));
4680
4681 s_return (S_T);
4682
4683 case OP_OBLIST: /* oblist */
4684 s_return (oblist_all_symbols (SCHEME_A));
4685
4686 #if USE_PORTS
4687
4688 case OP_CURR_INPORT: /* current-input-port */
4689 s_return (SCHEME_V->inport);
4690
4691 case OP_CURR_OUTPORT: /* current-output-port */
4692 s_return (SCHEME_V->outport);
4693
4694 case OP_OPEN_INFILE: /* open-input-file */
4695 case OP_OPEN_OUTFILE: /* open-output-file */
4696 case OP_OPEN_INOUTFILE: /* open-input-output-file */
4697 {
4698 int prop = 0;
4699 pointer p;
4700
4701 switch (op)
4702 {
4703 case OP_OPEN_INFILE:
4704 prop = port_input;
4705 break;
4706
4707 case OP_OPEN_OUTFILE:
4708 prop = port_output;
4709 break;
4710
4711 case OP_OPEN_INOUTFILE:
4712 prop = port_input | port_output;
4713 break;
4714 }
4715
4716 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
4717
4718 s_return (p == NIL ? S_F : p);
4719 }
4720
4721 # if USE_STRING_PORTS
4722
4723 case OP_OPEN_INSTRING: /* open-input-string */
4724 case OP_OPEN_INOUTSTRING: /* open-input-output-string */
4725 {
4726 int prop = 0;
4727 pointer p;
4728
4729 switch (op)
4730 {
4731 case OP_OPEN_INSTRING:
4732 prop = port_input;
4733 break;
4734
4735 case OP_OPEN_INOUTSTRING:
4736 prop = port_input | port_output;
4737 break;
4738 }
4739
4740 p = port_from_string (SCHEME_A_ strvalue (a),
4741 strvalue (a) + strlength (a), prop);
4742
4743 s_return (p == NIL ? S_F : p);
4744 }
4745
4746 case OP_OPEN_OUTSTRING: /* open-output-string */
4747 {
4748 pointer p;
4749
4750 if (a == NIL)
4751 p = port_from_scratch (SCHEME_A);
4752 else
4753 p = port_from_string (SCHEME_A_ strvalue (a),
4754 strvalue (a) + strlength (a), port_output);
4755
4756 s_return (p == NIL ? S_F : p);
4757 }
4758
4759 case OP_GET_OUTSTRING: /* get-output-string */
4760 {
4761 port *p;
4762
4763 if ((p = a->object.port)->kind & port_string)
4764 {
4765 off_t size;
4766 char *str;
4767
4768 size = p->rep.string.curr - p->rep.string.start + 1;
4769 str = malloc (size);
4770
4771 if (str != NULL)
4772 {
4773 pointer s;
4774
4775 memcpy (str, p->rep.string.start, size - 1);
4776 str[size - 1] = '\0';
4777 s = mk_string (SCHEME_A_ str);
4778 free (str);
4779 s_return (s);
4780 }
4781 }
4782
4783 s_return (S_F);
4784 }
4785
4786 # endif
4787
4788 case OP_CLOSE_INPORT: /* close-input-port */
4789 port_close (SCHEME_A_ a, port_input);
4790 s_return (S_T);
4791
4792 case OP_CLOSE_OUTPORT: /* close-output-port */
4793 port_close (SCHEME_A_ a, port_output);
4794 s_return (S_T);
4795 #endif
4796
4797 case OP_INT_ENV: /* interaction-environment */
4798 s_return (SCHEME_V->global_env);
4799
4800 case OP_CURR_ENV: /* current-environment */
4801 s_return (SCHEME_V->envir);
4802
4803 }
4804
4805 if (USE_ERROR_CHECKING) abort ();
4806 }
4807
4808 static int
4809 opexe_5 (SCHEME_P_ enum scheme_opcodes op)
4810 {
4811 pointer args = SCHEME_V->args;
4812 pointer x;
4813
4814 if (SCHEME_V->nesting != 0)
4815 {
4816 int n = SCHEME_V->nesting;
4817
4818 SCHEME_V->nesting = 0;
4819 SCHEME_V->retcode = -1;
4820 Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
4821 }
4822
4823 switch (op)
4824 {
4825 /* ========== reading part ========== */
4826 #if USE_PORTS
4827 case OP_READ:
4828 if (!is_pair (args))
4829 s_goto (OP_READ_INTERNAL);
4830
4831 if (!is_inport (car (args)))
4832 Error_1 ("read: not an input port:", car (args));
4833
4834 if (car (args) == SCHEME_V->inport)
4835 s_goto (OP_READ_INTERNAL);
4836
4837 x = SCHEME_V->inport;
4838 SCHEME_V->inport = car (args);
4839 x = cons (x, NIL);
4840 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4841 s_goto (OP_READ_INTERNAL);
4842
4843 case OP_READ_CHAR: /* read-char */
4844 case OP_PEEK_CHAR: /* peek-char */
4845 {
4846 int c;
4847
4848 if (is_pair (args))
4849 {
4850 if (car (args) != SCHEME_V->inport)
4851 {
4852 x = SCHEME_V->inport;
4853 x = cons (x, NIL);
4854 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4855 SCHEME_V->inport = car (args);
4856 }
4857 }
4858
4859 c = inchar (SCHEME_A);
4860
4861 if (c == EOF)
4862 s_return (S_EOF);
4863
4864 if (SCHEME_V->op == OP_PEEK_CHAR)
4865 backchar (SCHEME_A_ c);
4866
4867 s_return (mk_character (SCHEME_A_ c));
4868 }
4869
4870 case OP_CHAR_READY: /* char-ready? */
4871 {
4872 pointer p = SCHEME_V->inport;
4873 int res;
4874
4875 if (is_pair (args))
4876 p = car (args);
4877
4878 res = p->object.port->kind & port_string;
4879
4880 s_retbool (res);
4881 }
4882
4883 case OP_SET_INPORT: /* set-input-port */
4884 SCHEME_V->inport = car (args);
4885 s_return (SCHEME_V->value);
4886
4887 case OP_SET_OUTPORT: /* set-output-port */
4888 SCHEME_V->outport = car (args);
4889 s_return (SCHEME_V->value);
4890 #endif
4891
4892 case OP_RDSEXPR:
4893 switch (SCHEME_V->tok)
4894 {
4895 case TOK_EOF:
4896 s_return (S_EOF);
4897 /* NOTREACHED */
4898
4899 case TOK_VEC:
4900 s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
4901 /* fall through */
4902
4903 case TOK_LPAREN:
4904 SCHEME_V->tok = token (SCHEME_A);
4905
4906 if (SCHEME_V->tok == TOK_RPAREN)
4907 s_return (NIL);
4908 else if (SCHEME_V->tok == TOK_DOT)
4909 Error_0 ("syntax error: illegal dot expression");
4910 else
4911 {
4912 SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
4913 s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
4914 s_goto (OP_RDSEXPR);
4915 }
4916
4917 case TOK_QUOTE:
4918 s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
4919 SCHEME_V->tok = token (SCHEME_A);
4920 s_goto (OP_RDSEXPR);
4921
4922 case TOK_BQUOTE:
4923 SCHEME_V->tok = token (SCHEME_A);
4924
4925 if (SCHEME_V->tok == TOK_VEC)
4926 {
4927 s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
4928 SCHEME_V->tok = TOK_LPAREN;
4929 s_goto (OP_RDSEXPR);
4930 }
4931 else
4932 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
4933
4934 s_goto (OP_RDSEXPR);
4935
4936 case TOK_COMMA:
4937 s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
4938 SCHEME_V->tok = token (SCHEME_A);
4939 s_goto (OP_RDSEXPR);
4940
4941 case TOK_ATMARK:
4942 s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
4943 SCHEME_V->tok = token (SCHEME_A);
4944 s_goto (OP_RDSEXPR);
4945
4946 case TOK_ATOM:
4947 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS)));
4948
4949 case TOK_DOTATOM:
4950 SCHEME_V->strbuff[0] = '.';
4951 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ 1, DELIMITERS)));
4952
4953 case TOK_STRATOM:
4954 x = readstrexp (SCHEME_A_ '|');
4955 //TODO: haven't checked whether the garbage collector could interfere
4956 s_return (mk_atom (SCHEME_A_ strvalue (x)));
4957
4958 case TOK_DQUOTE:
4959 x = readstrexp (SCHEME_A_ '"');
4960
4961 if (x == S_F)
4962 Error_0 ("Error reading string");
4963
4964 setimmutable (x);
4965 s_return (x);
4966
4967 case TOK_SHARP:
4968 {
4969 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
4970
4971 if (f == NIL)
4972 Error_0 ("undefined sharp expression");
4973 else
4974 {
4975 SCHEME_V->code = cons (slot_value_in_env (f), NIL);
4976 s_goto (OP_EVAL);
4977 }
4978 }
4979
4980 case TOK_SHARP_CONST:
4981 if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ 0, DELIMITERS))) == NIL)
4982 Error_0 ("undefined sharp expression");
4983 else
4984 s_return (x);
4985
4986 default:
4987 Error_0 ("syntax error: illegal token");
4988 }
4989
4990 break;
4991
4992 case OP_RDLIST:
4993 SCHEME_V->args = cons (SCHEME_V->value, args);
4994 SCHEME_V->tok = token (SCHEME_A);
4995
4996 switch (SCHEME_V->tok)
4997 {
4998 case TOK_EOF:
4999 s_return (S_EOF);
5000
5001 case TOK_RPAREN:
5002 {
5003 int c = inchar (SCHEME_A);
5004
5005 if (c != '\n')
5006 backchar (SCHEME_A_ c);
5007 #if SHOW_ERROR_LINE
5008 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5009 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5010 #endif
5011
5012 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5013 s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5014 }
5015
5016 case TOK_DOT:
5017 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5018 SCHEME_V->tok = token (SCHEME_A);
5019 s_goto (OP_RDSEXPR);
5020
5021 default:
5022 s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5023 s_goto (OP_RDSEXPR);
5024 }
5025
5026 case OP_RDDOT:
5027 if (token (SCHEME_A) != TOK_RPAREN)
5028 Error_0 ("syntax error: illegal dot expression");
5029
5030 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5031 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5032
5033 case OP_RDQUOTE:
5034 s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5035
5036 case OP_RDQQUOTE:
5037 s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5038
5039 case OP_RDQQUOTEVEC:
5040 s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5041 cons (mk_symbol (SCHEME_A_ "vector"),
5042 cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5043
5044 case OP_RDUNQUOTE:
5045 s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5046
5047 case OP_RDUQTSP:
5048 s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5049
5050 case OP_RDVEC:
5051 /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5052 s_goto(OP_EVAL); Cannot be quoted */
5053 /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5054 s_return(x); Cannot be part of pairs */
5055 /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5056 SCHEME_V->args=SCHEME_V->value;
5057 s_goto(OP_APPLY); */
5058 SCHEME_V->args = SCHEME_V->value;
5059 s_goto (OP_VECTOR);
5060
5061 /* ========== printing part ========== */
5062 case OP_P0LIST:
5063 if (is_vector (args))
5064 {
5065 putstr (SCHEME_A_ "#(");
5066 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5067 s_goto (OP_PVECFROM);
5068 }
5069 else if (is_environment (args))
5070 {
5071 putstr (SCHEME_A_ "#<ENVIRONMENT>");
5072 s_return (S_T);
5073 }
5074 else if (!is_pair (args))
5075 {
5076 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5077 s_return (S_T);
5078 }
5079 else
5080 {
5081 pointer a = car (args);
5082 pointer b = cdr (args);
5083 int ok_abbr = ok_abbrev (b);
5084 SCHEME_V->args = car (b);
5085
5086 if (a == SCHEME_V->QUOTE && ok_abbr)
5087 putstr (SCHEME_A_ "'");
5088 else if (a == SCHEME_V->QQUOTE && ok_abbr)
5089 putstr (SCHEME_A_ "`");
5090 else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5091 putstr (SCHEME_A_ ",");
5092 else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5093 putstr (SCHEME_A_ ",@");
5094 else
5095 {
5096 putstr (SCHEME_A_ "(");
5097 s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5098 SCHEME_V->args = a;
5099 }
5100
5101 s_goto (OP_P0LIST);
5102 }
5103
5104 case OP_P1LIST:
5105 if (is_pair (args))
5106 {
5107 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5108 putstr (SCHEME_A_ " ");
5109 SCHEME_V->args = car (args);
5110 s_goto (OP_P0LIST);
5111 }
5112 else if (is_vector (args))
5113 {
5114 s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5115 putstr (SCHEME_A_ " . ");
5116 s_goto (OP_P0LIST);
5117 }
5118 else
5119 {
5120 if (args != NIL)
5121 {
5122 putstr (SCHEME_A_ " . ");
5123 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5124 }
5125
5126 putstr (SCHEME_A_ ")");
5127 s_return (S_T);
5128 }
5129
5130 case OP_PVECFROM:
5131 {
5132 int i = ivalue_unchecked (cdr (args));
5133 pointer vec = car (args);
5134 int len = veclength (vec);
5135
5136 if (i == len)
5137 {
5138 putstr (SCHEME_A_ ")");
5139 s_return (S_T);
5140 }
5141 else
5142 {
5143 pointer elem = vector_get (vec, i);
5144
5145 ivalue_unchecked (cdr (args)) = i + 1;
5146 s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5147 SCHEME_V->args = elem;
5148
5149 if (i > 0)
5150 putstr (SCHEME_A_ " ");
5151
5152 s_goto (OP_P0LIST);
5153 }
5154 }
5155 }
5156
5157 if (USE_ERROR_CHECKING) abort ();
5158 }
5159
5160 static int
5161 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5162 {
5163 pointer args = SCHEME_V->args;
5164 pointer a = car (args);
5165 pointer x, y;
5166
5167 switch (op)
5168 {
5169 case OP_LIST_LENGTH: /* length *//* a.k */
5170 {
5171 long v = list_length (SCHEME_A_ a);
5172
5173 if (v < 0)
5174 Error_1 ("length: not a list:", a);
5175
5176 s_return (mk_integer (SCHEME_A_ v));
5177 }
5178
5179 case OP_ASSQ: /* assq *//* a.k */
5180 x = a;
5181
5182 for (y = cadr (args); is_pair (y); y = cdr (y))
5183 {
5184 if (!is_pair (car (y)))
5185 Error_0 ("unable to handle non pair element");
5186
5187 if (x == caar (y))
5188 break;
5189 }
5190
5191 if (is_pair (y))
5192 s_return (car (y));
5193 else
5194 s_return (S_F);
5195
5196
5197 case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5198 SCHEME_V->args = a;
5199
5200 if (SCHEME_V->args == NIL)
5201 s_return (S_F);
5202 else if (is_closure (SCHEME_V->args))
5203 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5204 else if (is_macro (SCHEME_V->args))
5205 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5206 else
5207 s_return (S_F);
5208
5209 case OP_CLOSUREP: /* closure? */
5210 /*
5211 * Note, macro object is also a closure.
5212 * Therefore, (closure? <#MACRO>) ==> #t
5213 */
5214 s_retbool (is_closure (a));
5215
5216 case OP_MACROP: /* macro? */
5217 s_retbool (is_macro (a));
5218 }
5219
5220 if (USE_ERROR_CHECKING) abort ();
5221 }
5222
5223 /* dispatch functions (opexe_x) return new opcode, or 0 for same opcode, or -1 to stop */
5224 typedef int (*dispatch_func)(SCHEME_P_ enum scheme_opcodes);
5225
5226 typedef int (*test_predicate)(pointer);
5227 static int
5228 tst_any (pointer p)
5229 {
5230 return 1;
5231 }
5232
5233 static int
5234 tst_inonneg (pointer p)
5235 {
5236 return is_integer (p) && ivalue_unchecked (p) >= 0;
5237 }
5238
5239 static int
5240 tst_is_list (SCHEME_P_ pointer p)
5241 {
5242 return p == NIL || is_pair (p);
5243 }
5244
5245 /* Correspond carefully with following defines! */
5246 static struct
5247 {
5248 test_predicate fct;
5249 const char *kind;
5250 } tests[] = {
5251 { tst_any , 0 },
5252 { is_string , "string" },
5253 { is_symbol , "symbol" },
5254 { is_port , "port" },
5255 { is_inport , "input port" },
5256 { is_outport , "output port" },
5257 { is_environment, "environment" },
5258 { is_pair , "pair" },
5259 { 0 , "pair or '()" },
5260 { is_character , "character" },
5261 { is_vector , "vector" },
5262 { is_number , "number" },
5263 { is_integer , "integer" },
5264 { tst_inonneg , "non-negative integer" }
5265 };
5266
5267 #define TST_NONE 0 /* TST_NONE used for built-ins, 0 for internal ops */
5268 #define TST_ANY "\001"
5269 #define TST_STRING "\002"
5270 #define TST_SYMBOL "\003"
5271 #define TST_PORT "\004"
5272 #define TST_INPORT "\005"
5273 #define TST_OUTPORT "\006"
5274 #define TST_ENVIRONMENT "\007"
5275 #define TST_PAIR "\010"
5276 #define TST_LIST "\011"
5277 #define TST_CHAR "\012"
5278 #define TST_VECTOR "\013"
5279 #define TST_NUMBER "\014"
5280 #define TST_INTEGER "\015"
5281 #define TST_NATURAL "\016"
5282
5283 #define INF_ARG 0xff
5284 #define UNNAMED_OP ""
5285
5286 static const char opnames[] =
5287 #define OP_DEF(func,name,minarity,maxarity,argtest,op) name "\x00"
5288 #include "opdefines.h"
5289 #undef OP_DEF
5290 ;
5291
5292 static const char *
5293 opname (int idx)
5294 {
5295 const char *name = opnames;
5296
5297 /* should do this at compile time, but would require external program, right? */
5298 while (idx--)
5299 name += strlen (name) + 1;
5300
5301 return *name ? name : "ILLEGAL";
5302 }
5303
5304 static const char *
5305 procname (pointer x)
5306 {
5307 return opname (procnum (x));
5308 }
5309
5310 typedef struct
5311 {
5312 uint8_t func;
5313 /*dispatch_func func;*//*TODO: maybe optionally keep the pointer, for speed? */
5314 uint8_t builtin;
5315 #if USE_ERROR_CHECKING
5316 uint8_t min_arity;
5317 uint8_t max_arity;
5318 char arg_tests_encoding[3];
5319 #endif
5320 } op_code_info;
5321
5322 static const op_code_info dispatch_table[] = {
5323 #if USE_ERROR_CHECKING
5324 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1, minarity, maxarity, argtest },
5325 #else
5326 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1 },
5327 #endif
5328 #include "opdefines.h"
5329 #undef OP_DEF
5330 {0}
5331 };
5332
5333 /* kernel of this interpreter */
5334 static void ecb_hot
5335 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5336 {
5337 SCHEME_V->op = op;
5338
5339 for (;;)
5340 {
5341 const op_code_info *pcd = dispatch_table + SCHEME_V->op;
5342
5343 #if USE_ERROR_CHECKING
5344 if (pcd->builtin) /* if built-in function, check arguments */
5345 {
5346 char msg[STRBUFFSIZE];
5347 int n = list_length (SCHEME_A_ SCHEME_V->args);
5348
5349 /* Check number of arguments */
5350 if (ecb_expect_false (n < pcd->min_arity))
5351 {
5352 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5353 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5354 xError_1 (SCHEME_A_ msg, 0);
5355 continue;
5356 }
5357 else if (ecb_expect_false (n > pcd->max_arity && pcd->max_arity != INF_ARG))
5358 {
5359 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5360 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5361 xError_1 (SCHEME_A_ msg, 0);
5362 continue;
5363 }
5364 else
5365 {
5366 if (*pcd->arg_tests_encoding) /* literal 0 and TST_NONE treated the same */
5367 {
5368 int i = 0;
5369 int j;
5370 const char *t = pcd->arg_tests_encoding;
5371 pointer arglist = SCHEME_V->args;
5372
5373 do
5374 {
5375 pointer arg = car (arglist);
5376
5377 j = t[0];
5378
5379 /*TODO: tst_is_list has different prototype - fix if other tests acquire same prototype */
5380 if (j == TST_LIST[0])
5381 {
5382 if (!tst_is_list (SCHEME_A_ arg))
5383 break;
5384 }
5385 else
5386 {
5387 if (!tests[j - 1].fct (arg))
5388 break;
5389 }
5390
5391 if (t < pcd->arg_tests_encoding + sizeof (pcd->arg_tests_encoding) - 1 && t[1]) /* last test is replicated as necessary */
5392 t++;
5393
5394 arglist = cdr (arglist);
5395 i++;
5396 }
5397 while (i < n);
5398
5399 if (i < n)
5400 {
5401 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", opname (SCHEME_V->op), i + 1, tests[j].kind);
5402 xError_1 (SCHEME_A_ msg, 0);
5403 continue;
5404 }
5405 }
5406 }
5407 }
5408 #endif
5409
5410 ok_to_freely_gc (SCHEME_A);
5411
5412 static const dispatch_func dispatch_funcs[] = {
5413 opexe_0,
5414 opexe_1,
5415 opexe_2,
5416 opexe_3,
5417 opexe_4,
5418 opexe_5,
5419 opexe_6,
5420 };
5421
5422 if (ecb_expect_false (dispatch_funcs [pcd->func] (SCHEME_A_ SCHEME_V->op) != 0))
5423 return;
5424
5425 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5426 {
5427 xwrstr ("No memory!\n");
5428 return;
5429 }
5430 }
5431 }
5432
5433 /* ========== Initialization of internal keywords ========== */
5434
5435 static void
5436 assign_syntax (SCHEME_P_ const char *name)
5437 {
5438 pointer x = oblist_add_by_name (SCHEME_A_ name);
5439 set_typeflag (x, typeflag (x) | T_SYNTAX);
5440 }
5441
5442 static void
5443 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5444 {
5445 pointer x = mk_symbol (SCHEME_A_ name);
5446 pointer y = mk_proc (SCHEME_A_ op);
5447 new_slot_in_env (SCHEME_A_ x, y);
5448 }
5449
5450 static pointer
5451 mk_proc (SCHEME_P_ enum scheme_opcodes op)
5452 {
5453 pointer y = get_cell (SCHEME_A_ NIL, NIL);
5454 set_typeflag (y, (T_PROC | T_ATOM));
5455 ivalue_unchecked (y) = op;
5456 return y;
5457 }
5458
5459 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5460 static int
5461 syntaxnum (pointer p)
5462 {
5463 const char *s = strvalue (car (p));
5464
5465 switch (strlength (car (p)))
5466 {
5467 case 2:
5468 if (s[0] == 'i')
5469 return OP_IF0; /* if */
5470 else
5471 return OP_OR0; /* or */
5472
5473 case 3:
5474 if (s[0] == 'a')
5475 return OP_AND0; /* and */
5476 else
5477 return OP_LET0; /* let */
5478
5479 case 4:
5480 switch (s[3])
5481 {
5482 case 'e':
5483 return OP_CASE0; /* case */
5484
5485 case 'd':
5486 return OP_COND0; /* cond */
5487
5488 case '*':
5489 return OP_LET0AST;/* let* */
5490
5491 default:
5492 return OP_SET0; /* set! */
5493 }
5494
5495 case 5:
5496 switch (s[2])
5497 {
5498 case 'g':
5499 return OP_BEGIN; /* begin */
5500
5501 case 'l':
5502 return OP_DELAY; /* delay */
5503
5504 case 'c':
5505 return OP_MACRO0; /* macro */
5506
5507 default:
5508 return OP_QUOTE; /* quote */
5509 }
5510
5511 case 6:
5512 switch (s[2])
5513 {
5514 case 'm':
5515 return OP_LAMBDA; /* lambda */
5516
5517 case 'f':
5518 return OP_DEF0; /* define */
5519
5520 default:
5521 return OP_LET0REC;/* letrec */
5522 }
5523
5524 default:
5525 return OP_C0STREAM; /* cons-stream */
5526 }
5527 }
5528
5529 #if USE_MULTIPLICITY
5530 ecb_cold scheme *
5531 scheme_init_new ()
5532 {
5533 scheme *sc = malloc (sizeof (scheme));
5534
5535 if (!scheme_init (SCHEME_A))
5536 {
5537 free (SCHEME_A);
5538 return 0;
5539 }
5540 else
5541 return sc;
5542 }
5543 #endif
5544
5545 ecb_cold int
5546 scheme_init (SCHEME_P)
5547 {
5548 int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5549 pointer x;
5550
5551 num_set_fixnum (num_zero, 1);
5552 num_set_ivalue (num_zero, 0);
5553 num_set_fixnum (num_one, 1);
5554 num_set_ivalue (num_one, 1);
5555
5556 #if USE_INTERFACE
5557 SCHEME_V->vptr = &vtbl;
5558 #endif
5559 SCHEME_V->gensym_cnt = 0;
5560 SCHEME_V->last_cell_seg = -1;
5561 SCHEME_V->free_cell = NIL;
5562 SCHEME_V->fcells = 0;
5563 SCHEME_V->no_memory = 0;
5564 SCHEME_V->inport = NIL;
5565 SCHEME_V->outport = NIL;
5566 SCHEME_V->save_inport = NIL;
5567 SCHEME_V->loadport = NIL;
5568 SCHEME_V->nesting = 0;
5569 SCHEME_V->interactive_repl = 0;
5570
5571 if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5572 {
5573 #if USE_ERROR_CHECKING
5574 SCHEME_V->no_memory = 1;
5575 return 0;
5576 #endif
5577 }
5578
5579 SCHEME_V->gc_verbose = 0;
5580 dump_stack_initialize (SCHEME_A);
5581 SCHEME_V->code = NIL;
5582 SCHEME_V->args = NIL;
5583 SCHEME_V->envir = NIL;
5584 SCHEME_V->tracing = 0;
5585
5586 /* init NIL */
5587 set_typeflag (NIL, T_ATOM | T_MARK);
5588 set_car (NIL, NIL);
5589 set_cdr (NIL, NIL);
5590 /* init T */
5591 set_typeflag (S_T, T_ATOM | T_MARK);
5592 set_car (S_T, S_T);
5593 set_cdr (S_T, S_T);
5594 /* init F */
5595 set_typeflag (S_F, T_ATOM | T_MARK);
5596 set_car (S_F, S_F);
5597 set_cdr (S_F, S_F);
5598 /* init EOF_OBJ */
5599 set_typeflag (S_EOF, T_ATOM | T_MARK);
5600 set_car (S_EOF, S_EOF);
5601 set_cdr (S_EOF, S_EOF);
5602 /* init sink */
5603 set_typeflag (S_SINK, T_PAIR | T_MARK);
5604 set_car (S_SINK, NIL);
5605
5606 /* init c_nest */
5607 SCHEME_V->c_nest = NIL;
5608
5609 SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5610 /* init global_env */
5611 new_frame_in_env (SCHEME_A_ NIL);
5612 SCHEME_V->global_env = SCHEME_V->envir;
5613 /* init else */
5614 x = mk_symbol (SCHEME_A_ "else");
5615 new_slot_in_env (SCHEME_A_ x, S_T);
5616
5617 {
5618 static const char *syntax_names[] = {
5619 "lambda", "quote", "define", "if", "begin", "set!",
5620 "let", "let*", "letrec", "cond", "delay", "and",
5621 "or", "cons-stream", "macro", "case"
5622 };
5623
5624 for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5625 assign_syntax (SCHEME_A_ syntax_names[i]);
5626 }
5627
5628 // TODO: should iterate via strlen, to avoid n² complexity
5629 for (i = 0; i < n; i++)
5630 if (dispatch_table[i].builtin)
5631 assign_proc (SCHEME_A_ i, opname (i));
5632
5633 /* initialization of global pointers to special symbols */
5634 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5635 SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5636 SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5637 SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5638 SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5639 SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5640 SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5641 SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5642 SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5643 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5644
5645 return !SCHEME_V->no_memory;
5646 }
5647
5648 #if USE_PORTS
5649 void
5650 scheme_set_input_port_file (SCHEME_P_ int fin)
5651 {
5652 SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5653 }
5654
5655 void
5656 scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5657 {
5658 SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5659 }
5660
5661 void
5662 scheme_set_output_port_file (SCHEME_P_ int fout)
5663 {
5664 SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5665 }
5666
5667 void
5668 scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5669 {
5670 SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5671 }
5672 #endif
5673
5674 void
5675 scheme_set_external_data (SCHEME_P_ void *p)
5676 {
5677 SCHEME_V->ext_data = p;
5678 }
5679
5680 ecb_cold void
5681 scheme_deinit (SCHEME_P)
5682 {
5683 int i;
5684
5685 #if SHOW_ERROR_LINE
5686 char *fname;
5687 #endif
5688
5689 SCHEME_V->oblist = NIL;
5690 SCHEME_V->global_env = NIL;
5691 dump_stack_free (SCHEME_A);
5692 SCHEME_V->envir = NIL;
5693 SCHEME_V->code = NIL;
5694 SCHEME_V->args = NIL;
5695 SCHEME_V->value = NIL;
5696
5697 if (is_port (SCHEME_V->inport))
5698 set_typeflag (SCHEME_V->inport, T_ATOM);
5699
5700 SCHEME_V->inport = NIL;
5701 SCHEME_V->outport = NIL;
5702
5703 if (is_port (SCHEME_V->save_inport))
5704 set_typeflag (SCHEME_V->save_inport, T_ATOM);
5705
5706 SCHEME_V->save_inport = NIL;
5707
5708 if (is_port (SCHEME_V->loadport))
5709 set_typeflag (SCHEME_V->loadport, T_ATOM);
5710
5711 SCHEME_V->loadport = NIL;
5712 SCHEME_V->gc_verbose = 0;
5713 gc (SCHEME_A_ NIL, NIL);
5714
5715 for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5716 free (SCHEME_V->alloc_seg[i]);
5717
5718 #if SHOW_ERROR_LINE
5719 for (i = 0; i <= SCHEME_V->file_i; i++)
5720 {
5721 if (SCHEME_V->load_stack[i].kind & port_file)
5722 {
5723 fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5724
5725 if (fname)
5726 free (fname);
5727 }
5728 }
5729 #endif
5730 }
5731
5732 void
5733 scheme_load_file (SCHEME_P_ int fin)
5734 {
5735 scheme_load_named_file (SCHEME_A_ fin, 0);
5736 }
5737
5738 void
5739 scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5740 {
5741 dump_stack_reset (SCHEME_A);
5742 SCHEME_V->envir = SCHEME_V->global_env;
5743 SCHEME_V->file_i = 0;
5744 SCHEME_V->load_stack[0].unget = -1;
5745 SCHEME_V->load_stack[0].kind = port_input | port_file;
5746 SCHEME_V->load_stack[0].rep.stdio.file = fin;
5747 #if USE_PORTS
5748 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5749 #endif
5750 SCHEME_V->retcode = 0;
5751
5752 #if USE_PORTS
5753 if (fin == STDIN_FILENO)
5754 SCHEME_V->interactive_repl = 1;
5755 #endif
5756
5757 #if USE_PORTS
5758 #if SHOW_ERROR_LINE
5759 SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5760
5761 if (fin != STDIN_FILENO && filename)
5762 SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5763 #endif
5764 #endif
5765
5766 SCHEME_V->inport = SCHEME_V->loadport;
5767 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5768 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5769 set_typeflag (SCHEME_V->loadport, T_ATOM);
5770
5771 if (SCHEME_V->retcode == 0)
5772 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5773 }
5774
5775 void
5776 scheme_load_string (SCHEME_P_ const char *cmd)
5777 {
5778 dump_stack_reset (SCHEME_A);
5779 SCHEME_V->envir = SCHEME_V->global_env;
5780 SCHEME_V->file_i = 0;
5781 SCHEME_V->load_stack[0].kind = port_input | port_string;
5782 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
5783 SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
5784 SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
5785 #if USE_PORTS
5786 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5787 #endif
5788 SCHEME_V->retcode = 0;
5789 SCHEME_V->interactive_repl = 0;
5790 SCHEME_V->inport = SCHEME_V->loadport;
5791 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5792 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5793 set_typeflag (SCHEME_V->loadport, T_ATOM);
5794
5795 if (SCHEME_V->retcode == 0)
5796 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5797 }
5798
5799 void
5800 scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
5801 {
5802 pointer x;
5803
5804 x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
5805
5806 if (x != NIL)
5807 set_slot_in_env (SCHEME_A_ x, value);
5808 else
5809 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
5810 }
5811
5812 #if !STANDALONE
5813
5814 void
5815 scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
5816 {
5817 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
5818 }
5819
5820 void
5821 scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
5822 {
5823 int i;
5824
5825 for (i = 0; i < count; i++)
5826 scheme_register_foreign_func (SCHEME_A_ list + i);
5827 }
5828
5829 pointer
5830 scheme_apply0 (SCHEME_P_ const char *procname)
5831 {
5832 return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
5833 }
5834
5835 void
5836 save_from_C_call (SCHEME_P)
5837 {
5838 pointer saved_data = cons (car (S_SINK),
5839 cons (SCHEME_V->envir,
5840 SCHEME_V->dump));
5841
5842 /* Push */
5843 SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
5844 /* Truncate the dump stack so TS will return here when done, not
5845 directly resume pre-C-call operations. */
5846 dump_stack_reset (SCHEME_A);
5847 }
5848
5849 void
5850 restore_from_C_call (SCHEME_P)
5851 {
5852 set_car (S_SINK, caar (SCHEME_V->c_nest));
5853 SCHEME_V->envir = cadar (SCHEME_V->c_nest);
5854 SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
5855 /* Pop */
5856 SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
5857 }
5858
5859 /* "func" and "args" are assumed to be already eval'ed. */
5860 pointer
5861 scheme_call (SCHEME_P_ pointer func, pointer args)
5862 {
5863 int old_repl = SCHEME_V->interactive_repl;
5864
5865 SCHEME_V->interactive_repl = 0;
5866 save_from_C_call (SCHEME_A);
5867 SCHEME_V->envir = SCHEME_V->global_env;
5868 SCHEME_V->args = args;
5869 SCHEME_V->code = func;
5870 SCHEME_V->retcode = 0;
5871 Eval_Cycle (SCHEME_A_ OP_APPLY);
5872 SCHEME_V->interactive_repl = old_repl;
5873 restore_from_C_call (SCHEME_A);
5874 return SCHEME_V->value;
5875 }
5876
5877 pointer
5878 scheme_eval (SCHEME_P_ pointer obj)
5879 {
5880 int old_repl = SCHEME_V->interactive_repl;
5881
5882 SCHEME_V->interactive_repl = 0;
5883 save_from_C_call (SCHEME_A);
5884 SCHEME_V->args = NIL;
5885 SCHEME_V->code = obj;
5886 SCHEME_V->retcode = 0;
5887 Eval_Cycle (SCHEME_A_ OP_EVAL);
5888 SCHEME_V->interactive_repl = old_repl;
5889 restore_from_C_call (SCHEME_A);
5890 return SCHEME_V->value;
5891 }
5892
5893 #endif
5894
5895 /* ========== Main ========== */
5896
5897 #if STANDALONE
5898
5899 int
5900 main (int argc, char **argv)
5901 {
5902 # if USE_MULTIPLICITY
5903 scheme ssc;
5904 scheme *const SCHEME_V = &ssc;
5905 # else
5906 # endif
5907 int fin;
5908 char *file_name = InitFile;
5909 int retcode;
5910 int isfile = 1;
5911
5912 if (argc == 2 && strcmp (argv[1], "-?") == 0)
5913 {
5914 xwrstr ("Usage: tinyscheme -?\n");
5915 xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
5916 xwrstr ("followed by\n");
5917 xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
5918 xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5919 xwrstr ("assuming that the executable is named tinyscheme.\n");
5920 xwrstr ("Use - as filename for stdin.\n");
5921 return 1;
5922 }
5923
5924 if (!scheme_init (SCHEME_A))
5925 {
5926 xwrstr ("Could not initialize!\n");
5927 return 2;
5928 }
5929
5930 # if USE_PORTS
5931 scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
5932 scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
5933 # endif
5934
5935 argv++;
5936
5937 #if 0
5938 if (access (file_name, 0) != 0)
5939 {
5940 char *p = getenv ("TINYSCHEMEINIT");
5941
5942 if (p != 0)
5943 file_name = p;
5944 }
5945 #endif
5946
5947 do
5948 {
5949 #if USE_PORTS
5950 if (strcmp (file_name, "-") == 0)
5951 fin = STDIN_FILENO;
5952 else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
5953 {
5954 pointer args = NIL;
5955
5956 isfile = file_name[1] == '1';
5957 file_name = *argv++;
5958
5959 if (strcmp (file_name, "-") == 0)
5960 fin = STDIN_FILENO;
5961 else if (isfile)
5962 fin = open (file_name, O_RDONLY);
5963
5964 for (; *argv; argv++)
5965 {
5966 pointer value = mk_string (SCHEME_A_ * argv);
5967
5968 args = cons (value, args);
5969 }
5970
5971 args = reverse_in_place (SCHEME_A_ NIL, args);
5972 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
5973
5974 }
5975 else
5976 fin = open (file_name, O_RDONLY);
5977 #endif
5978
5979 if (isfile && fin < 0)
5980 {
5981 xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
5982 }
5983 else
5984 {
5985 if (isfile)
5986 scheme_load_named_file (SCHEME_A_ fin, file_name);
5987 else
5988 scheme_load_string (SCHEME_A_ file_name);
5989
5990 #if USE_PORTS
5991 if (!isfile || fin != STDIN_FILENO)
5992 {
5993 if (SCHEME_V->retcode != 0)
5994 {
5995 xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
5996 }
5997
5998 if (isfile)
5999 close (fin);
6000 }
6001 #endif
6002 }
6003
6004 file_name = *argv++;
6005 }
6006 while (file_name != 0);
6007
6008 if (argc == 1)
6009 scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6010
6011 retcode = SCHEME_V->retcode;
6012 scheme_deinit (SCHEME_A);
6013
6014 return retcode;
6015 }
6016
6017 #endif
6018
6019 /*
6020 Local variables:
6021 c-file-style: "k&r"
6022 End:
6023 */