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