ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.26
Committed: Sat Nov 28 05:12:53 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.25: +256 -244 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 exit(0);//D
4715 return -1;
4716
4717 case OP_GC: /* gc */
4718 gc (SCHEME_A_ NIL, NIL);
4719 s_return (S_T);
4720
4721 case OP_GCVERB: /* gc-verbose */
4722 {
4723 int was = SCHEME_V->gc_verbose;
4724
4725 SCHEME_V->gc_verbose = (a != S_F);
4726 s_retbool (was);
4727 }
4728
4729 case OP_NEWSEGMENT: /* new-segment */
4730 if (!is_pair (args) || !is_number (a))
4731 Error_0 ("new-segment: argument must be a number");
4732
4733 alloc_cellseg (SCHEME_A_ ivalue (a));
4734
4735 s_return (S_T);
4736
4737 case OP_OBLIST: /* oblist */
4738 s_return (oblist_all_symbols (SCHEME_A));
4739
4740 #if USE_PORTS
4741
4742 case OP_CURR_INPORT: /* current-input-port */
4743 s_return (SCHEME_V->inport);
4744
4745 case OP_CURR_OUTPORT: /* current-output-port */
4746 s_return (SCHEME_V->outport);
4747
4748 case OP_OPEN_INFILE: /* open-input-file */
4749 case OP_OPEN_OUTFILE: /* open-output-file */
4750 case OP_OPEN_INOUTFILE: /* open-input-output-file */
4751 {
4752 int prop = 0;
4753 pointer p;
4754
4755 switch (op)
4756 {
4757 case OP_OPEN_INFILE:
4758 prop = port_input;
4759 break;
4760
4761 case OP_OPEN_OUTFILE:
4762 prop = port_output;
4763 break;
4764
4765 case OP_OPEN_INOUTFILE:
4766 prop = port_input | port_output;
4767 break;
4768 }
4769
4770 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
4771
4772 s_return (p == NIL ? S_F : p);
4773 }
4774
4775 # if USE_STRING_PORTS
4776
4777 case OP_OPEN_INSTRING: /* open-input-string */
4778 case OP_OPEN_INOUTSTRING: /* open-input-output-string */
4779 {
4780 int prop = 0;
4781 pointer p;
4782
4783 switch (op)
4784 {
4785 case OP_OPEN_INSTRING:
4786 prop = port_input;
4787 break;
4788
4789 case OP_OPEN_INOUTSTRING:
4790 prop = port_input | port_output;
4791 break;
4792 }
4793
4794 p = port_from_string (SCHEME_A_ strvalue (a),
4795 strvalue (a) + strlength (a), prop);
4796
4797 s_return (p == NIL ? S_F : p);
4798 }
4799
4800 case OP_OPEN_OUTSTRING: /* open-output-string */
4801 {
4802 pointer p;
4803
4804 if (a == NIL)
4805 p = port_from_scratch (SCHEME_A);
4806 else
4807 p = port_from_string (SCHEME_A_ strvalue (a),
4808 strvalue (a) + strlength (a), port_output);
4809
4810 s_return (p == NIL ? S_F : p);
4811 }
4812
4813 case OP_GET_OUTSTRING: /* get-output-string */
4814 {
4815 port *p;
4816
4817 if ((p = a->object.port)->kind & port_string)
4818 {
4819 off_t size;
4820 char *str;
4821
4822 size = p->rep.string.curr - p->rep.string.start + 1;
4823 str = malloc (size);
4824
4825 if (str != NULL)
4826 {
4827 pointer s;
4828
4829 memcpy (str, p->rep.string.start, size - 1);
4830 str[size - 1] = '\0';
4831 s = mk_string (SCHEME_A_ str);
4832 free (str);
4833 s_return (s);
4834 }
4835 }
4836
4837 s_return (S_F);
4838 }
4839
4840 # endif
4841
4842 case OP_CLOSE_INPORT: /* close-input-port */
4843 port_close (SCHEME_A_ a, port_input);
4844 s_return (S_T);
4845
4846 case OP_CLOSE_OUTPORT: /* close-output-port */
4847 port_close (SCHEME_A_ a, port_output);
4848 s_return (S_T);
4849 #endif
4850
4851 case OP_INT_ENV: /* interaction-environment */
4852 s_return (SCHEME_V->global_env);
4853
4854 case OP_CURR_ENV: /* current-environment */
4855 s_return (SCHEME_V->envir);
4856
4857 }
4858
4859 if (USE_ERROR_CHECKING) abort ();
4860 }
4861
4862 static int
4863 opexe_5 (SCHEME_P_ enum scheme_opcodes op)
4864 {
4865 pointer args = SCHEME_V->args;
4866 pointer x;
4867
4868 if (SCHEME_V->nesting != 0)
4869 {
4870 int n = SCHEME_V->nesting;
4871
4872 SCHEME_V->nesting = 0;
4873 SCHEME_V->retcode = -1;
4874 Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
4875 }
4876
4877 switch (op)
4878 {
4879 /* ========== reading part ========== */
4880 #if USE_PORTS
4881 case OP_READ:
4882 if (!is_pair (args))
4883 s_goto (OP_READ_INTERNAL);
4884
4885 if (!is_inport (car (args)))
4886 Error_1 ("read: not an input port:", car (args));
4887
4888 if (car (args) == SCHEME_V->inport)
4889 s_goto (OP_READ_INTERNAL);
4890
4891 x = SCHEME_V->inport;
4892 SCHEME_V->inport = car (args);
4893 x = cons (x, NIL);
4894 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4895 s_goto (OP_READ_INTERNAL);
4896
4897 case OP_READ_CHAR: /* read-char */
4898 case OP_PEEK_CHAR: /* peek-char */
4899 {
4900 int c;
4901
4902 if (is_pair (args))
4903 {
4904 if (car (args) != SCHEME_V->inport)
4905 {
4906 x = SCHEME_V->inport;
4907 x = cons (x, NIL);
4908 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4909 SCHEME_V->inport = car (args);
4910 }
4911 }
4912
4913 c = inchar (SCHEME_A);
4914
4915 if (c == EOF)
4916 s_return (S_EOF);
4917
4918 if (SCHEME_V->op == OP_PEEK_CHAR)
4919 backchar (SCHEME_A_ c);
4920
4921 s_return (mk_character (SCHEME_A_ c));
4922 }
4923
4924 case OP_CHAR_READY: /* char-ready? */
4925 {
4926 pointer p = SCHEME_V->inport;
4927 int res;
4928
4929 if (is_pair (args))
4930 p = car (args);
4931
4932 res = p->object.port->kind & port_string;
4933
4934 s_retbool (res);
4935 }
4936
4937 case OP_SET_INPORT: /* set-input-port */
4938 SCHEME_V->inport = car (args);
4939 s_return (SCHEME_V->value);
4940
4941 case OP_SET_OUTPORT: /* set-output-port */
4942 SCHEME_V->outport = car (args);
4943 s_return (SCHEME_V->value);
4944 #endif
4945
4946 case OP_RDSEXPR:
4947 switch (SCHEME_V->tok)
4948 {
4949 case TOK_EOF:
4950 s_return (S_EOF);
4951 /* NOTREACHED */
4952
4953 case TOK_VEC:
4954 s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
4955 /* fall through */
4956
4957 case TOK_LPAREN:
4958 SCHEME_V->tok = token (SCHEME_A);
4959
4960 if (SCHEME_V->tok == TOK_RPAREN)
4961 s_return (NIL);
4962 else if (SCHEME_V->tok == TOK_DOT)
4963 Error_0 ("syntax error: illegal dot expression");
4964 else
4965 {
4966 SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
4967 s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
4968 s_goto (OP_RDSEXPR);
4969 }
4970
4971 case TOK_QUOTE:
4972 s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
4973 SCHEME_V->tok = token (SCHEME_A);
4974 s_goto (OP_RDSEXPR);
4975
4976 case TOK_BQUOTE:
4977 SCHEME_V->tok = token (SCHEME_A);
4978
4979 if (SCHEME_V->tok == TOK_VEC)
4980 {
4981 s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
4982 SCHEME_V->tok = TOK_LPAREN;
4983 s_goto (OP_RDSEXPR);
4984 }
4985 else
4986 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
4987
4988 s_goto (OP_RDSEXPR);
4989
4990 case TOK_COMMA:
4991 s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
4992 SCHEME_V->tok = token (SCHEME_A);
4993 s_goto (OP_RDSEXPR);
4994
4995 case TOK_ATMARK:
4996 s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
4997 SCHEME_V->tok = token (SCHEME_A);
4998 s_goto (OP_RDSEXPR);
4999
5000 case TOK_ATOM:
5001 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS)));
5002
5003 case TOK_DQUOTE:
5004 x = readstrexp (SCHEME_A);
5005
5006 if (x == S_F)
5007 Error_0 ("Error reading string");
5008
5009 setimmutable (x);
5010 s_return (x);
5011
5012 case TOK_SHARP:
5013 {
5014 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
5015
5016 if (f == NIL)
5017 Error_0 ("undefined sharp expression");
5018 else
5019 {
5020 SCHEME_V->code = cons (slot_value_in_env (f), NIL);
5021 s_goto (OP_EVAL);
5022 }
5023 }
5024
5025 case TOK_SHARP_CONST:
5026 if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS))) == NIL)
5027 Error_0 ("undefined sharp expression");
5028 else
5029 s_return (x);
5030
5031 default:
5032 Error_0 ("syntax error: illegal token");
5033 }
5034
5035 break;
5036
5037 case OP_RDLIST:
5038 SCHEME_V->args = cons (SCHEME_V->value, args);
5039 SCHEME_V->tok = token (SCHEME_A);
5040
5041 switch (SCHEME_V->tok)
5042 {
5043 case TOK_EOF:
5044 s_return (S_EOF);
5045
5046 case TOK_RPAREN:
5047 {
5048 int c = inchar (SCHEME_A);
5049
5050 if (c != '\n')
5051 backchar (SCHEME_A_ c);
5052 #if SHOW_ERROR_LINE
5053 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5054 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5055 #endif
5056
5057 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5058 s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5059 }
5060
5061 case TOK_DOT:
5062 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5063 SCHEME_V->tok = token (SCHEME_A);
5064 s_goto (OP_RDSEXPR);
5065
5066 default:
5067 s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5068 s_goto (OP_RDSEXPR);
5069 }
5070
5071 case OP_RDDOT:
5072 if (token (SCHEME_A) != TOK_RPAREN)
5073 Error_0 ("syntax error: illegal dot expression");
5074
5075 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5076 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5077
5078 case OP_RDQUOTE:
5079 s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5080
5081 case OP_RDQQUOTE:
5082 s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5083
5084 case OP_RDQQUOTEVEC:
5085 s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5086 cons (mk_symbol (SCHEME_A_ "vector"),
5087 cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5088
5089 case OP_RDUNQUOTE:
5090 s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5091
5092 case OP_RDUQTSP:
5093 s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5094
5095 case OP_RDVEC:
5096 /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5097 s_goto(OP_EVAL); Cannot be quoted */
5098 /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5099 s_return(x); Cannot be part of pairs */
5100 /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5101 SCHEME_V->args=SCHEME_V->value;
5102 s_goto(OP_APPLY); */
5103 SCHEME_V->args = SCHEME_V->value;
5104 s_goto (OP_VECTOR);
5105
5106 /* ========== printing part ========== */
5107 case OP_P0LIST:
5108 if (is_vector (args))
5109 {
5110 putstr (SCHEME_A_ "#(");
5111 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5112 s_goto (OP_PVECFROM);
5113 }
5114 else if (is_environment (args))
5115 {
5116 putstr (SCHEME_A_ "#<ENVIRONMENT>");
5117 s_return (S_T);
5118 }
5119 else if (!is_pair (args))
5120 {
5121 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5122 s_return (S_T);
5123 }
5124 else
5125 {
5126 pointer a = car (args);
5127 pointer b = cdr (args);
5128 int ok_abbr = ok_abbrev (b);
5129 SCHEME_V->args = car (b);
5130
5131 if (a == SCHEME_V->QUOTE && ok_abbr)
5132 putstr (SCHEME_A_ "'");
5133 else if (a == SCHEME_V->QQUOTE && ok_abbr)
5134 putstr (SCHEME_A_ "`");
5135 else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5136 putstr (SCHEME_A_ ",");
5137 else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5138 putstr (SCHEME_A_ ",@");
5139 else
5140 {
5141 putstr (SCHEME_A_ "(");
5142 s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5143 SCHEME_V->args = a;
5144 }
5145
5146 s_goto (OP_P0LIST);
5147 }
5148
5149 case OP_P1LIST:
5150 if (is_pair (args))
5151 {
5152 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5153 putstr (SCHEME_A_ " ");
5154 SCHEME_V->args = car (args);
5155 s_goto (OP_P0LIST);
5156 }
5157 else if (is_vector (args))
5158 {
5159 s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5160 putstr (SCHEME_A_ " . ");
5161 s_goto (OP_P0LIST);
5162 }
5163 else
5164 {
5165 if (args != NIL)
5166 {
5167 putstr (SCHEME_A_ " . ");
5168 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5169 }
5170
5171 putstr (SCHEME_A_ ")");
5172 s_return (S_T);
5173 }
5174
5175 case OP_PVECFROM:
5176 {
5177 int i = ivalue_unchecked (cdr (args));
5178 pointer vec = car (args);
5179 int len = veclength (vec);
5180
5181 if (i == len)
5182 {
5183 putstr (SCHEME_A_ ")");
5184 s_return (S_T);
5185 }
5186 else
5187 {
5188 pointer elem = vector_elem (vec, i);
5189
5190 ivalue_unchecked (cdr (args)) = i + 1;
5191 s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5192 SCHEME_V->args = elem;
5193
5194 if (i > 0)
5195 putstr (SCHEME_A_ " ");
5196
5197 s_goto (OP_P0LIST);
5198 }
5199 }
5200 }
5201
5202 if (USE_ERROR_CHECKING) abort ();
5203 }
5204
5205 static int
5206 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5207 {
5208 pointer args = SCHEME_V->args;
5209 pointer a = car (args);
5210 pointer x, y;
5211
5212 switch (op)
5213 {
5214 case OP_LIST_LENGTH: /* length *//* a.k */
5215 {
5216 long v = list_length (SCHEME_A_ a);
5217
5218 if (v < 0)
5219 Error_1 ("length: not a list:", a);
5220
5221 s_return (mk_integer (SCHEME_A_ v));
5222 }
5223
5224 case OP_ASSQ: /* assq *//* a.k */
5225 x = a;
5226
5227 for (y = cadr (args); is_pair (y); y = cdr (y))
5228 {
5229 if (!is_pair (car (y)))
5230 Error_0 ("unable to handle non pair element");
5231
5232 if (x == caar (y))
5233 break;
5234 }
5235
5236 if (is_pair (y))
5237 s_return (car (y));
5238 else
5239 s_return (S_F);
5240
5241
5242 case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5243 SCHEME_V->args = a;
5244
5245 if (SCHEME_V->args == NIL)
5246 s_return (S_F);
5247 else if (is_closure (SCHEME_V->args))
5248 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5249 else if (is_macro (SCHEME_V->args))
5250 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5251 else
5252 s_return (S_F);
5253
5254 case OP_CLOSUREP: /* closure? */
5255 /*
5256 * Note, macro object is also a closure.
5257 * Therefore, (closure? <#MACRO>) ==> #t
5258 */
5259 s_retbool (is_closure (a));
5260
5261 case OP_MACROP: /* macro? */
5262 s_retbool (is_macro (a));
5263 }
5264
5265 if (USE_ERROR_CHECKING) abort ();
5266 }
5267
5268 /* dispatch functions (opexe_x) return new opcode, or 0 for same opcode, or -1 to stop */
5269 typedef int (*dispatch_func)(SCHEME_P_ enum scheme_opcodes);
5270
5271 typedef int (*test_predicate)(pointer);
5272 static int
5273 tst_any (pointer p)
5274 {
5275 return 1;
5276 }
5277
5278 static int
5279 tst_inonneg (pointer p)
5280 {
5281 return is_integer (p) && ivalue_unchecked (p) >= 0;
5282 }
5283
5284 static int
5285 tst_is_list (SCHEME_P_ pointer p)
5286 {
5287 return p == NIL || is_pair (p);
5288 }
5289
5290 /* Correspond carefully with following defines! */
5291 static struct
5292 {
5293 test_predicate fct;
5294 const char *kind;
5295 } tests[] = {
5296 { tst_any , 0 },
5297 { is_string , "string" },
5298 { is_symbol , "symbol" },
5299 { is_port , "port" },
5300 { is_inport , "input port" },
5301 { is_outport , "output port" },
5302 { is_environment, "environment" },
5303 { is_pair , "pair" },
5304 { 0 , "pair or '()" },
5305 { is_character , "character" },
5306 { is_vector , "vector" },
5307 { is_number , "number" },
5308 { is_integer , "integer" },
5309 { tst_inonneg , "non-negative integer" }
5310 };
5311
5312 #define TST_NONE 0 /* TST_NONE used for built-ins, 0 for internal ops */
5313 #define TST_ANY "\001"
5314 #define TST_STRING "\002"
5315 #define TST_SYMBOL "\003"
5316 #define TST_PORT "\004"
5317 #define TST_INPORT "\005"
5318 #define TST_OUTPORT "\006"
5319 #define TST_ENVIRONMENT "\007"
5320 #define TST_PAIR "\010"
5321 #define TST_LIST "\011"
5322 #define TST_CHAR "\012"
5323 #define TST_VECTOR "\013"
5324 #define TST_NUMBER "\014"
5325 #define TST_INTEGER "\015"
5326 #define TST_NATURAL "\016"
5327
5328 #define INF_ARG 0xff
5329 #define UNNAMED_OP ""
5330
5331 static const char opnames[] =
5332 #define OP_DEF(func,name,minarity,maxarity,argtest,op) name "\x00"
5333 #include "opdefines.h"
5334 #undef OP_DEF
5335 ;
5336
5337 static const char *
5338 opname (int idx)
5339 {
5340 const char *name = opnames;
5341
5342 /* should do this at compile time, but would require external program, right? */
5343 while (idx--)
5344 name += strlen (name) + 1;
5345
5346 return *name ? name : "ILLEGAL";
5347 }
5348
5349 static const char *
5350 procname (pointer x)
5351 {
5352 return opname (procnum (x));
5353 }
5354
5355 typedef struct
5356 {
5357 uint8_t func;
5358 /*dispatch_func func;*//*TODO: maybe optionally keep the pointer, for speed? */
5359 uint8_t builtin;
5360 #if USE_ERROR_CHECKING
5361 uint8_t min_arity;
5362 uint8_t max_arity;
5363 char arg_tests_encoding[3];
5364 #endif
5365 } op_code_info;
5366
5367 static const op_code_info dispatch_table[] = {
5368 #if USE_ERROR_CHECKING
5369 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1, minarity, maxarity, argtest },
5370 #else
5371 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1 },
5372 #endif
5373 #include "opdefines.h"
5374 #undef OP_DEF
5375 {0}
5376 };
5377
5378 /* kernel of this interpreter */
5379 static void ecb_hot
5380 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5381 {
5382 SCHEME_V->op = op;
5383
5384 for (;;)
5385 {
5386 const op_code_info *pcd = dispatch_table + SCHEME_V->op;
5387
5388 #if USE_ERROR_CHECKING
5389 if (pcd->builtin) /* if built-in function, check arguments */
5390 {
5391 char msg[STRBUFFSIZE];
5392 int n = list_length (SCHEME_A_ SCHEME_V->args);
5393
5394 /* Check number of arguments */
5395 if (ecb_expect_false (n < pcd->min_arity))
5396 {
5397 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5398 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5399 xError_1 (SCHEME_A_ msg, 0);
5400 continue;
5401 }
5402 else if (ecb_expect_false (n > pcd->max_arity && pcd->max_arity != INF_ARG))
5403 {
5404 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5405 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5406 xError_1 (SCHEME_A_ msg, 0);
5407 continue;
5408 }
5409 else
5410 {
5411 if (*pcd->arg_tests_encoding) /* literal 0 and TST_NONE treated the same */
5412 {
5413 int i = 0;
5414 int j;
5415 const char *t = pcd->arg_tests_encoding;
5416 pointer arglist = SCHEME_V->args;
5417
5418 do
5419 {
5420 pointer arg = car (arglist);
5421
5422 j = t[0];
5423
5424 /*TODO: tst_is_list has different prototype - fix if other tests acquire same prototype */
5425 if (j == TST_LIST[0])
5426 {
5427 if (!tst_is_list (SCHEME_A_ arg))
5428 break;
5429 }
5430 else
5431 {
5432 if (!tests[j - 1].fct (arg))
5433 break;
5434 }
5435
5436 if (t[1]) /* last test is replicated as necessary */
5437 t++;
5438
5439 arglist = cdr (arglist);
5440 i++;
5441 }
5442 while (i < n);
5443
5444 if (i < n)
5445 {
5446 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", opname (SCHEME_V->op), i + 1, tests[j].kind);
5447 xError_1 (SCHEME_A_ msg, 0);
5448 continue;
5449 }
5450 }
5451 }
5452 }
5453 #endif
5454
5455 ok_to_freely_gc (SCHEME_A);
5456
5457 static const dispatch_func dispatch_funcs[] = {
5458 opexe_0,
5459 opexe_1,
5460 opexe_2,
5461 opexe_3,
5462 opexe_4,
5463 opexe_5,
5464 opexe_6,
5465 };
5466
5467 if (ecb_expect_false (dispatch_funcs [pcd->func] (SCHEME_A_ SCHEME_V->op) != 0))
5468 return;
5469
5470 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5471 {
5472 xwrstr ("No memory!\n");
5473 return;
5474 }
5475 }
5476 }
5477
5478 /* ========== Initialization of internal keywords ========== */
5479
5480 static void
5481 assign_syntax (SCHEME_P_ const char *name)
5482 {
5483 pointer x = oblist_add_by_name (SCHEME_A_ name);
5484 set_typeflag (x, typeflag (x) | T_SYNTAX);
5485 }
5486
5487 static void
5488 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5489 {
5490 pointer x = mk_symbol (SCHEME_A_ name);
5491 pointer y = mk_proc (SCHEME_A_ op);
5492 new_slot_in_env (SCHEME_A_ x, y);
5493 }
5494
5495 static pointer
5496 mk_proc (SCHEME_P_ enum scheme_opcodes op)
5497 {
5498 pointer y = get_cell (SCHEME_A_ NIL, NIL);
5499 set_typeflag (y, (T_PROC | T_ATOM));
5500 ivalue_unchecked (y) = op;
5501 return y;
5502 }
5503
5504 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5505 static int
5506 syntaxnum (pointer p)
5507 {
5508 const char *s = strvalue (car (p));
5509
5510 switch (strlength (car (p)))
5511 {
5512 case 2:
5513 if (s[0] == 'i')
5514 return OP_IF0; /* if */
5515 else
5516 return OP_OR0; /* or */
5517
5518 case 3:
5519 if (s[0] == 'a')
5520 return OP_AND0; /* and */
5521 else
5522 return OP_LET0; /* let */
5523
5524 case 4:
5525 switch (s[3])
5526 {
5527 case 'e':
5528 return OP_CASE0; /* case */
5529
5530 case 'd':
5531 return OP_COND0; /* cond */
5532
5533 case '*':
5534 return OP_LET0AST;/* let* */
5535
5536 default:
5537 return OP_SET0; /* set! */
5538 }
5539
5540 case 5:
5541 switch (s[2])
5542 {
5543 case 'g':
5544 return OP_BEGIN; /* begin */
5545
5546 case 'l':
5547 return OP_DELAY; /* delay */
5548
5549 case 'c':
5550 return OP_MACRO0; /* macro */
5551
5552 default:
5553 return OP_QUOTE; /* quote */
5554 }
5555
5556 case 6:
5557 switch (s[2])
5558 {
5559 case 'm':
5560 return OP_LAMBDA; /* lambda */
5561
5562 case 'f':
5563 return OP_DEF0; /* define */
5564
5565 default:
5566 return OP_LET0REC;/* letrec */
5567 }
5568
5569 default:
5570 return OP_C0STREAM; /* cons-stream */
5571 }
5572 }
5573
5574 #if USE_MULTIPLICITY
5575 ecb_cold scheme *
5576 scheme_init_new ()
5577 {
5578 scheme *sc = malloc (sizeof (scheme));
5579
5580 if (!scheme_init (SCHEME_A))
5581 {
5582 free (SCHEME_A);
5583 return 0;
5584 }
5585 else
5586 return sc;
5587 }
5588 #endif
5589
5590 ecb_cold int
5591 scheme_init (SCHEME_P)
5592 {
5593 int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5594 pointer x;
5595
5596 num_set_fixnum (num_zero, 1);
5597 num_set_ivalue (num_zero, 0);
5598 num_set_fixnum (num_one, 1);
5599 num_set_ivalue (num_one, 1);
5600
5601 #if USE_INTERFACE
5602 SCHEME_V->vptr = &vtbl;
5603 #endif
5604 SCHEME_V->gensym_cnt = 0;
5605 SCHEME_V->last_cell_seg = -1;
5606 SCHEME_V->free_cell = NIL;
5607 SCHEME_V->fcells = 0;
5608 SCHEME_V->no_memory = 0;
5609 SCHEME_V->inport = NIL;
5610 SCHEME_V->outport = NIL;
5611 SCHEME_V->save_inport = NIL;
5612 SCHEME_V->loadport = NIL;
5613 SCHEME_V->nesting = 0;
5614 SCHEME_V->interactive_repl = 0;
5615
5616 if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5617 {
5618 #if USE_ERROR_CHECKING
5619 SCHEME_V->no_memory = 1;
5620 return 0;
5621 #endif
5622 }
5623
5624 SCHEME_V->gc_verbose = 0;
5625 dump_stack_initialize (SCHEME_A);
5626 SCHEME_V->code = NIL;
5627 SCHEME_V->args = NIL;
5628 SCHEME_V->envir = NIL;
5629 SCHEME_V->tracing = 0;
5630
5631 /* init NIL */
5632 set_typeflag (NIL, T_ATOM | T_MARK);
5633 set_car (NIL, NIL);
5634 set_cdr (NIL, NIL);
5635 /* init T */
5636 set_typeflag (S_T, T_ATOM | T_MARK);
5637 set_car (S_T, S_T);
5638 set_cdr (S_T, S_T);
5639 /* init F */
5640 set_typeflag (S_F, T_ATOM | T_MARK);
5641 set_car (S_F, S_F);
5642 set_cdr (S_F, S_F);
5643 /* init EOF_OBJ */
5644 set_typeflag (S_EOF, T_ATOM | T_MARK);
5645 set_car (S_EOF, S_EOF);
5646 set_cdr (S_EOF, S_EOF);
5647 /* init sink */
5648 set_typeflag (S_SINK, T_PAIR | T_MARK);
5649 set_car (S_SINK, NIL);
5650
5651 /* init c_nest */
5652 SCHEME_V->c_nest = NIL;
5653
5654 SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5655 /* init global_env */
5656 new_frame_in_env (SCHEME_A_ NIL);
5657 SCHEME_V->global_env = SCHEME_V->envir;
5658 /* init else */
5659 x = mk_symbol (SCHEME_A_ "else");
5660 new_slot_in_env (SCHEME_A_ x, S_T);
5661
5662 {
5663 static const char *syntax_names[] = {
5664 "lambda", "quote", "define", "if", "begin", "set!",
5665 "let", "let*", "letrec", "cond", "delay", "and",
5666 "or", "cons-stream", "macro", "case"
5667 };
5668
5669 for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5670 assign_syntax (SCHEME_A_ syntax_names[i]);
5671 }
5672
5673 // TODO: should iterate via strlen, to avoid n² complexity
5674 for (i = 0; i < n; i++)
5675 if (dispatch_table[i].builtin)
5676 assign_proc (SCHEME_A_ i, opname (i));
5677
5678 /* initialization of global pointers to special symbols */
5679 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5680 SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5681 SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5682 SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5683 SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5684 SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5685 SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5686 SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5687 SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5688 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5689
5690 return !SCHEME_V->no_memory;
5691 }
5692
5693 #if USE_PORTS
5694 void
5695 scheme_set_input_port_file (SCHEME_P_ int fin)
5696 {
5697 SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5698 }
5699
5700 void
5701 scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5702 {
5703 SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5704 }
5705
5706 void
5707 scheme_set_output_port_file (SCHEME_P_ int fout)
5708 {
5709 SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5710 }
5711
5712 void
5713 scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5714 {
5715 SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5716 }
5717 #endif
5718
5719 void
5720 scheme_set_external_data (SCHEME_P_ void *p)
5721 {
5722 SCHEME_V->ext_data = p;
5723 }
5724
5725 ecb_cold void
5726 scheme_deinit (SCHEME_P)
5727 {
5728 int i;
5729
5730 #if SHOW_ERROR_LINE
5731 char *fname;
5732 #endif
5733
5734 SCHEME_V->oblist = NIL;
5735 SCHEME_V->global_env = NIL;
5736 dump_stack_free (SCHEME_A);
5737 SCHEME_V->envir = NIL;
5738 SCHEME_V->code = NIL;
5739 SCHEME_V->args = NIL;
5740 SCHEME_V->value = NIL;
5741
5742 if (is_port (SCHEME_V->inport))
5743 set_typeflag (SCHEME_V->inport, T_ATOM);
5744
5745 SCHEME_V->inport = NIL;
5746 SCHEME_V->outport = NIL;
5747
5748 if (is_port (SCHEME_V->save_inport))
5749 set_typeflag (SCHEME_V->save_inport, T_ATOM);
5750
5751 SCHEME_V->save_inport = NIL;
5752
5753 if (is_port (SCHEME_V->loadport))
5754 set_typeflag (SCHEME_V->loadport, T_ATOM);
5755
5756 SCHEME_V->loadport = NIL;
5757 SCHEME_V->gc_verbose = 0;
5758 gc (SCHEME_A_ NIL, NIL);
5759
5760 for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5761 free (SCHEME_V->alloc_seg[i]);
5762
5763 #if SHOW_ERROR_LINE
5764 for (i = 0; i <= SCHEME_V->file_i; i++)
5765 {
5766 if (SCHEME_V->load_stack[i].kind & port_file)
5767 {
5768 fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5769
5770 if (fname)
5771 free (fname);
5772 }
5773 }
5774 #endif
5775 }
5776
5777 void
5778 scheme_load_file (SCHEME_P_ int fin)
5779 {
5780 scheme_load_named_file (SCHEME_A_ fin, 0);
5781 }
5782
5783 void
5784 scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5785 {
5786 dump_stack_reset (SCHEME_A);
5787 SCHEME_V->envir = SCHEME_V->global_env;
5788 SCHEME_V->file_i = 0;
5789 SCHEME_V->load_stack[0].unget = -1;
5790 SCHEME_V->load_stack[0].kind = port_input | port_file;
5791 SCHEME_V->load_stack[0].rep.stdio.file = fin;
5792 #if USE_PORTS
5793 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5794 #endif
5795 SCHEME_V->retcode = 0;
5796
5797 #if USE_PORTS
5798 if (fin == STDIN_FILENO)
5799 SCHEME_V->interactive_repl = 1;
5800 #endif
5801
5802 #if USE_PORTS
5803 #if SHOW_ERROR_LINE
5804 SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5805
5806 if (fin != STDIN_FILENO && filename)
5807 SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5808 #endif
5809 #endif
5810
5811 SCHEME_V->inport = SCHEME_V->loadport;
5812 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5813 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5814 set_typeflag (SCHEME_V->loadport, T_ATOM);
5815
5816 if (SCHEME_V->retcode == 0)
5817 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5818 }
5819
5820 void
5821 scheme_load_string (SCHEME_P_ const char *cmd)
5822 {
5823 dump_stack_reset (SCHEME_A);
5824 SCHEME_V->envir = SCHEME_V->global_env;
5825 SCHEME_V->file_i = 0;
5826 SCHEME_V->load_stack[0].kind = port_input | port_string;
5827 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
5828 SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
5829 SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
5830 #if USE_PORTS
5831 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5832 #endif
5833 SCHEME_V->retcode = 0;
5834 SCHEME_V->interactive_repl = 0;
5835 SCHEME_V->inport = SCHEME_V->loadport;
5836 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5837 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5838 set_typeflag (SCHEME_V->loadport, T_ATOM);
5839
5840 if (SCHEME_V->retcode == 0)
5841 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5842 }
5843
5844 void
5845 scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
5846 {
5847 pointer x;
5848
5849 x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
5850
5851 if (x != NIL)
5852 set_slot_in_env (SCHEME_A_ x, value);
5853 else
5854 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
5855 }
5856
5857 #if !STANDALONE
5858
5859 void
5860 scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
5861 {
5862 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
5863 }
5864
5865 void
5866 scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
5867 {
5868 int i;
5869
5870 for (i = 0; i < count; i++)
5871 scheme_register_foreign_func (SCHEME_A_ list + i);
5872 }
5873
5874 pointer
5875 scheme_apply0 (SCHEME_P_ const char *procname)
5876 {
5877 return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
5878 }
5879
5880 void
5881 save_from_C_call (SCHEME_P)
5882 {
5883 pointer saved_data = cons (car (S_SINK),
5884 cons (SCHEME_V->envir,
5885 SCHEME_V->dump));
5886
5887 /* Push */
5888 SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
5889 /* Truncate the dump stack so TS will return here when done, not
5890 directly resume pre-C-call operations. */
5891 dump_stack_reset (SCHEME_A);
5892 }
5893
5894 void
5895 restore_from_C_call (SCHEME_P)
5896 {
5897 set_car (S_SINK, caar (SCHEME_V->c_nest));
5898 SCHEME_V->envir = cadar (SCHEME_V->c_nest);
5899 SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
5900 /* Pop */
5901 SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
5902 }
5903
5904 /* "func" and "args" are assumed to be already eval'ed. */
5905 pointer
5906 scheme_call (SCHEME_P_ pointer func, pointer args)
5907 {
5908 int old_repl = SCHEME_V->interactive_repl;
5909
5910 SCHEME_V->interactive_repl = 0;
5911 save_from_C_call (SCHEME_A);
5912 SCHEME_V->envir = SCHEME_V->global_env;
5913 SCHEME_V->args = args;
5914 SCHEME_V->code = func;
5915 SCHEME_V->retcode = 0;
5916 Eval_Cycle (SCHEME_A_ OP_APPLY);
5917 SCHEME_V->interactive_repl = old_repl;
5918 restore_from_C_call (SCHEME_A);
5919 return SCHEME_V->value;
5920 }
5921
5922 pointer
5923 scheme_eval (SCHEME_P_ pointer obj)
5924 {
5925 int old_repl = SCHEME_V->interactive_repl;
5926
5927 SCHEME_V->interactive_repl = 0;
5928 save_from_C_call (SCHEME_A);
5929 SCHEME_V->args = NIL;
5930 SCHEME_V->code = obj;
5931 SCHEME_V->retcode = 0;
5932 Eval_Cycle (SCHEME_A_ OP_EVAL);
5933 SCHEME_V->interactive_repl = old_repl;
5934 restore_from_C_call (SCHEME_A);
5935 return SCHEME_V->value;
5936 }
5937
5938 #endif
5939
5940 /* ========== Main ========== */
5941
5942 #if STANDALONE
5943
5944 int
5945 main (int argc, char **argv)
5946 {
5947 # if USE_MULTIPLICITY
5948 scheme ssc;
5949 scheme *const SCHEME_V = &ssc;
5950 # else
5951 # endif
5952 int fin;
5953 char *file_name = InitFile;
5954 int retcode;
5955 int isfile = 1;
5956
5957 if (argc == 2 && strcmp (argv[1], "-?") == 0)
5958 {
5959 xwrstr ("Usage: tinyscheme -?\n");
5960 xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
5961 xwrstr ("followed by\n");
5962 xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
5963 xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5964 xwrstr ("assuming that the executable is named tinyscheme.\n");
5965 xwrstr ("Use - as filename for stdin.\n");
5966 return 1;
5967 }
5968
5969 if (!scheme_init (SCHEME_A))
5970 {
5971 xwrstr ("Could not initialize!\n");
5972 return 2;
5973 }
5974
5975 # if USE_PORTS
5976 scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
5977 scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
5978 # endif
5979
5980 argv++;
5981
5982 #if 0
5983 if (access (file_name, 0) != 0)
5984 {
5985 char *p = getenv ("TINYSCHEMEINIT");
5986
5987 if (p != 0)
5988 file_name = p;
5989 }
5990 #endif
5991
5992 do
5993 {
5994 #if USE_PORTS
5995 if (strcmp (file_name, "-") == 0)
5996 fin = STDIN_FILENO;
5997 else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
5998 {
5999 pointer args = NIL;
6000
6001 isfile = file_name[1] == '1';
6002 file_name = *argv++;
6003
6004 if (strcmp (file_name, "-") == 0)
6005 fin = STDIN_FILENO;
6006 else if (isfile)
6007 fin = open (file_name, O_RDONLY);
6008
6009 for (; *argv; argv++)
6010 {
6011 pointer value = mk_string (SCHEME_A_ * argv);
6012
6013 args = cons (value, args);
6014 }
6015
6016 args = reverse_in_place (SCHEME_A_ NIL, args);
6017 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
6018
6019 }
6020 else
6021 fin = open (file_name, O_RDONLY);
6022 #endif
6023
6024 if (isfile && fin < 0)
6025 {
6026 xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
6027 }
6028 else
6029 {
6030 if (isfile)
6031 scheme_load_named_file (SCHEME_A_ fin, file_name);
6032 else
6033 scheme_load_string (SCHEME_A_ file_name);
6034
6035 #if USE_PORTS
6036 if (!isfile || fin != STDIN_FILENO)
6037 {
6038 if (SCHEME_V->retcode != 0)
6039 {
6040 xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
6041 }
6042
6043 if (isfile)
6044 close (fin);
6045 }
6046 #endif
6047 }
6048
6049 file_name = *argv++;
6050 }
6051 while (file_name != 0);
6052
6053 if (argc == 1)
6054 scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6055
6056 retcode = SCHEME_V->retcode;
6057 scheme_deinit (SCHEME_A);
6058
6059 return retcode;
6060 }
6061
6062 #endif
6063
6064 /*
6065 Local variables:
6066 c-file-style: "k&r"
6067 End:
6068 */