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