ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/microscheme/scheme.c
Revision: 1.34
Committed: Sat Nov 28 22:14:49 2015 UTC (8 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.33: +15 -23 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 (car (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 static pointer
1085 generate_symbol (SCHEME_P_ const char *name)
1086 {
1087 pointer x = mk_string (SCHEME_A_ name);
1088 setimmutable (x);
1089 x = immutable_cons (x, NIL);
1090 set_typeflag (x, T_SYMBOL);
1091 return x;
1092 }
1093
1094 #ifndef USE_OBJECT_LIST
1095
1096 static int
1097 hash_fn (const char *key, int table_size)
1098 {
1099 const unsigned char *p = key;
1100 uint32_t hash = 2166136261;
1101
1102 while (*p)
1103 hash = (hash ^ *p++) * 16777619;
1104
1105 return hash % table_size;
1106 }
1107
1108 static pointer
1109 oblist_initial_value (SCHEME_P)
1110 {
1111 return mk_vector (SCHEME_A_ 461); /* probably should be bigger */
1112 }
1113
1114 /* returns the new symbol */
1115 static pointer
1116 oblist_add_by_name (SCHEME_P_ const char *name)
1117 {
1118 pointer x = generate_symbol (SCHEME_A_ name);
1119 int location = hash_fn (name, veclength (SCHEME_V->oblist));
1120 vector_set (SCHEME_V->oblist, location, immutable_cons (x, vector_get (SCHEME_V->oblist, location)));
1121 return x;
1122 }
1123
1124 ecb_inline pointer
1125 oblist_find_by_name (SCHEME_P_ const char *name)
1126 {
1127 int location;
1128 pointer x;
1129 char *s;
1130
1131 location = hash_fn (name, veclength (SCHEME_V->oblist));
1132
1133 for (x = vector_get (SCHEME_V->oblist, location); x != NIL; x = cdr (x))
1134 {
1135 s = symname (car (x));
1136
1137 /* case-insensitive, per R5RS section 2 */
1138 if (stricmp (name, s) == 0)
1139 return car (x);
1140 }
1141
1142 return NIL;
1143 }
1144
1145 static pointer
1146 oblist_all_symbols (SCHEME_P)
1147 {
1148 int i;
1149 pointer x;
1150 pointer ob_list = NIL;
1151
1152 for (i = 0; i < veclength (SCHEME_V->oblist); i++)
1153 for (x = vector_get (SCHEME_V->oblist, i); x != NIL; x = cdr (x))
1154 ob_list = cons (x, ob_list);
1155
1156 return ob_list;
1157 }
1158
1159 #else
1160
1161 static pointer
1162 oblist_initial_value (SCHEME_P)
1163 {
1164 return NIL;
1165 }
1166
1167 ecb_inline pointer
1168 oblist_find_by_name (SCHEME_P_ const char *name)
1169 {
1170 pointer x;
1171 char *s;
1172
1173 for (x = SCHEME_V->oblist; x != NIL; x = cdr (x))
1174 {
1175 s = symname (car (x));
1176
1177 /* case-insensitive, per R5RS section 2 */
1178 if (stricmp (name, s) == 0)
1179 return car (x);
1180 }
1181
1182 return NIL;
1183 }
1184
1185 /* returns the new symbol */
1186 static pointer
1187 oblist_add_by_name (SCHEME_P_ const char *name)
1188 {
1189 pointer x = mk_string (SCHEME_A_ name);
1190 set_typeflag (x, T_SYMBOL);
1191 setimmutable (x);
1192 SCHEME_V->oblist = immutable_cons (x, SCHEME_V->oblist);
1193 return x;
1194 }
1195
1196 static pointer
1197 oblist_all_symbols (SCHEME_P)
1198 {
1199 return SCHEME_V->oblist;
1200 }
1201
1202 #endif
1203
1204 #if USE_PORTS
1205 static pointer
1206 mk_port (SCHEME_P_ port *p)
1207 {
1208 pointer x = get_cell (SCHEME_A_ NIL, NIL);
1209
1210 set_typeflag (x, T_PORT | T_ATOM);
1211 x->object.port = p;
1212
1213 return x;
1214 }
1215 #endif
1216
1217 pointer
1218 mk_foreign_func (SCHEME_P_ foreign_func f)
1219 {
1220 pointer x = get_cell (SCHEME_A_ NIL, NIL);
1221
1222 set_typeflag (x, (T_FOREIGN | T_ATOM));
1223 x->object.ff = f;
1224
1225 return x;
1226 }
1227
1228 INTERFACE pointer
1229 mk_character (SCHEME_P_ int c)
1230 {
1231 pointer x = get_cell (SCHEME_A_ NIL, NIL);
1232
1233 set_typeflag (x, (T_CHARACTER | T_ATOM));
1234 set_ivalue (x, c & 0xff);
1235
1236 return x;
1237 }
1238
1239 /* get number atom (integer) */
1240 INTERFACE pointer
1241 mk_integer (SCHEME_P_ long n)
1242 {
1243 pointer x = get_cell (SCHEME_A_ NIL, NIL);
1244
1245 set_typeflag (x, (T_INTEGER | T_ATOM));
1246 set_ivalue (x, n);
1247
1248 return x;
1249 }
1250
1251 INTERFACE pointer
1252 mk_real (SCHEME_P_ RVALUE n)
1253 {
1254 #if USE_REAL
1255 pointer x = get_cell (SCHEME_A_ NIL, NIL);
1256
1257 set_typeflag (x, (T_REAL | T_ATOM));
1258 set_rvalue (x, n);
1259
1260 return x;
1261 #else
1262 return mk_integer (SCHEME_A_ n);
1263 #endif
1264 }
1265
1266 static pointer
1267 mk_number (SCHEME_P_ const num n)
1268 {
1269 #if USE_REAL
1270 return num_is_fixnum (n)
1271 ? mk_integer (SCHEME_A_ num_ivalue (n))
1272 : mk_real (SCHEME_A_ num_rvalue (n));
1273 #else
1274 return mk_integer (SCHEME_A_ num_ivalue (n));
1275 #endif
1276 }
1277
1278 /* allocate name to string area */
1279 static char *
1280 store_string (SCHEME_P_ uint32_t len_str, const char *str, char fill)
1281 {
1282 char *q = malloc (len_str + 1);
1283
1284 if (q == 0 && USE_ERROR_CHECKING)
1285 {
1286 SCHEME_V->no_memory = 1;
1287 return SCHEME_V->strbuff;
1288 }
1289
1290 if (str)
1291 {
1292 int l = strlen (str);
1293
1294 if (l > len_str)
1295 l = len_str;
1296
1297 memcpy (q, str, l);
1298 q[l] = 0;
1299 }
1300 else
1301 {
1302 memset (q, fill, len_str);
1303 q[len_str] = 0;
1304 }
1305
1306 return q;
1307 }
1308
1309 INTERFACE pointer
1310 mk_empty_string (SCHEME_P_ uint32_t len, char fill)
1311 {
1312 pointer x = get_cell (SCHEME_A_ NIL, NIL);
1313
1314 set_typeflag (x, T_STRING | T_ATOM);
1315 strvalue (x) = store_string (SCHEME_A_ len, 0, fill);
1316 strlength (x) = len;
1317 return x;
1318 }
1319
1320 INTERFACE pointer
1321 mk_counted_string (SCHEME_P_ const char *str, uint32_t len)
1322 {
1323 pointer x = get_cell (SCHEME_A_ NIL, NIL);
1324
1325 set_typeflag (x, T_STRING | T_ATOM);
1326 strvalue (x) = store_string (SCHEME_A_ len, str, 0);
1327 strlength (x) = len;
1328 return x;
1329 }
1330
1331 INTERFACE pointer
1332 mk_string (SCHEME_P_ const char *str)
1333 {
1334 return mk_counted_string (SCHEME_A_ str, strlen (str));
1335 }
1336
1337 INTERFACE pointer
1338 mk_vector (SCHEME_P_ uint32_t len)
1339 {
1340 return get_vector_object (SCHEME_A_ len, NIL);
1341 }
1342
1343 INTERFACE void
1344 fill_vector (pointer vec, uint32_t start, pointer obj)
1345 {
1346 int i;
1347
1348 for (i = start; i < veclength (vec); i++)
1349 vecvalue (vec)[i] = obj;
1350 }
1351
1352 INTERFACE pointer
1353 vector_get (pointer vec, uint32_t ielem)
1354 {
1355 return vecvalue(vec)[ielem];
1356 }
1357
1358 INTERFACE void
1359 vector_set (pointer vec, uint32_t ielem, pointer a)
1360 {
1361 vecvalue(vec)[ielem] = a;
1362 }
1363
1364 /* get new symbol */
1365 INTERFACE pointer
1366 mk_symbol (SCHEME_P_ const char *name)
1367 {
1368 /* first check oblist */
1369 pointer x = oblist_find_by_name (SCHEME_A_ name);
1370
1371 if (x == NIL)
1372 x = oblist_add_by_name (SCHEME_A_ name);
1373
1374 return x;
1375 }
1376
1377 INTERFACE pointer
1378 gensym (SCHEME_P)
1379 {
1380 pointer x;
1381 char name[40] = "gensym-";
1382 xnum (name + 7, SCHEME_V->gensym_cnt);
1383
1384 return generate_symbol (SCHEME_A_ name);
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 #ifndef USE_ALIST_ENV
2819
2820 /*
2821 * In this implementation, each frame of the environment may be
2822 * a hash table: a vector of alists hashed by variable name.
2823 * In practice, we use a vector only for the initial frame;
2824 * subsequent frames are too small and transient for the lookup
2825 * speed to out-weigh the cost of making a new vector.
2826 */
2827
2828 static void
2829 new_frame_in_env (SCHEME_P_ pointer old_env)
2830 {
2831 pointer new_frame;
2832
2833 /* The interaction-environment has about 300 variables in it. */
2834 if (old_env == NIL)
2835 new_frame = mk_vector (SCHEME_A_ 461);
2836 else
2837 new_frame = NIL;
2838
2839 SCHEME_V->envir = immutable_cons (new_frame, old_env);
2840 setenvironment (SCHEME_V->envir);
2841 }
2842
2843 static uint32_t
2844 sym_hash (pointer sym, uint32_t size)
2845 {
2846 uintptr_t ptr = (uintptr_t)sym;
2847
2848 #if 0
2849 /* table size is prime, so why mix */
2850 ptr += ptr >> 32;
2851 ptr += ptr >> 16;
2852 ptr += ptr >> 8;
2853 #endif
2854
2855 return ptr % size;
2856 }
2857
2858 ecb_inline void
2859 new_slot_spec_in_env (SCHEME_P_ pointer env, pointer variable, pointer value)
2860 {
2861 pointer slot = immutable_cons (variable, value);
2862
2863 if (is_vector (car (env)))
2864 {
2865 int location = sym_hash (variable, veclength (car (env)));
2866 vector_set (car (env), location, immutable_cons (slot, vector_get (car (env), location)));
2867 }
2868 else
2869 set_car (env, immutable_cons (slot, car (env)));
2870 }
2871
2872 static pointer
2873 find_slot_in_env (SCHEME_P_ pointer env, pointer hdl, int all)
2874 {
2875 pointer x, y;
2876
2877 for (x = env; x != NIL; x = cdr (x))
2878 {
2879 if (is_vector (car (x)))
2880 {
2881 int location = sym_hash (hdl, veclength (car (x)));
2882 y = vector_get (car (x), location);
2883 }
2884 else
2885 y = car (x);
2886
2887 for (; y != NIL; y = cdr (y))
2888 if (caar (y) == hdl)
2889 break;
2890
2891 if (y != NIL)
2892 return car (y);
2893
2894 if (!all)
2895 break;
2896 }
2897
2898 return NIL;
2899 }
2900
2901 #else /* USE_ALIST_ENV */
2902
2903 ecb_inline void
2904 new_frame_in_env (SCHEME_P_ pointer old_env)
2905 {
2906 SCHEME_V->envir = immutable_cons (NIL, old_env);
2907 setenvironment (SCHEME_V->envir);
2908 }
2909
2910 ecb_inline void
2911 new_slot_spec_in_env (SCHEME_P_ pointer env, pointer variable, pointer value)
2912 {
2913 set_car (env, immutable_cons (immutable_cons (variable, value), car (env)));
2914 }
2915
2916 static pointer
2917 find_slot_in_env (SCHEME_P_ pointer env, pointer hdl, int all)
2918 {
2919 pointer x, y;
2920
2921 for (x = env; x != NIL; x = cdr (x))
2922 {
2923 for (y = car (x); y != NIL; y = cdr (y))
2924 if (caar (y) == hdl)
2925 break;
2926
2927 if (y != NIL)
2928 return car (y);
2929 break;
2930
2931 if (!all)
2932 break;
2933 }
2934
2935 return NIL;
2936 }
2937
2938 #endif /* USE_ALIST_ENV else */
2939
2940 ecb_inline void
2941 new_slot_in_env (SCHEME_P_ pointer variable, pointer value)
2942 {
2943 new_slot_spec_in_env (SCHEME_A_ SCHEME_V->envir, variable, value);
2944 }
2945
2946 ecb_inline void
2947 set_slot_in_env (SCHEME_P_ pointer slot, pointer value)
2948 {
2949 set_cdr (slot, value);
2950 }
2951
2952 ecb_inline pointer
2953 slot_value_in_env (pointer slot)
2954 {
2955 return cdr (slot);
2956 }
2957
2958 /* ========== Evaluation Cycle ========== */
2959
2960 static int
2961 xError_1 (SCHEME_P_ const char *s, pointer a)
2962 {
2963 #if USE_ERROR_HOOK
2964 pointer x;
2965 pointer hdl = SCHEME_V->ERROR_HOOK;
2966 #endif
2967
2968 #if USE_PRINTF
2969 #if SHOW_ERROR_LINE
2970 char sbuf[STRBUFFSIZE];
2971
2972 /* make sure error is not in REPL */
2973 if ((SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file) && SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.file != STDIN_FILENO)
2974 {
2975 int ln = SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line;
2976 const char *fname = SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.filename;
2977
2978 /* should never happen */
2979 if (!fname)
2980 fname = "<unknown>";
2981
2982 /* we started from 0 */
2983 ln++;
2984 snprintf (sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s);
2985
2986 s = sbuf;
2987 }
2988 #endif
2989 #endif
2990
2991 #if USE_ERROR_HOOK
2992 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, hdl, 1);
2993
2994 if (x != NIL)
2995 {
2996 pointer code = a
2997 ? cons (cons (SCHEME_V->QUOTE, cons (a, NIL)), NIL)
2998 : NIL;
2999
3000 code = cons (mk_string (SCHEME_A_ s), code);
3001 setimmutable (car (code));
3002 SCHEME_V->code = cons (slot_value_in_env (x), code);
3003 SCHEME_V->op = OP_EVAL;
3004
3005 return 0;
3006 }
3007 #endif
3008
3009 if (a)
3010 SCHEME_V->args = cons (a, NIL);
3011 else
3012 SCHEME_V->args = NIL;
3013
3014 SCHEME_V->args = cons (mk_string (SCHEME_A_ s), SCHEME_V->args);
3015 setimmutable (car (SCHEME_V->args));
3016 SCHEME_V->op = OP_ERR0;
3017
3018 return 0;
3019 }
3020
3021 #define Error_1(s, a) return xError_1(SCHEME_A_ USE_ERROR_CHECKING ? s : "", a)
3022 #define Error_0(s) Error_1 (s, 0)
3023
3024 /* Too small to turn into function */
3025 #define BEGIN do {
3026 #define END } while (0)
3027 #define s_goto(a) BEGIN \
3028 SCHEME_V->op = a; \
3029 return 0; END
3030
3031 #define s_return(a) return xs_return (SCHEME_A_ a)
3032
3033 #ifndef USE_SCHEME_STACK
3034
3035 /* this structure holds all the interpreter's registers */
3036 struct dump_stack_frame
3037 {
3038 enum scheme_opcodes op;
3039 pointer args;
3040 pointer envir;
3041 pointer code;
3042 };
3043
3044 # define STACK_GROWTH 3
3045
3046 static void
3047 s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3048 {
3049 int nframes = (uintptr_t)SCHEME_V->dump;
3050 struct dump_stack_frame *next_frame;
3051
3052 /* enough room for the next frame? */
3053 if (nframes >= SCHEME_V->dump_size)
3054 {
3055 SCHEME_V->dump_size += STACK_GROWTH;
3056 SCHEME_V->dump_base = realloc (SCHEME_V->dump_base, sizeof (struct dump_stack_frame) * SCHEME_V->dump_size);
3057 }
3058
3059 next_frame = SCHEME_V->dump_base + nframes;
3060
3061 next_frame->op = op;
3062 next_frame->args = args;
3063 next_frame->envir = SCHEME_V->envir;
3064 next_frame->code = code;
3065
3066 SCHEME_V->dump = (pointer)(uintptr_t)(nframes + 1);
3067 }
3068
3069 static int
3070 xs_return (SCHEME_P_ pointer a)
3071 {
3072 int nframes = (uintptr_t)SCHEME_V->dump;
3073 struct dump_stack_frame *frame;
3074
3075 SCHEME_V->value = a;
3076
3077 if (nframes <= 0)
3078 return -1;
3079
3080 frame = &SCHEME_V->dump_base[--nframes];
3081 SCHEME_V->op = frame->op;
3082 SCHEME_V->args = frame->args;
3083 SCHEME_V->envir = frame->envir;
3084 SCHEME_V->code = frame->code;
3085 SCHEME_V->dump = (pointer)(uintptr_t)nframes;
3086
3087 return 0;
3088 }
3089
3090 ecb_inline void
3091 dump_stack_reset (SCHEME_P)
3092 {
3093 /* in this implementation, SCHEME_V->dump is the number of frames on the stack */
3094 SCHEME_V->dump = (pointer)+0;
3095 }
3096
3097 ecb_inline void
3098 dump_stack_initialize (SCHEME_P)
3099 {
3100 SCHEME_V->dump_size = 0;
3101 SCHEME_V->dump_base = 0;
3102 dump_stack_reset (SCHEME_A);
3103 }
3104
3105 static void
3106 dump_stack_free (SCHEME_P)
3107 {
3108 free (SCHEME_V->dump_base);
3109 SCHEME_V->dump_base = 0;
3110 SCHEME_V->dump = (pointer)0;
3111 SCHEME_V->dump_size = 0;
3112 }
3113
3114 static void
3115 dump_stack_mark (SCHEME_P)
3116 {
3117 int nframes = (uintptr_t)SCHEME_V->dump;
3118 int i;
3119
3120 for (i = 0; i < nframes; i++)
3121 {
3122 struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3123
3124 mark (frame->args);
3125 mark (frame->envir);
3126 mark (frame->code);
3127 }
3128 }
3129
3130 static pointer
3131 ss_get_cont (SCHEME_P)
3132 {
3133 int nframes = (uintptr_t)SCHEME_V->dump;
3134 int i;
3135
3136 pointer cont = NIL;
3137
3138 for (i = nframes; i--; )
3139 {
3140 struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3141
3142 cont = cons (mk_integer (SCHEME_A_ frame->op),
3143 cons (frame->args,
3144 cons (frame->envir,
3145 cons (frame->code,
3146 cont))));
3147 }
3148
3149 return cont;
3150 }
3151
3152 static void
3153 ss_set_cont (SCHEME_P_ pointer cont)
3154 {
3155 int i = 0;
3156 struct dump_stack_frame *frame = SCHEME_V->dump_base;
3157
3158 while (cont != NIL)
3159 {
3160 frame->op = ivalue_unchecked (car (cont)); cont = cdr (cont);
3161 frame->args = car (cont) ; cont = cdr (cont);
3162 frame->envir = car (cont) ; cont = cdr (cont);
3163 frame->code = car (cont) ; cont = cdr (cont);
3164
3165 ++frame;
3166 ++i;
3167 }
3168
3169 SCHEME_V->dump = (pointer)(uintptr_t)i;
3170 }
3171
3172 #else
3173
3174 ecb_inline void
3175 dump_stack_reset (SCHEME_P)
3176 {
3177 SCHEME_V->dump = NIL;
3178 }
3179
3180 ecb_inline void
3181 dump_stack_initialize (SCHEME_P)
3182 {
3183 dump_stack_reset (SCHEME_A);
3184 }
3185
3186 static void
3187 dump_stack_free (SCHEME_P)
3188 {
3189 SCHEME_V->dump = NIL;
3190 }
3191
3192 static int
3193 xs_return (SCHEME_P_ pointer a)
3194 {
3195 pointer dump = SCHEME_V->dump;
3196
3197 SCHEME_V->value = a;
3198
3199 if (dump == NIL)
3200 return -1;
3201
3202 SCHEME_V->op = ivalue_unchecked (car (dump)); dump = cdr (dump);
3203 SCHEME_V->args = car (dump) ; dump = cdr (dump);
3204 SCHEME_V->envir = car (dump) ; dump = cdr (dump);
3205 SCHEME_V->code = car (dump) ; dump = cdr (dump);
3206
3207 SCHEME_V->dump = dump;
3208
3209 return 0;
3210 }
3211
3212 static void
3213 s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3214 {
3215 SCHEME_V->dump = cons (mk_integer (SCHEME_A_ op),
3216 cons (args,
3217 cons (SCHEME_V->envir,
3218 cons (code,
3219 SCHEME_V->dump))));
3220 }
3221
3222 static void
3223 dump_stack_mark (SCHEME_P)
3224 {
3225 mark (SCHEME_V->dump);
3226 }
3227
3228 static pointer
3229 ss_get_cont (SCHEME_P)
3230 {
3231 return SCHEME_V->dump;
3232 }
3233
3234 static void
3235 ss_set_cont (SCHEME_P_ pointer cont)
3236 {
3237 SCHEME_V->dump = cont;
3238 }
3239
3240 #endif
3241
3242 #define s_retbool(tf) s_return ((tf) ? S_T : S_F)
3243
3244 static int
3245 opexe_0 (SCHEME_P_ enum scheme_opcodes op)
3246 {
3247 pointer args = SCHEME_V->args;
3248 pointer x, y;
3249
3250 switch (op)
3251 {
3252 case OP_LOAD: /* load */
3253 if (file_interactive (SCHEME_A))
3254 {
3255 xwrstr ("Loading "); xwrstr (strvalue (car (args))); xwrstr ("\n");
3256 //D fprintf (SCHEME_V->outport->object.port->rep.stdio.file, "Loading %s\n", strvalue (car (args)));
3257 }
3258
3259 if (!file_push (SCHEME_A_ strvalue (car (args))))
3260 Error_1 ("unable to open", car (args));
3261 else
3262 {
3263 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
3264 s_goto (OP_T0LVL);
3265 }
3266
3267 case OP_T0LVL: /* top level */
3268
3269 /* If we reached the end of file, this loop is done. */
3270 if (SCHEME_V->loadport->object.port->kind & port_saw_EOF)
3271 {
3272 if (SCHEME_V->file_i == 0)
3273 {
3274 SCHEME_V->args = NIL;
3275 s_goto (OP_QUIT);
3276 }
3277 else
3278 {
3279 file_pop (SCHEME_A);
3280 s_return (SCHEME_V->value);
3281 }
3282
3283 /* NOTREACHED */
3284 }
3285
3286 /* If interactive, be nice to user. */
3287 if (file_interactive (SCHEME_A))
3288 {
3289 SCHEME_V->envir = SCHEME_V->global_env;
3290 dump_stack_reset (SCHEME_A);
3291 putstr (SCHEME_A_ "\n");
3292 putstr (SCHEME_A_ prompt);
3293 }
3294
3295 /* Set up another iteration of REPL */
3296 SCHEME_V->nesting = 0;
3297 SCHEME_V->save_inport = SCHEME_V->inport;
3298 SCHEME_V->inport = SCHEME_V->loadport;
3299 s_save (SCHEME_A_ OP_T0LVL, NIL, NIL);
3300 s_save (SCHEME_A_ OP_VALUEPRINT, NIL, NIL);
3301 s_save (SCHEME_A_ OP_T1LVL, NIL, NIL);
3302 s_goto (OP_READ_INTERNAL);
3303
3304 case OP_T1LVL: /* top level */
3305 SCHEME_V->code = SCHEME_V->value;
3306 SCHEME_V->inport = SCHEME_V->save_inport;
3307 s_goto (OP_EVAL);
3308
3309 case OP_READ_INTERNAL: /* internal read */
3310 SCHEME_V->tok = token (SCHEME_A);
3311
3312 if (SCHEME_V->tok == TOK_EOF)
3313 s_return (S_EOF);
3314
3315 s_goto (OP_RDSEXPR);
3316
3317 case OP_GENSYM:
3318 s_return (gensym (SCHEME_A));
3319
3320 case OP_VALUEPRINT: /* print evaluation result */
3321
3322 /* OP_VALUEPRINT is always pushed, because when changing from
3323 non-interactive to interactive mode, it needs to be
3324 already on the stack */
3325 #if USE_TRACING
3326 if (SCHEME_V->tracing)
3327 putstr (SCHEME_A_ "\nGives: ");
3328 #endif
3329
3330 if (file_interactive (SCHEME_A))
3331 {
3332 SCHEME_V->print_flag = 1;
3333 SCHEME_V->args = SCHEME_V->value;
3334 s_goto (OP_P0LIST);
3335 }
3336 else
3337 s_return (SCHEME_V->value);
3338
3339 case OP_EVAL: /* main part of evaluation */
3340 #if USE_TRACING
3341 if (SCHEME_V->tracing)
3342 {
3343 /*s_save(SCHEME_A_ OP_VALUEPRINT,NIL,NIL); */
3344 s_save (SCHEME_A_ OP_REAL_EVAL, args, SCHEME_V->code);
3345 SCHEME_V->args = SCHEME_V->code;
3346 putstr (SCHEME_A_ "\nEval: ");
3347 s_goto (OP_P0LIST);
3348 }
3349
3350 /* fall through */
3351
3352 case OP_REAL_EVAL:
3353 #endif
3354 if (is_symbol (SCHEME_V->code)) /* symbol */
3355 {
3356 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3357
3358 if (x != NIL)
3359 s_return (slot_value_in_env (x));
3360 else
3361 Error_1 ("eval: unbound variable:", SCHEME_V->code);
3362 }
3363 else if (is_pair (SCHEME_V->code))
3364 {
3365 x = car (SCHEME_V->code);
3366
3367 if (is_syntax (x)) /* SYNTAX */
3368 {
3369 SCHEME_V->code = cdr (SCHEME_V->code);
3370 s_goto (syntaxnum (x));
3371 }
3372 else /* first, eval top element and eval arguments */
3373 {
3374 s_save (SCHEME_A_ OP_E0ARGS, NIL, SCHEME_V->code);
3375 /* If no macros => s_save(SCHEME_A_ OP_E1ARGS, NIL, cdr(SCHEME_V->code)); */
3376 SCHEME_V->code = x;
3377 s_goto (OP_EVAL);
3378 }
3379 }
3380 else
3381 s_return (SCHEME_V->code);
3382
3383 case OP_E0ARGS: /* eval arguments */
3384 if (is_macro (SCHEME_V->value)) /* macro expansion */
3385 {
3386 s_save (SCHEME_A_ OP_DOMACRO, NIL, NIL);
3387 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3388 SCHEME_V->code = SCHEME_V->value;
3389 s_goto (OP_APPLY);
3390 }
3391 else
3392 {
3393 SCHEME_V->code = cdr (SCHEME_V->code);
3394 s_goto (OP_E1ARGS);
3395 }
3396
3397 case OP_E1ARGS: /* eval arguments */
3398 args = cons (SCHEME_V->value, args);
3399
3400 if (is_pair (SCHEME_V->code)) /* continue */
3401 {
3402 s_save (SCHEME_A_ OP_E1ARGS, args, cdr (SCHEME_V->code));
3403 SCHEME_V->code = car (SCHEME_V->code);
3404 SCHEME_V->args = NIL;
3405 s_goto (OP_EVAL);
3406 }
3407 else /* end */
3408 {
3409 args = reverse_in_place (SCHEME_A_ NIL, args);
3410 SCHEME_V->code = car (args);
3411 SCHEME_V->args = cdr (args);
3412 s_goto (OP_APPLY);
3413 }
3414
3415 #if USE_TRACING
3416
3417 case OP_TRACING:
3418 {
3419 int tr = SCHEME_V->tracing;
3420
3421 SCHEME_V->tracing = ivalue_unchecked (car (args));
3422 s_return (mk_integer (SCHEME_A_ tr));
3423 }
3424
3425 #endif
3426
3427 case OP_APPLY: /* apply 'code' to 'args' */
3428 #if USE_TRACING
3429 if (SCHEME_V->tracing)
3430 {
3431 s_save (SCHEME_A_ OP_REAL_APPLY, args, SCHEME_V->code);
3432 SCHEME_V->print_flag = 1;
3433 /* args=cons(SCHEME_V->code,args); */
3434 putstr (SCHEME_A_ "\nApply to: ");
3435 s_goto (OP_P0LIST);
3436 }
3437
3438 /* fall through */
3439
3440 case OP_REAL_APPLY:
3441 #endif
3442 if (is_proc (SCHEME_V->code))
3443 s_goto (procnum (SCHEME_V->code)); /* PROCEDURE */
3444 else if (is_foreign (SCHEME_V->code))
3445 {
3446 /* Keep nested calls from GC'ing the arglist */
3447 push_recent_alloc (SCHEME_A_ args, NIL);
3448 x = SCHEME_V->code->object.ff (SCHEME_A_ args);
3449
3450 s_return (x);
3451 }
3452 else if (is_closure (SCHEME_V->code) || is_macro (SCHEME_V->code) || is_promise (SCHEME_V->code)) /* CLOSURE */
3453 {
3454 /* Should not accept promise */
3455 /* make environment */
3456 new_frame_in_env (SCHEME_A_ closure_env (SCHEME_V->code));
3457
3458 for (x = car (closure_code (SCHEME_V->code)), y = args; is_pair (x); x = cdr (x), y = cdr (y))
3459 {
3460 if (y == NIL)
3461 Error_0 ("not enough arguments");
3462 else
3463 new_slot_in_env (SCHEME_A_ car (x), car (y));
3464 }
3465
3466 if (x == NIL)
3467 {
3468 /*--
3469 * if (y != NIL) {
3470 * Error_0("too many arguments");
3471 * }
3472 */
3473 }
3474 else if (is_symbol (x))
3475 new_slot_in_env (SCHEME_A_ x, y);
3476 else
3477 Error_1 ("syntax error in closure: not a symbol:", x);
3478
3479 SCHEME_V->code = cdr (closure_code (SCHEME_V->code));
3480 SCHEME_V->args = NIL;
3481 s_goto (OP_BEGIN);
3482 }
3483 else if (is_continuation (SCHEME_V->code)) /* CONTINUATION */
3484 {
3485 ss_set_cont (SCHEME_A_ cont_dump (SCHEME_V->code));
3486 s_return (args != NIL ? car (args) : NIL);
3487 }
3488 else
3489 Error_0 ("illegal function");
3490
3491 case OP_DOMACRO: /* do macro */
3492 SCHEME_V->code = SCHEME_V->value;
3493 s_goto (OP_EVAL);
3494
3495 #if 1
3496
3497 case OP_LAMBDA: /* lambda */
3498 /* If the hook is defined, apply it to SCHEME_V->code, otherwise
3499 set SCHEME_V->value fall thru */
3500 {
3501 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->COMPILE_HOOK, 1);
3502
3503 if (f != NIL)
3504 {
3505 s_save (SCHEME_A_ OP_LAMBDA1, args, SCHEME_V->code);
3506 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3507 SCHEME_V->code = slot_value_in_env (f);
3508 s_goto (OP_APPLY);
3509 }
3510
3511 SCHEME_V->value = SCHEME_V->code;
3512 /* Fallthru */
3513 }
3514
3515 case OP_LAMBDA1:
3516 s_return (mk_closure (SCHEME_A_ SCHEME_V->value, SCHEME_V->envir));
3517
3518 #else
3519
3520 case OP_LAMBDA: /* lambda */
3521 s_return (mk_closure (SCHEME_A_ SCHEME_V->code, SCHEME_V->envir));
3522
3523 #endif
3524
3525 case OP_MKCLOSURE: /* make-closure */
3526 x = car (args);
3527
3528 if (car (x) == SCHEME_V->LAMBDA)
3529 x = cdr (x);
3530
3531 if (cdr (args) == NIL)
3532 y = SCHEME_V->envir;
3533 else
3534 y = cadr (args);
3535
3536 s_return (mk_closure (SCHEME_A_ x, y));
3537
3538 case OP_QUOTE: /* quote */
3539 s_return (car (SCHEME_V->code));
3540
3541 case OP_DEF0: /* define */
3542 if (is_immutable (car (SCHEME_V->code)))
3543 Error_1 ("define: unable to alter immutable", car (SCHEME_V->code));
3544
3545 if (is_pair (car (SCHEME_V->code)))
3546 {
3547 x = caar (SCHEME_V->code);
3548 SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3549 }
3550 else
3551 {
3552 x = car (SCHEME_V->code);
3553 SCHEME_V->code = cadr (SCHEME_V->code);
3554 }
3555
3556 if (!is_symbol (x))
3557 Error_0 ("variable is not a symbol");
3558
3559 s_save (SCHEME_A_ OP_DEF1, NIL, x);
3560 s_goto (OP_EVAL);
3561
3562 case OP_DEF1: /* define */
3563 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3564
3565 if (x != NIL)
3566 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3567 else
3568 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3569
3570 s_return (SCHEME_V->code);
3571
3572
3573 case OP_DEFP: /* defined? */
3574 x = SCHEME_V->envir;
3575
3576 if (cdr (args) != NIL)
3577 x = cadr (args);
3578
3579 s_retbool (find_slot_in_env (SCHEME_A_ x, car (args), 1) != NIL);
3580
3581 case OP_SET0: /* set! */
3582 if (is_immutable (car (SCHEME_V->code)))
3583 Error_1 ("set!: unable to alter immutable variable", car (SCHEME_V->code));
3584
3585 s_save (SCHEME_A_ OP_SET1, NIL, car (SCHEME_V->code));
3586 SCHEME_V->code = cadr (SCHEME_V->code);
3587 s_goto (OP_EVAL);
3588
3589 case OP_SET1: /* set! */
3590 y = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3591
3592 if (y != NIL)
3593 {
3594 set_slot_in_env (SCHEME_A_ y, SCHEME_V->value);
3595 s_return (SCHEME_V->value);
3596 }
3597 else
3598 Error_1 ("set!: unbound variable:", SCHEME_V->code);
3599
3600
3601 case OP_BEGIN: /* begin */
3602 if (!is_pair (SCHEME_V->code))
3603 s_return (SCHEME_V->code);
3604
3605 if (cdr (SCHEME_V->code) != NIL)
3606 s_save (SCHEME_A_ OP_BEGIN, NIL, cdr (SCHEME_V->code));
3607
3608 SCHEME_V->code = car (SCHEME_V->code);
3609 s_goto (OP_EVAL);
3610
3611 case OP_IF0: /* if */
3612 s_save (SCHEME_A_ OP_IF1, NIL, cdr (SCHEME_V->code));
3613 SCHEME_V->code = car (SCHEME_V->code);
3614 s_goto (OP_EVAL);
3615
3616 case OP_IF1: /* if */
3617 if (is_true (SCHEME_V->value))
3618 SCHEME_V->code = car (SCHEME_V->code);
3619 else
3620 SCHEME_V->code = cadr (SCHEME_V->code); /* (if #f 1) ==> () because * car(NIL) = NIL */
3621 s_goto (OP_EVAL);
3622
3623 case OP_LET0: /* let */
3624 SCHEME_V->args = NIL;
3625 SCHEME_V->value = SCHEME_V->code;
3626 SCHEME_V->code = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code);
3627 s_goto (OP_LET1);
3628
3629 case OP_LET1: /* let (calculate parameters) */
3630 args = cons (SCHEME_V->value, args);
3631
3632 if (is_pair (SCHEME_V->code)) /* continue */
3633 {
3634 if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3635 Error_1 ("Bad syntax of binding spec in let :", car (SCHEME_V->code));
3636
3637 s_save (SCHEME_A_ OP_LET1, args, cdr (SCHEME_V->code));
3638 SCHEME_V->code = cadar (SCHEME_V->code);
3639 SCHEME_V->args = NIL;
3640 s_goto (OP_EVAL);
3641 }
3642 else /* end */
3643 {
3644 args = reverse_in_place (SCHEME_A_ NIL, args);
3645 SCHEME_V->code = car (args);
3646 SCHEME_V->args = cdr (args);
3647 s_goto (OP_LET2);
3648 }
3649
3650 case OP_LET2: /* let */
3651 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3652
3653 for (x = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code), y = args;
3654 y != NIL; x = cdr (x), y = cdr (y))
3655 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3656
3657 if (is_symbol (car (SCHEME_V->code))) /* named let */
3658 {
3659 for (x = cadr (SCHEME_V->code), args = NIL; x != NIL; x = cdr (x))
3660 {
3661 if (!is_pair (x))
3662 Error_1 ("Bad syntax of binding in let :", x);
3663
3664 if (!is_list (SCHEME_A_ car (x)))
3665 Error_1 ("Bad syntax of binding in let :", car (x));
3666
3667 args = cons (caar (x), args);
3668 }
3669
3670 x = mk_closure (SCHEME_A_ cons (reverse_in_place (SCHEME_A_ NIL, args), cddr (SCHEME_V->code)),
3671 SCHEME_V->envir);
3672 new_slot_in_env (SCHEME_A_ car (SCHEME_V->code), x);
3673 SCHEME_V->code = cddr (SCHEME_V->code);
3674 }
3675 else
3676 {
3677 SCHEME_V->code = cdr (SCHEME_V->code);
3678 }
3679
3680 SCHEME_V->args = NIL;
3681 s_goto (OP_BEGIN);
3682
3683 case OP_LET0AST: /* let* */
3684 if (car (SCHEME_V->code) == NIL)
3685 {
3686 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3687 SCHEME_V->code = cdr (SCHEME_V->code);
3688 s_goto (OP_BEGIN);
3689 }
3690
3691 if (!is_pair (car (SCHEME_V->code)) || !is_pair (caar (SCHEME_V->code)) || !is_pair (cdaar (SCHEME_V->code)))
3692 Error_1 ("Bad syntax of binding spec in let* :", car (SCHEME_V->code));
3693
3694 s_save (SCHEME_A_ OP_LET1AST, cdr (SCHEME_V->code), car (SCHEME_V->code));
3695 SCHEME_V->code = car (cdaar (SCHEME_V->code));
3696 s_goto (OP_EVAL);
3697
3698 case OP_LET1AST: /* let* (make new frame) */
3699 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3700 s_goto (OP_LET2AST);
3701
3702 case OP_LET2AST: /* let* (calculate parameters) */
3703 new_slot_in_env (SCHEME_A_ caar (SCHEME_V->code), SCHEME_V->value);
3704 SCHEME_V->code = cdr (SCHEME_V->code);
3705
3706 if (is_pair (SCHEME_V->code)) /* continue */
3707 {
3708 s_save (SCHEME_A_ OP_LET2AST, args, SCHEME_V->code);
3709 SCHEME_V->code = cadar (SCHEME_V->code);
3710 SCHEME_V->args = NIL;
3711 s_goto (OP_EVAL);
3712 }
3713 else /* end */
3714 {
3715 SCHEME_V->code = args;
3716 SCHEME_V->args = NIL;
3717 s_goto (OP_BEGIN);
3718 }
3719
3720 case OP_LET0REC: /* letrec */
3721 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3722 SCHEME_V->args = NIL;
3723 SCHEME_V->value = SCHEME_V->code;
3724 SCHEME_V->code = car (SCHEME_V->code);
3725 s_goto (OP_LET1REC);
3726
3727 case OP_LET1REC: /* letrec (calculate parameters) */
3728 args = cons (SCHEME_V->value, args);
3729
3730 if (is_pair (SCHEME_V->code)) /* continue */
3731 {
3732 if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3733 Error_1 ("Bad syntax of binding spec in letrec :", car (SCHEME_V->code));
3734
3735 s_save (SCHEME_A_ OP_LET1REC, args, cdr (SCHEME_V->code));
3736 SCHEME_V->code = cadar (SCHEME_V->code);
3737 SCHEME_V->args = NIL;
3738 s_goto (OP_EVAL);
3739 }
3740 else /* end */
3741 {
3742 args = reverse_in_place (SCHEME_A_ NIL, args);
3743 SCHEME_V->code = car (args);
3744 SCHEME_V->args = cdr (args);
3745 s_goto (OP_LET2REC);
3746 }
3747
3748 case OP_LET2REC: /* letrec */
3749 for (x = car (SCHEME_V->code), y = args; y != NIL; x = cdr (x), y = cdr (y))
3750 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3751
3752 SCHEME_V->code = cdr (SCHEME_V->code);
3753 SCHEME_V->args = NIL;
3754 s_goto (OP_BEGIN);
3755
3756 case OP_COND0: /* cond */
3757 if (!is_pair (SCHEME_V->code))
3758 Error_0 ("syntax error in cond");
3759
3760 s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3761 SCHEME_V->code = caar (SCHEME_V->code);
3762 s_goto (OP_EVAL);
3763
3764 case OP_COND1: /* cond */
3765 if (is_true (SCHEME_V->value))
3766 {
3767 if ((SCHEME_V->code = cdar (SCHEME_V->code)) == NIL)
3768 s_return (SCHEME_V->value);
3769
3770 if (car (SCHEME_V->code) == SCHEME_V->FEED_TO)
3771 {
3772 if (!is_pair (cdr (SCHEME_V->code)))
3773 Error_0 ("syntax error in cond");
3774
3775 x = cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL));
3776 SCHEME_V->code = cons (cadr (SCHEME_V->code), cons (x, NIL));
3777 s_goto (OP_EVAL);
3778 }
3779
3780 s_goto (OP_BEGIN);
3781 }
3782 else
3783 {
3784 if ((SCHEME_V->code = cdr (SCHEME_V->code)) == NIL)
3785 s_return (NIL);
3786 else
3787 {
3788 s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3789 SCHEME_V->code = caar (SCHEME_V->code);
3790 s_goto (OP_EVAL);
3791 }
3792 }
3793
3794 case OP_DELAY: /* delay */
3795 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3796 set_typeflag (x, T_PROMISE);
3797 s_return (x);
3798
3799 case OP_AND0: /* and */
3800 if (SCHEME_V->code == NIL)
3801 s_return (S_T);
3802
3803 s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3804 SCHEME_V->code = car (SCHEME_V->code);
3805 s_goto (OP_EVAL);
3806
3807 case OP_AND1: /* and */
3808 if (is_false (SCHEME_V->value))
3809 s_return (SCHEME_V->value);
3810 else if (SCHEME_V->code == NIL)
3811 s_return (SCHEME_V->value);
3812 else
3813 {
3814 s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3815 SCHEME_V->code = car (SCHEME_V->code);
3816 s_goto (OP_EVAL);
3817 }
3818
3819 case OP_OR0: /* or */
3820 if (SCHEME_V->code == NIL)
3821 s_return (S_F);
3822
3823 s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3824 SCHEME_V->code = car (SCHEME_V->code);
3825 s_goto (OP_EVAL);
3826
3827 case OP_OR1: /* or */
3828 if (is_true (SCHEME_V->value))
3829 s_return (SCHEME_V->value);
3830 else if (SCHEME_V->code == NIL)
3831 s_return (SCHEME_V->value);
3832 else
3833 {
3834 s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3835 SCHEME_V->code = car (SCHEME_V->code);
3836 s_goto (OP_EVAL);
3837 }
3838
3839 case OP_C0STREAM: /* cons-stream */
3840 s_save (SCHEME_A_ OP_C1STREAM, NIL, cdr (SCHEME_V->code));
3841 SCHEME_V->code = car (SCHEME_V->code);
3842 s_goto (OP_EVAL);
3843
3844 case OP_C1STREAM: /* cons-stream */
3845 SCHEME_V->args = SCHEME_V->value; /* save SCHEME_V->value to register args for gc */
3846 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3847 set_typeflag (x, T_PROMISE);
3848 s_return (cons (args, x));
3849
3850 case OP_MACRO0: /* macro */
3851 if (is_pair (car (SCHEME_V->code)))
3852 {
3853 x = caar (SCHEME_V->code);
3854 SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3855 }
3856 else
3857 {
3858 x = car (SCHEME_V->code);
3859 SCHEME_V->code = cadr (SCHEME_V->code);
3860 }
3861
3862 if (!is_symbol (x))
3863 Error_0 ("variable is not a symbol");
3864
3865 s_save (SCHEME_A_ OP_MACRO1, NIL, x);
3866 s_goto (OP_EVAL);
3867
3868 case OP_MACRO1: /* macro */
3869 set_typeflag (SCHEME_V->value, T_MACRO);
3870 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3871
3872 if (x != NIL)
3873 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3874 else
3875 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3876
3877 s_return (SCHEME_V->code);
3878
3879 case OP_CASE0: /* case */
3880 s_save (SCHEME_A_ OP_CASE1, NIL, cdr (SCHEME_V->code));
3881 SCHEME_V->code = car (SCHEME_V->code);
3882 s_goto (OP_EVAL);
3883
3884 case OP_CASE1: /* case */
3885 for (x = SCHEME_V->code; x != NIL; x = cdr (x))
3886 {
3887 if (!is_pair (y = caar (x)))
3888 break;
3889
3890 for (; y != NIL; y = cdr (y))
3891 if (eqv (car (y), SCHEME_V->value))
3892 break;
3893
3894 if (y != NIL)
3895 break;
3896 }
3897
3898 if (x != NIL)
3899 {
3900 if (is_pair (caar (x)))
3901 {
3902 SCHEME_V->code = cdar (x);
3903 s_goto (OP_BEGIN);
3904 }
3905 else /* else */
3906 {
3907 s_save (SCHEME_A_ OP_CASE2, NIL, cdar (x));
3908 SCHEME_V->code = caar (x);
3909 s_goto (OP_EVAL);
3910 }
3911 }
3912 else
3913 s_return (NIL);
3914
3915 case OP_CASE2: /* case */
3916 if (is_true (SCHEME_V->value))
3917 s_goto (OP_BEGIN);
3918 else
3919 s_return (NIL);
3920
3921 case OP_PAPPLY: /* apply */
3922 SCHEME_V->code = car (args);
3923 SCHEME_V->args = list_star (SCHEME_A_ cdr (args));
3924 /*SCHEME_V->args = cadr(args); */
3925 s_goto (OP_APPLY);
3926
3927 case OP_PEVAL: /* eval */
3928 if (cdr (args) != NIL)
3929 SCHEME_V->envir = cadr (args);
3930
3931 SCHEME_V->code = car (args);
3932 s_goto (OP_EVAL);
3933
3934 case OP_CONTINUATION: /* call-with-current-continuation */
3935 SCHEME_V->code = car (args);
3936 SCHEME_V->args = cons (mk_continuation (SCHEME_A_ ss_get_cont (SCHEME_A)), NIL);
3937 s_goto (OP_APPLY);
3938 }
3939
3940 if (USE_ERROR_CHECKING) abort ();
3941 }
3942
3943 static int
3944 opexe_1 (SCHEME_P_ enum scheme_opcodes op)
3945 {
3946 pointer args = SCHEME_V->args;
3947 pointer x = car (args);
3948 num v;
3949
3950 switch (op)
3951 {
3952 #if USE_MATH
3953 case OP_INEX2EX: /* inexact->exact */
3954 {
3955 if (is_integer (x))
3956 s_return (x);
3957
3958 RVALUE r = rvalue_unchecked (x);
3959
3960 if (r == (RVALUE)(IVALUE)r)
3961 s_return (mk_integer (SCHEME_A_ rvalue_unchecked (x)));
3962 else
3963 Error_1 ("inexact->exact: not integral:", x);
3964 }
3965
3966 case OP_EXP: s_return (mk_real (SCHEME_A_ exp (rvalue (x))));
3967 case OP_LOG: s_return (mk_real (SCHEME_A_ log (rvalue (x))));
3968 case OP_SIN: s_return (mk_real (SCHEME_A_ sin (rvalue (x))));
3969 case OP_COS: s_return (mk_real (SCHEME_A_ cos (rvalue (x))));
3970 case OP_TAN: s_return (mk_real (SCHEME_A_ tan (rvalue (x))));
3971 case OP_ASIN: s_return (mk_real (SCHEME_A_ asin (rvalue (x))));
3972 case OP_ACOS: s_return (mk_real (SCHEME_A_ acos (rvalue (x))));
3973
3974 case OP_ATAN:
3975 if (cdr (args) == NIL)
3976 s_return (mk_real (SCHEME_A_ atan (rvalue (x))));
3977 else
3978 {
3979 pointer y = cadr (args);
3980 s_return (mk_real (SCHEME_A_ atan2 (rvalue (x), rvalue (y))));
3981 }
3982
3983 case OP_SQRT:
3984 s_return (mk_real (SCHEME_A_ sqrt (rvalue (x))));
3985
3986 case OP_EXPT:
3987 {
3988 RVALUE result;
3989 int real_result = 1;
3990 pointer y = cadr (args);
3991
3992 if (is_integer (x) && is_integer (y))
3993 real_result = 0;
3994
3995 /* This 'if' is an R5RS compatibility fix. */
3996 /* NOTE: Remove this 'if' fix for R6RS. */
3997 if (rvalue (x) == 0 && rvalue (y) < 0)
3998 result = 0;
3999 else
4000 result = pow (rvalue (x), rvalue (y));
4001
4002 /* Before returning integer result make sure we can. */
4003 /* If the test fails, result is too big for integer. */
4004 if (!real_result)
4005 {
4006 long result_as_long = result;
4007
4008 if (result != result_as_long)
4009 real_result = 1;
4010 }
4011
4012 if (real_result)
4013 s_return (mk_real (SCHEME_A_ result));
4014 else
4015 s_return (mk_integer (SCHEME_A_ result));
4016 }
4017
4018 case OP_FLOOR: s_return (mk_real (SCHEME_A_ floor (rvalue (x))));
4019 case OP_CEILING: s_return (mk_real (SCHEME_A_ ceil (rvalue (x))));
4020
4021 case OP_TRUNCATE:
4022 {
4023 RVALUE n = rvalue (x);
4024 s_return (mk_real (SCHEME_A_ n > 0 ? floor (n) : ceil (n)));
4025 }
4026
4027 case OP_ROUND:
4028 if (is_integer (x))
4029 s_return (x);
4030
4031 s_return (mk_real (SCHEME_A_ round_per_R5RS (rvalue (x))));
4032 #endif
4033
4034 case OP_ADD: /* + */
4035 v = num_zero;
4036
4037 for (x = args; x != NIL; x = cdr (x))
4038 v = num_op (NUM_ADD, v, nvalue (car (x)));
4039
4040 s_return (mk_number (SCHEME_A_ v));
4041
4042 case OP_MUL: /* * */
4043 v = num_one;
4044
4045 for (x = args; x != NIL; x = cdr (x))
4046 v = num_op (NUM_MUL, v, nvalue (car (x)));
4047
4048 s_return (mk_number (SCHEME_A_ v));
4049
4050 case OP_SUB: /* - */
4051 if (cdr (args) == NIL)
4052 {
4053 x = args;
4054 v = num_zero;
4055 }
4056 else
4057 {
4058 x = cdr (args);
4059 v = nvalue (car (args));
4060 }
4061
4062 for (; x != NIL; x = cdr (x))
4063 v = num_op (NUM_SUB, v, nvalue (car (x)));
4064
4065 s_return (mk_number (SCHEME_A_ v));
4066
4067 case OP_DIV: /* / */
4068 if (cdr (args) == NIL)
4069 {
4070 x = args;
4071 v = num_one;
4072 }
4073 else
4074 {
4075 x = cdr (args);
4076 v = nvalue (car (args));
4077 }
4078
4079 for (; x != NIL; x = cdr (x))
4080 if (!is_zero_rvalue (rvalue (car (x))))
4081 v = num_div (v, nvalue (car (x)));
4082 else
4083 Error_0 ("/: division by zero");
4084
4085 s_return (mk_number (SCHEME_A_ v));
4086
4087 case OP_INTDIV: /* quotient */
4088 if (cdr (args) == NIL)
4089 {
4090 x = args;
4091 v = num_one;
4092 }
4093 else
4094 {
4095 x = cdr (args);
4096 v = nvalue (car (args));
4097 }
4098
4099 for (; x != NIL; x = cdr (x))
4100 {
4101 if (ivalue (car (x)) != 0)
4102 v = num_op (NUM_INTDIV, v, nvalue (car (x)));
4103 else
4104 Error_0 ("quotient: division by zero");
4105 }
4106
4107 s_return (mk_number (SCHEME_A_ v));
4108
4109 case OP_REM: /* remainder */
4110 v = nvalue (x);
4111
4112 if (ivalue (cadr (args)) != 0)
4113 v = num_rem (v, nvalue (cadr (args)));
4114 else
4115 Error_0 ("remainder: division by zero");
4116
4117 s_return (mk_number (SCHEME_A_ v));
4118
4119 case OP_MOD: /* modulo */
4120 v = nvalue (x);
4121
4122 if (ivalue (cadr (args)) != 0)
4123 v = num_mod (v, nvalue (cadr (args)));
4124 else
4125 Error_0 ("modulo: division by zero");
4126
4127 s_return (mk_number (SCHEME_A_ v));
4128
4129 case OP_CAR: /* car */
4130 s_return (caar (args));
4131
4132 case OP_CDR: /* cdr */
4133 s_return (cdar (args));
4134
4135 case OP_CONS: /* cons */
4136 set_cdr (args, cadr (args));
4137 s_return (args);
4138
4139 case OP_SETCAR: /* set-car! */
4140 if (!is_immutable (x))
4141 {
4142 set_car (x, cadr (args));
4143 s_return (car (args));
4144 }
4145 else
4146 Error_0 ("set-car!: unable to alter immutable pair");
4147
4148 case OP_SETCDR: /* set-cdr! */
4149 if (!is_immutable (x))
4150 {
4151 set_cdr (x, cadr (args));
4152 s_return (car (args));
4153 }
4154 else
4155 Error_0 ("set-cdr!: unable to alter immutable pair");
4156
4157 case OP_CHAR2INT: /* char->integer */
4158 s_return (mk_integer (SCHEME_A_ ivalue_unchecked (x)));
4159
4160 case OP_INT2CHAR: /* integer->char */
4161 s_return (mk_character (SCHEME_A_ ivalue_unchecked (x)));
4162
4163 case OP_CHARUPCASE:
4164 {
4165 unsigned char c = ivalue_unchecked (x);
4166 c = toupper (c);
4167 s_return (mk_character (SCHEME_A_ c));
4168 }
4169
4170 case OP_CHARDNCASE:
4171 {
4172 unsigned char c = ivalue_unchecked (x);
4173 c = tolower (c);
4174 s_return (mk_character (SCHEME_A_ c));
4175 }
4176
4177 case OP_STR2SYM: /* string->symbol */
4178 s_return (mk_symbol (SCHEME_A_ strvalue (x)));
4179
4180 case OP_STR2ATOM: /* string->atom */
4181 {
4182 char *s = strvalue (x);
4183 long pf = 0;
4184
4185 if (cdr (args) != NIL)
4186 {
4187 /* we know cadr(args) is a natural number */
4188 /* see if it is 2, 8, 10, or 16, or error */
4189 pf = ivalue_unchecked (cadr (args));
4190
4191 if (pf == 16 || pf == 10 || pf == 8 || pf == 2)
4192 {
4193 /* base is OK */
4194 }
4195 else
4196 pf = -1;
4197 }
4198
4199 if (pf < 0)
4200 Error_1 ("string->atom: bad base:", cadr (args));
4201 else if (*s == '#') /* no use of base! */
4202 s_return (mk_sharp_const (SCHEME_A_ s + 1));
4203 else
4204 {
4205 if (pf == 0 || pf == 10)
4206 s_return (mk_atom (SCHEME_A_ s));
4207 else
4208 {
4209 char *ep;
4210 long iv = strtol (s, &ep, (int) pf);
4211
4212 if (*ep == 0)
4213 s_return (mk_integer (SCHEME_A_ iv));
4214 else
4215 s_return (S_F);
4216 }
4217 }
4218 }
4219
4220 case OP_SYM2STR: /* symbol->string */
4221 x = mk_string (SCHEME_A_ symname (x));
4222 setimmutable (x);
4223 s_return (x);
4224
4225 case OP_ATOM2STR: /* atom->string */
4226 {
4227 long pf = 0;
4228
4229 if (cdr (args) != NIL)
4230 {
4231 /* we know cadr(args) is a natural number */
4232 /* see if it is 2, 8, 10, or 16, or error */
4233 pf = ivalue_unchecked (cadr (args));
4234
4235 if (is_number (x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2))
4236 {
4237 /* base is OK */
4238 }
4239 else
4240 pf = -1;
4241 }
4242
4243 if (pf < 0)
4244 Error_1 ("atom->string: bad base:", cadr (args));
4245 else if (is_number (x) || is_character (x) || is_string (x) || is_symbol (x))
4246 {
4247 char *p;
4248 int len;
4249
4250 atom2str (SCHEME_A_ x, pf, &p, &len);
4251 s_return (mk_counted_string (SCHEME_A_ p, len));
4252 }
4253 else
4254 Error_1 ("atom->string: not an atom:", x);
4255 }
4256
4257 case OP_MKSTRING: /* make-string */
4258 {
4259 int fill = cdr (args) != NIL ? charvalue (cadr (args)) : ' ';
4260 int len = ivalue_unchecked (x);
4261
4262 s_return (mk_empty_string (SCHEME_A_ len, fill));
4263 }
4264
4265 case OP_STRLEN: /* string-length */
4266 s_return (mk_integer (SCHEME_A_ strlength (x)));
4267
4268 case OP_STRREF: /* string-ref */
4269 {
4270 char *str = strvalue (x);
4271 int index = ivalue_unchecked (cadr (args));
4272
4273 if (index >= strlength (x))
4274 Error_1 ("string-ref: out of bounds:", cadr (args));
4275
4276 s_return (mk_character (SCHEME_A_ ((unsigned char *)str)[index]));
4277 }
4278
4279 case OP_STRSET: /* string-set! */
4280 {
4281 char *str = strvalue (x);
4282 int index = ivalue_unchecked (cadr (args));
4283 int c;
4284
4285 if (is_immutable (x))
4286 Error_1 ("string-set!: unable to alter immutable string:", x);
4287
4288 if (index >= strlength (x))
4289 Error_1 ("string-set!: out of bounds:", cadr (args));
4290
4291 c = charvalue (caddr (args));
4292
4293 str[index] = c;
4294 s_return (car (args));
4295 }
4296
4297 case OP_STRAPPEND: /* string-append */
4298 {
4299 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4300 int len = 0;
4301 pointer newstr;
4302 char *pos;
4303
4304 /* compute needed length for new string */
4305 for (x = args; x != NIL; x = cdr (x))
4306 len += strlength (car (x));
4307
4308 newstr = mk_empty_string (SCHEME_A_ len, ' ');
4309
4310 /* store the contents of the argument strings into the new string */
4311 for (pos = strvalue (newstr), x = args; x != NIL; pos += strlength (car (x)), x = cdr (x))
4312 memcpy (pos, strvalue (car (x)), strlength (car (x)));
4313
4314 s_return (newstr);
4315 }
4316
4317 case OP_SUBSTR: /* substring */
4318 {
4319 char *str = strvalue (x);
4320 int index0 = ivalue_unchecked (cadr (args));
4321 int index1;
4322 int len;
4323
4324 if (index0 > strlength (x))
4325 Error_1 ("substring: start out of bounds:", cadr (args));
4326
4327 if (cddr (args) != NIL)
4328 {
4329 index1 = ivalue_unchecked (caddr (args));
4330
4331 if (index1 > strlength (x) || index1 < index0)
4332 Error_1 ("substring: end out of bounds:", caddr (args));
4333 }
4334 else
4335 index1 = strlength (x);
4336
4337 len = index1 - index0;
4338 x = mk_empty_string (SCHEME_A_ len, ' ');
4339 memcpy (strvalue (x), str + index0, len);
4340 strvalue (x)[len] = 0;
4341
4342 s_return (x);
4343 }
4344
4345 case OP_VECTOR: /* vector */
4346 {
4347 int i;
4348 pointer vec;
4349 int len = list_length (SCHEME_A_ args);
4350
4351 if (len < 0)
4352 Error_1 ("vector: not a proper list:", args);
4353
4354 vec = mk_vector (SCHEME_A_ len);
4355
4356 #if USE_ERROR_CHECKING
4357 if (SCHEME_V->no_memory)
4358 s_return (S_SINK);
4359 #endif
4360
4361 for (x = args, i = 0; is_pair (x); x = cdr (x), i++)
4362 vector_set (vec, i, car (x));
4363
4364 s_return (vec);
4365 }
4366
4367 case OP_MKVECTOR: /* make-vector */
4368 {
4369 pointer fill = NIL;
4370 pointer vec;
4371 int len = ivalue_unchecked (x);
4372
4373 if (cdr (args) != NIL)
4374 fill = cadr (args);
4375
4376 vec = mk_vector (SCHEME_A_ len);
4377
4378 #if USE_ERROR_CHECKING
4379 if (SCHEME_V->no_memory)
4380 s_return (S_SINK);
4381 #endif
4382
4383 if (fill != NIL)
4384 fill_vector (vec, 0, fill);
4385
4386 s_return (vec);
4387 }
4388
4389 case OP_VECLEN: /* vector-length */
4390 s_return (mk_integer (SCHEME_A_ veclength (x)));
4391
4392 case OP_VECREF: /* vector-ref */
4393 {
4394 int index = ivalue_unchecked (cadr (args));
4395
4396 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4397 Error_1 ("vector-ref: out of bounds:", cadr (args));
4398
4399 s_return (vector_get (x, index));
4400 }
4401
4402 case OP_VECSET: /* vector-set! */
4403 {
4404 int index = ivalue_unchecked (cadr (args));
4405
4406 if (is_immutable (x))
4407 Error_1 ("vector-set!: unable to alter immutable vector:", x);
4408
4409 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4410 Error_1 ("vector-set!: out of bounds:", cadr (args));
4411
4412 vector_set (x, index, caddr (args));
4413 s_return (x);
4414 }
4415 }
4416
4417 if (USE_ERROR_CHECKING) abort ();
4418 }
4419
4420 static int
4421 opexe_2 (SCHEME_P_ enum scheme_opcodes op)
4422 {
4423 pointer x = SCHEME_V->args;
4424
4425 for (;;)
4426 {
4427 num v = nvalue (car (x));
4428 x = cdr (x);
4429
4430 if (x == NIL)
4431 break;
4432
4433 int r = num_cmp (v, nvalue (car (x)));
4434
4435 switch (op)
4436 {
4437 case OP_NUMEQ: r = r == 0; break;
4438 case OP_LESS: r = r < 0; break;
4439 case OP_GRE: r = r > 0; break;
4440 case OP_LEQ: r = r <= 0; break;
4441 case OP_GEQ: r = r >= 0; break;
4442 }
4443
4444 if (!r)
4445 s_return (S_F);
4446 }
4447
4448 s_return (S_T);
4449 }
4450
4451 static int
4452 opexe_3 (SCHEME_P_ enum scheme_opcodes op)
4453 {
4454 pointer args = SCHEME_V->args;
4455 pointer a = car (args);
4456 pointer d = cdr (args);
4457 int r;
4458
4459 switch (op)
4460 {
4461 case OP_NOT: /* not */ r = is_false (a) ; break;
4462 case OP_BOOLP: /* boolean? */ r = a == S_F || a == S_T; break;
4463 case OP_EOFOBJP: /* eof-object? */ r = a == S_EOF ; break;
4464 case OP_NULLP: /* null? */ r = a == NIL ; break;
4465 case OP_SYMBOLP: /* symbol? */ r = is_symbol (a) ; break;
4466 case OP_NUMBERP: /* number? */ r = is_number (a) ; break;
4467 case OP_STRINGP: /* string? */ r = is_string (a) ; break;
4468 case OP_INTEGERP: /* integer? */ r = is_integer (a) ; break;
4469 case OP_REALP: /* real? */ r = is_number (a) ; break; /* all numbers are real */
4470 case OP_CHARP: /* char? */ r = is_character (a) ; break;
4471
4472 #if USE_CHAR_CLASSIFIERS
4473 case OP_CHARAP: /* char-alphabetic? */ r = Cisalpha (ivalue_unchecked (a)); break;
4474 case OP_CHARNP: /* char-numeric? */ r = Cisdigit (ivalue_unchecked (a)); break;
4475 case OP_CHARWP: /* char-whitespace? */ r = Cisspace (ivalue_unchecked (a)); break;
4476 case OP_CHARUP: /* char-upper-case? */ r = Cisupper (ivalue_unchecked (a)); break;
4477 case OP_CHARLP: /* char-lower-case? */ r = Cislower (ivalue_unchecked (a)); break;
4478 #endif
4479
4480 #if USE_PORTS
4481 case OP_PORTP: /* port? */ r = is_port (a) ; break;
4482 case OP_INPORTP: /* input-port? */ r = is_inport (a) ; break;
4483 case OP_OUTPORTP: /* output-port? */ r = is_outport (a); break;
4484 #endif
4485
4486 case OP_PROCP: /* procedure? */
4487
4488 /*--
4489 * continuation should be procedure by the example
4490 * (call-with-current-continuation procedure?) ==> #t
4491 * in R^3 report sec. 6.9
4492 */
4493 r = is_proc (a) || is_closure (a) || is_continuation (a) || is_foreign (a);
4494 break;
4495
4496 case OP_PAIRP: /* pair? */ r = is_pair (a) ; break;
4497 case OP_LISTP: /* list? */ r = list_length (SCHEME_A_ a) >= 0; break;
4498 case OP_ENVP: /* environment? */ r = is_environment (a) ; break;
4499 case OP_VECTORP: /* vector? */ r = is_vector (a) ; break;
4500 case OP_EQ: /* eq? */ r = a == cadr (args) ; break;
4501 case OP_EQV: /* eqv? */ r = eqv (a, cadr (args)) ; break;
4502 }
4503
4504 s_retbool (r);
4505 }
4506
4507 static int
4508 opexe_4 (SCHEME_P_ enum scheme_opcodes op)
4509 {
4510 pointer args = SCHEME_V->args;
4511 pointer a = car (args);
4512 pointer x, y;
4513
4514 switch (op)
4515 {
4516 case OP_FORCE: /* force */
4517 SCHEME_V->code = a;
4518
4519 if (is_promise (SCHEME_V->code))
4520 {
4521 /* Should change type to closure here */
4522 s_save (SCHEME_A_ OP_SAVE_FORCED, NIL, SCHEME_V->code);
4523 SCHEME_V->args = NIL;
4524 s_goto (OP_APPLY);
4525 }
4526 else
4527 s_return (SCHEME_V->code);
4528
4529 case OP_SAVE_FORCED: /* Save forced value replacing promise */
4530 memcpy (SCHEME_V->code, SCHEME_V->value, sizeof (struct cell));
4531 s_return (SCHEME_V->value);
4532
4533 #if USE_PORTS
4534
4535 case OP_WRITE: /* write */
4536 case OP_DISPLAY: /* display */
4537 case OP_WRITE_CHAR: /* write-char */
4538 if (is_pair (cdr (SCHEME_V->args)))
4539 {
4540 if (cadr (SCHEME_V->args) != SCHEME_V->outport)
4541 {
4542 x = cons (SCHEME_V->outport, NIL);
4543 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4544 SCHEME_V->outport = cadr (SCHEME_V->args);
4545 }
4546 }
4547
4548 SCHEME_V->args = a;
4549
4550 if (op == OP_WRITE)
4551 SCHEME_V->print_flag = 1;
4552 else
4553 SCHEME_V->print_flag = 0;
4554
4555 s_goto (OP_P0LIST);
4556
4557 case OP_NEWLINE: /* newline */
4558 if (is_pair (args))
4559 {
4560 if (a != SCHEME_V->outport)
4561 {
4562 x = cons (SCHEME_V->outport, NIL);
4563 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4564 SCHEME_V->outport = a;
4565 }
4566 }
4567
4568 putstr (SCHEME_A_ "\n");
4569 s_return (S_T);
4570 #endif
4571
4572 case OP_ERR0: /* error */
4573 SCHEME_V->retcode = -1;
4574
4575 if (!is_string (a))
4576 {
4577 args = cons (mk_string (SCHEME_A_ " -- "), args);
4578 setimmutable (car (args));
4579 }
4580
4581 putstr (SCHEME_A_ "Error: ");
4582 putstr (SCHEME_A_ strvalue (car (args)));
4583 SCHEME_V->args = cdr (args);
4584 s_goto (OP_ERR1);
4585
4586 case OP_ERR1: /* error */
4587 putstr (SCHEME_A_ " ");
4588
4589 if (args != NIL)
4590 {
4591 s_save (SCHEME_A_ OP_ERR1, cdr (args), NIL);
4592 SCHEME_V->args = a;
4593 SCHEME_V->print_flag = 1;
4594 s_goto (OP_P0LIST);
4595 }
4596 else
4597 {
4598 putstr (SCHEME_A_ "\n");
4599
4600 if (SCHEME_V->interactive_repl)
4601 s_goto (OP_T0LVL);
4602 else
4603 return -1;
4604 }
4605
4606 case OP_REVERSE: /* reverse */
4607 s_return (reverse (SCHEME_A_ a));
4608
4609 case OP_LIST_STAR: /* list* */
4610 s_return (list_star (SCHEME_A_ SCHEME_V->args));
4611
4612 case OP_APPEND: /* append */
4613 x = NIL;
4614 y = args;
4615
4616 if (y == x)
4617 s_return (x);
4618
4619 /* cdr() in the while condition is not a typo. If car() */
4620 /* is used (append '() 'a) will return the wrong result. */
4621 while (cdr (y) != NIL)
4622 {
4623 x = revappend (SCHEME_A_ x, car (y));
4624 y = cdr (y);
4625
4626 if (x == S_F)
4627 Error_0 ("non-list argument to append");
4628 }
4629
4630 s_return (reverse_in_place (SCHEME_A_ car (y), x));
4631
4632 #if USE_PLIST
4633
4634 case OP_PUT: /* put */
4635 if (!hasprop (a) || !hasprop (cadr (args)))
4636 Error_0 ("illegal use of put");
4637
4638 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4639 {
4640 if (caar (x) == y)
4641 break;
4642 }
4643
4644 if (x != NIL)
4645 cdar (x) = caddr (args);
4646 else
4647 symprop (a) = cons (cons (y, caddr (args)), symprop (a));
4648
4649 s_return (S_T);
4650
4651 case OP_GET: /* get */
4652 if (!hasprop (a) || !hasprop (cadr (args)))
4653 Error_0 ("illegal use of get");
4654
4655 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4656 if (caar (x) == y)
4657 break;
4658
4659 if (x != NIL)
4660 s_return (cdar (x));
4661 else
4662 s_return (NIL);
4663
4664 #endif /* USE_PLIST */
4665
4666 case OP_QUIT: /* quit */
4667 if (is_pair (args))
4668 SCHEME_V->retcode = ivalue (a);
4669
4670 return -1;
4671
4672 case OP_GC: /* gc */
4673 gc (SCHEME_A_ NIL, NIL);
4674 s_return (S_T);
4675
4676 case OP_GCVERB: /* gc-verbose */
4677 {
4678 int was = SCHEME_V->gc_verbose;
4679
4680 SCHEME_V->gc_verbose = (a != S_F);
4681 s_retbool (was);
4682 }
4683
4684 case OP_NEWSEGMENT: /* new-segment */
4685 if (!is_pair (args) || !is_number (a))
4686 Error_0 ("new-segment: argument must be a number");
4687
4688 alloc_cellseg (SCHEME_A_ ivalue (a));
4689
4690 s_return (S_T);
4691
4692 case OP_OBLIST: /* oblist */
4693 s_return (oblist_all_symbols (SCHEME_A));
4694
4695 #if USE_PORTS
4696
4697 case OP_CURR_INPORT: /* current-input-port */
4698 s_return (SCHEME_V->inport);
4699
4700 case OP_CURR_OUTPORT: /* current-output-port */
4701 s_return (SCHEME_V->outport);
4702
4703 case OP_OPEN_INFILE: /* open-input-file */
4704 case OP_OPEN_OUTFILE: /* open-output-file */
4705 case OP_OPEN_INOUTFILE: /* open-input-output-file */
4706 {
4707 int prop = 0;
4708 pointer p;
4709
4710 switch (op)
4711 {
4712 case OP_OPEN_INFILE:
4713 prop = port_input;
4714 break;
4715
4716 case OP_OPEN_OUTFILE:
4717 prop = port_output;
4718 break;
4719
4720 case OP_OPEN_INOUTFILE:
4721 prop = port_input | port_output;
4722 break;
4723 }
4724
4725 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
4726
4727 s_return (p == NIL ? S_F : p);
4728 }
4729
4730 # if USE_STRING_PORTS
4731
4732 case OP_OPEN_INSTRING: /* open-input-string */
4733 case OP_OPEN_INOUTSTRING: /* open-input-output-string */
4734 {
4735 int prop = 0;
4736 pointer p;
4737
4738 switch (op)
4739 {
4740 case OP_OPEN_INSTRING:
4741 prop = port_input;
4742 break;
4743
4744 case OP_OPEN_INOUTSTRING:
4745 prop = port_input | port_output;
4746 break;
4747 }
4748
4749 p = port_from_string (SCHEME_A_ strvalue (a),
4750 strvalue (a) + strlength (a), prop);
4751
4752 s_return (p == NIL ? S_F : p);
4753 }
4754
4755 case OP_OPEN_OUTSTRING: /* open-output-string */
4756 {
4757 pointer p;
4758
4759 if (a == NIL)
4760 p = port_from_scratch (SCHEME_A);
4761 else
4762 p = port_from_string (SCHEME_A_ strvalue (a),
4763 strvalue (a) + strlength (a), port_output);
4764
4765 s_return (p == NIL ? S_F : p);
4766 }
4767
4768 case OP_GET_OUTSTRING: /* get-output-string */
4769 {
4770 port *p;
4771
4772 if ((p = a->object.port)->kind & port_string)
4773 {
4774 off_t size;
4775 char *str;
4776
4777 size = p->rep.string.curr - p->rep.string.start + 1;
4778 str = malloc (size);
4779
4780 if (str != NULL)
4781 {
4782 pointer s;
4783
4784 memcpy (str, p->rep.string.start, size - 1);
4785 str[size - 1] = '\0';
4786 s = mk_string (SCHEME_A_ str);
4787 free (str);
4788 s_return (s);
4789 }
4790 }
4791
4792 s_return (S_F);
4793 }
4794
4795 # endif
4796
4797 case OP_CLOSE_INPORT: /* close-input-port */
4798 port_close (SCHEME_A_ a, port_input);
4799 s_return (S_T);
4800
4801 case OP_CLOSE_OUTPORT: /* close-output-port */
4802 port_close (SCHEME_A_ a, port_output);
4803 s_return (S_T);
4804 #endif
4805
4806 case OP_INT_ENV: /* interaction-environment */
4807 s_return (SCHEME_V->global_env);
4808
4809 case OP_CURR_ENV: /* current-environment */
4810 s_return (SCHEME_V->envir);
4811
4812 }
4813
4814 if (USE_ERROR_CHECKING) abort ();
4815 }
4816
4817 static int
4818 opexe_5 (SCHEME_P_ enum scheme_opcodes op)
4819 {
4820 pointer args = SCHEME_V->args;
4821 pointer x;
4822
4823 if (SCHEME_V->nesting != 0)
4824 {
4825 int n = SCHEME_V->nesting;
4826
4827 SCHEME_V->nesting = 0;
4828 SCHEME_V->retcode = -1;
4829 Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
4830 }
4831
4832 switch (op)
4833 {
4834 /* ========== reading part ========== */
4835 #if USE_PORTS
4836 case OP_READ:
4837 if (!is_pair (args))
4838 s_goto (OP_READ_INTERNAL);
4839
4840 if (!is_inport (car (args)))
4841 Error_1 ("read: not an input port:", car (args));
4842
4843 if (car (args) == SCHEME_V->inport)
4844 s_goto (OP_READ_INTERNAL);
4845
4846 x = SCHEME_V->inport;
4847 SCHEME_V->inport = car (args);
4848 x = cons (x, NIL);
4849 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4850 s_goto (OP_READ_INTERNAL);
4851
4852 case OP_READ_CHAR: /* read-char */
4853 case OP_PEEK_CHAR: /* peek-char */
4854 {
4855 int c;
4856
4857 if (is_pair (args))
4858 {
4859 if (car (args) != SCHEME_V->inport)
4860 {
4861 x = SCHEME_V->inport;
4862 x = cons (x, NIL);
4863 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4864 SCHEME_V->inport = car (args);
4865 }
4866 }
4867
4868 c = inchar (SCHEME_A);
4869
4870 if (c == EOF)
4871 s_return (S_EOF);
4872
4873 if (SCHEME_V->op == OP_PEEK_CHAR)
4874 backchar (SCHEME_A_ c);
4875
4876 s_return (mk_character (SCHEME_A_ c));
4877 }
4878
4879 case OP_CHAR_READY: /* char-ready? */
4880 {
4881 pointer p = SCHEME_V->inport;
4882 int res;
4883
4884 if (is_pair (args))
4885 p = car (args);
4886
4887 res = p->object.port->kind & port_string;
4888
4889 s_retbool (res);
4890 }
4891
4892 case OP_SET_INPORT: /* set-input-port */
4893 SCHEME_V->inport = car (args);
4894 s_return (SCHEME_V->value);
4895
4896 case OP_SET_OUTPORT: /* set-output-port */
4897 SCHEME_V->outport = car (args);
4898 s_return (SCHEME_V->value);
4899 #endif
4900
4901 case OP_RDSEXPR:
4902 switch (SCHEME_V->tok)
4903 {
4904 case TOK_EOF:
4905 s_return (S_EOF);
4906 /* NOTREACHED */
4907
4908 case TOK_VEC:
4909 s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
4910 /* fall through */
4911
4912 case TOK_LPAREN:
4913 SCHEME_V->tok = token (SCHEME_A);
4914
4915 if (SCHEME_V->tok == TOK_RPAREN)
4916 s_return (NIL);
4917 else if (SCHEME_V->tok == TOK_DOT)
4918 Error_0 ("syntax error: illegal dot expression");
4919 else
4920 {
4921 SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
4922 s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
4923 s_goto (OP_RDSEXPR);
4924 }
4925
4926 case TOK_QUOTE:
4927 s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
4928 SCHEME_V->tok = token (SCHEME_A);
4929 s_goto (OP_RDSEXPR);
4930
4931 case TOK_BQUOTE:
4932 SCHEME_V->tok = token (SCHEME_A);
4933
4934 if (SCHEME_V->tok == TOK_VEC)
4935 {
4936 s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
4937 SCHEME_V->tok = TOK_LPAREN;
4938 s_goto (OP_RDSEXPR);
4939 }
4940 else
4941 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
4942
4943 s_goto (OP_RDSEXPR);
4944
4945 case TOK_COMMA:
4946 s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
4947 SCHEME_V->tok = token (SCHEME_A);
4948 s_goto (OP_RDSEXPR);
4949
4950 case TOK_ATMARK:
4951 s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
4952 SCHEME_V->tok = token (SCHEME_A);
4953 s_goto (OP_RDSEXPR);
4954
4955 case TOK_ATOM:
4956 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS)));
4957
4958 case TOK_DQUOTE:
4959 x = readstrexp (SCHEME_A);
4960
4961 if (x == S_F)
4962 Error_0 ("Error reading string");
4963
4964 setimmutable (x);
4965 s_return (x);
4966
4967 case TOK_SHARP:
4968 {
4969 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
4970
4971 if (f == NIL)
4972 Error_0 ("undefined sharp expression");
4973 else
4974 {
4975 SCHEME_V->code = cons (slot_value_in_env (f), NIL);
4976 s_goto (OP_EVAL);
4977 }
4978 }
4979
4980 case TOK_SHARP_CONST:
4981 if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS))) == NIL)
4982 Error_0 ("undefined sharp expression");
4983 else
4984 s_return (x);
4985
4986 default:
4987 Error_0 ("syntax error: illegal token");
4988 }
4989
4990 break;
4991
4992 case OP_RDLIST:
4993 SCHEME_V->args = cons (SCHEME_V->value, args);
4994 SCHEME_V->tok = token (SCHEME_A);
4995
4996 switch (SCHEME_V->tok)
4997 {
4998 case TOK_EOF:
4999 s_return (S_EOF);
5000
5001 case TOK_RPAREN:
5002 {
5003 int c = inchar (SCHEME_A);
5004
5005 if (c != '\n')
5006 backchar (SCHEME_A_ c);
5007 #if SHOW_ERROR_LINE
5008 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5009 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5010 #endif
5011
5012 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5013 s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5014 }
5015
5016 case TOK_DOT:
5017 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5018 SCHEME_V->tok = token (SCHEME_A);
5019 s_goto (OP_RDSEXPR);
5020
5021 default:
5022 s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5023 s_goto (OP_RDSEXPR);
5024 }
5025
5026 case OP_RDDOT:
5027 if (token (SCHEME_A) != TOK_RPAREN)
5028 Error_0 ("syntax error: illegal dot expression");
5029
5030 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5031 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5032
5033 case OP_RDQUOTE:
5034 s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5035
5036 case OP_RDQQUOTE:
5037 s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5038
5039 case OP_RDQQUOTEVEC:
5040 s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5041 cons (mk_symbol (SCHEME_A_ "vector"),
5042 cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5043
5044 case OP_RDUNQUOTE:
5045 s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5046
5047 case OP_RDUQTSP:
5048 s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5049
5050 case OP_RDVEC:
5051 /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5052 s_goto(OP_EVAL); Cannot be quoted */
5053 /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5054 s_return(x); Cannot be part of pairs */
5055 /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5056 SCHEME_V->args=SCHEME_V->value;
5057 s_goto(OP_APPLY); */
5058 SCHEME_V->args = SCHEME_V->value;
5059 s_goto (OP_VECTOR);
5060
5061 /* ========== printing part ========== */
5062 case OP_P0LIST:
5063 if (is_vector (args))
5064 {
5065 putstr (SCHEME_A_ "#(");
5066 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5067 s_goto (OP_PVECFROM);
5068 }
5069 else if (is_environment (args))
5070 {
5071 putstr (SCHEME_A_ "#<ENVIRONMENT>");
5072 s_return (S_T);
5073 }
5074 else if (!is_pair (args))
5075 {
5076 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5077 s_return (S_T);
5078 }
5079 else
5080 {
5081 pointer a = car (args);
5082 pointer b = cdr (args);
5083 int ok_abbr = ok_abbrev (b);
5084 SCHEME_V->args = car (b);
5085
5086 if (a == SCHEME_V->QUOTE && ok_abbr)
5087 putstr (SCHEME_A_ "'");
5088 else if (a == SCHEME_V->QQUOTE && ok_abbr)
5089 putstr (SCHEME_A_ "`");
5090 else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5091 putstr (SCHEME_A_ ",");
5092 else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5093 putstr (SCHEME_A_ ",@");
5094 else
5095 {
5096 putstr (SCHEME_A_ "(");
5097 s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5098 SCHEME_V->args = a;
5099 }
5100
5101 s_goto (OP_P0LIST);
5102 }
5103
5104 case OP_P1LIST:
5105 if (is_pair (args))
5106 {
5107 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5108 putstr (SCHEME_A_ " ");
5109 SCHEME_V->args = car (args);
5110 s_goto (OP_P0LIST);
5111 }
5112 else if (is_vector (args))
5113 {
5114 s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5115 putstr (SCHEME_A_ " . ");
5116 s_goto (OP_P0LIST);
5117 }
5118 else
5119 {
5120 if (args != NIL)
5121 {
5122 putstr (SCHEME_A_ " . ");
5123 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5124 }
5125
5126 putstr (SCHEME_A_ ")");
5127 s_return (S_T);
5128 }
5129
5130 case OP_PVECFROM:
5131 {
5132 int i = ivalue_unchecked (cdr (args));
5133 pointer vec = car (args);
5134 int len = veclength (vec);
5135
5136 if (i == len)
5137 {
5138 putstr (SCHEME_A_ ")");
5139 s_return (S_T);
5140 }
5141 else
5142 {
5143 pointer elem = vector_get (vec, i);
5144
5145 ivalue_unchecked (cdr (args)) = i + 1;
5146 s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5147 SCHEME_V->args = elem;
5148
5149 if (i > 0)
5150 putstr (SCHEME_A_ " ");
5151
5152 s_goto (OP_P0LIST);
5153 }
5154 }
5155 }
5156
5157 if (USE_ERROR_CHECKING) abort ();
5158 }
5159
5160 static int
5161 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5162 {
5163 pointer args = SCHEME_V->args;
5164 pointer a = car (args);
5165 pointer x, y;
5166
5167 switch (op)
5168 {
5169 case OP_LIST_LENGTH: /* length *//* a.k */
5170 {
5171 long v = list_length (SCHEME_A_ a);
5172
5173 if (v < 0)
5174 Error_1 ("length: not a list:", a);
5175
5176 s_return (mk_integer (SCHEME_A_ v));
5177 }
5178
5179 case OP_ASSQ: /* assq *//* a.k */
5180 x = a;
5181
5182 for (y = cadr (args); is_pair (y); y = cdr (y))
5183 {
5184 if (!is_pair (car (y)))
5185 Error_0 ("unable to handle non pair element");
5186
5187 if (x == caar (y))
5188 break;
5189 }
5190
5191 if (is_pair (y))
5192 s_return (car (y));
5193 else
5194 s_return (S_F);
5195
5196
5197 case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5198 SCHEME_V->args = a;
5199
5200 if (SCHEME_V->args == NIL)
5201 s_return (S_F);
5202 else if (is_closure (SCHEME_V->args))
5203 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5204 else if (is_macro (SCHEME_V->args))
5205 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5206 else
5207 s_return (S_F);
5208
5209 case OP_CLOSUREP: /* closure? */
5210 /*
5211 * Note, macro object is also a closure.
5212 * Therefore, (closure? <#MACRO>) ==> #t
5213 */
5214 s_retbool (is_closure (a));
5215
5216 case OP_MACROP: /* macro? */
5217 s_retbool (is_macro (a));
5218 }
5219
5220 if (USE_ERROR_CHECKING) abort ();
5221 }
5222
5223 /* dispatch functions (opexe_x) return new opcode, or 0 for same opcode, or -1 to stop */
5224 typedef int (*dispatch_func)(SCHEME_P_ enum scheme_opcodes);
5225
5226 typedef int (*test_predicate)(pointer);
5227 static int
5228 tst_any (pointer p)
5229 {
5230 return 1;
5231 }
5232
5233 static int
5234 tst_inonneg (pointer p)
5235 {
5236 return is_integer (p) && ivalue_unchecked (p) >= 0;
5237 }
5238
5239 static int
5240 tst_is_list (SCHEME_P_ pointer p)
5241 {
5242 return p == NIL || is_pair (p);
5243 }
5244
5245 /* Correspond carefully with following defines! */
5246 static struct
5247 {
5248 test_predicate fct;
5249 const char *kind;
5250 } tests[] = {
5251 { tst_any , 0 },
5252 { is_string , "string" },
5253 { is_symbol , "symbol" },
5254 { is_port , "port" },
5255 { is_inport , "input port" },
5256 { is_outport , "output port" },
5257 { is_environment, "environment" },
5258 { is_pair , "pair" },
5259 { 0 , "pair or '()" },
5260 { is_character , "character" },
5261 { is_vector , "vector" },
5262 { is_number , "number" },
5263 { is_integer , "integer" },
5264 { tst_inonneg , "non-negative integer" }
5265 };
5266
5267 #define TST_NONE 0 /* TST_NONE used for built-ins, 0 for internal ops */
5268 #define TST_ANY "\001"
5269 #define TST_STRING "\002"
5270 #define TST_SYMBOL "\003"
5271 #define TST_PORT "\004"
5272 #define TST_INPORT "\005"
5273 #define TST_OUTPORT "\006"
5274 #define TST_ENVIRONMENT "\007"
5275 #define TST_PAIR "\010"
5276 #define TST_LIST "\011"
5277 #define TST_CHAR "\012"
5278 #define TST_VECTOR "\013"
5279 #define TST_NUMBER "\014"
5280 #define TST_INTEGER "\015"
5281 #define TST_NATURAL "\016"
5282
5283 #define INF_ARG 0xff
5284 #define UNNAMED_OP ""
5285
5286 static const char opnames[] =
5287 #define OP_DEF(func,name,minarity,maxarity,argtest,op) name "\x00"
5288 #include "opdefines.h"
5289 #undef OP_DEF
5290 ;
5291
5292 static const char *
5293 opname (int idx)
5294 {
5295 const char *name = opnames;
5296
5297 /* should do this at compile time, but would require external program, right? */
5298 while (idx--)
5299 name += strlen (name) + 1;
5300
5301 return *name ? name : "ILLEGAL";
5302 }
5303
5304 static const char *
5305 procname (pointer x)
5306 {
5307 return opname (procnum (x));
5308 }
5309
5310 typedef struct
5311 {
5312 uint8_t func;
5313 /*dispatch_func func;*//*TODO: maybe optionally keep the pointer, for speed? */
5314 uint8_t builtin;
5315 #if USE_ERROR_CHECKING
5316 uint8_t min_arity;
5317 uint8_t max_arity;
5318 char arg_tests_encoding[3];
5319 #endif
5320 } op_code_info;
5321
5322 static const op_code_info dispatch_table[] = {
5323 #if USE_ERROR_CHECKING
5324 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1, minarity, maxarity, argtest },
5325 #else
5326 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1 },
5327 #endif
5328 #include "opdefines.h"
5329 #undef OP_DEF
5330 {0}
5331 };
5332
5333 /* kernel of this interpreter */
5334 static void ecb_hot
5335 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5336 {
5337 SCHEME_V->op = op;
5338
5339 for (;;)
5340 {
5341 const op_code_info *pcd = dispatch_table + SCHEME_V->op;
5342
5343 #if USE_ERROR_CHECKING
5344 if (pcd->builtin) /* if built-in function, check arguments */
5345 {
5346 char msg[STRBUFFSIZE];
5347 int n = list_length (SCHEME_A_ SCHEME_V->args);
5348
5349 /* Check number of arguments */
5350 if (ecb_expect_false (n < pcd->min_arity))
5351 {
5352 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5353 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5354 xError_1 (SCHEME_A_ msg, 0);
5355 continue;
5356 }
5357 else if (ecb_expect_false (n > pcd->max_arity && pcd->max_arity != INF_ARG))
5358 {
5359 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5360 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5361 xError_1 (SCHEME_A_ msg, 0);
5362 continue;
5363 }
5364 else
5365 {
5366 if (*pcd->arg_tests_encoding) /* literal 0 and TST_NONE treated the same */
5367 {
5368 int i = 0;
5369 int j;
5370 const char *t = pcd->arg_tests_encoding;
5371 pointer arglist = SCHEME_V->args;
5372
5373 do
5374 {
5375 pointer arg = car (arglist);
5376
5377 j = t[0];
5378
5379 /*TODO: tst_is_list has different prototype - fix if other tests acquire same prototype */
5380 if (j == TST_LIST[0])
5381 {
5382 if (!tst_is_list (SCHEME_A_ arg))
5383 break;
5384 }
5385 else
5386 {
5387 if (!tests[j - 1].fct (arg))
5388 break;
5389 }
5390
5391 if (t < pcd->arg_tests_encoding + sizeof (pcd->arg_tests_encoding) - 1 && t[1]) /* last test is replicated as necessary */
5392 t++;
5393
5394 arglist = cdr (arglist);
5395 i++;
5396 }
5397 while (i < n);
5398
5399 if (i < n)
5400 {
5401 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", opname (SCHEME_V->op), i + 1, tests[j].kind);
5402 xError_1 (SCHEME_A_ msg, 0);
5403 continue;
5404 }
5405 }
5406 }
5407 }
5408 #endif
5409
5410 ok_to_freely_gc (SCHEME_A);
5411
5412 static const dispatch_func dispatch_funcs[] = {
5413 opexe_0,
5414 opexe_1,
5415 opexe_2,
5416 opexe_3,
5417 opexe_4,
5418 opexe_5,
5419 opexe_6,
5420 };
5421
5422 if (ecb_expect_false (dispatch_funcs [pcd->func] (SCHEME_A_ SCHEME_V->op) != 0))
5423 return;
5424
5425 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5426 {
5427 xwrstr ("No memory!\n");
5428 return;
5429 }
5430 }
5431 }
5432
5433 /* ========== Initialization of internal keywords ========== */
5434
5435 static void
5436 assign_syntax (SCHEME_P_ const char *name)
5437 {
5438 pointer x = oblist_add_by_name (SCHEME_A_ name);
5439 set_typeflag (x, typeflag (x) | T_SYNTAX);
5440 }
5441
5442 static void
5443 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5444 {
5445 pointer x = mk_symbol (SCHEME_A_ name);
5446 pointer y = mk_proc (SCHEME_A_ op);
5447 new_slot_in_env (SCHEME_A_ x, y);
5448 }
5449
5450 static pointer
5451 mk_proc (SCHEME_P_ enum scheme_opcodes op)
5452 {
5453 pointer y = get_cell (SCHEME_A_ NIL, NIL);
5454 set_typeflag (y, (T_PROC | T_ATOM));
5455 ivalue_unchecked (y) = op;
5456 return y;
5457 }
5458
5459 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5460 static int
5461 syntaxnum (pointer p)
5462 {
5463 const char *s = strvalue (car (p));
5464
5465 switch (strlength (car (p)))
5466 {
5467 case 2:
5468 if (s[0] == 'i')
5469 return OP_IF0; /* if */
5470 else
5471 return OP_OR0; /* or */
5472
5473 case 3:
5474 if (s[0] == 'a')
5475 return OP_AND0; /* and */
5476 else
5477 return OP_LET0; /* let */
5478
5479 case 4:
5480 switch (s[3])
5481 {
5482 case 'e':
5483 return OP_CASE0; /* case */
5484
5485 case 'd':
5486 return OP_COND0; /* cond */
5487
5488 case '*':
5489 return OP_LET0AST;/* let* */
5490
5491 default:
5492 return OP_SET0; /* set! */
5493 }
5494
5495 case 5:
5496 switch (s[2])
5497 {
5498 case 'g':
5499 return OP_BEGIN; /* begin */
5500
5501 case 'l':
5502 return OP_DELAY; /* delay */
5503
5504 case 'c':
5505 return OP_MACRO0; /* macro */
5506
5507 default:
5508 return OP_QUOTE; /* quote */
5509 }
5510
5511 case 6:
5512 switch (s[2])
5513 {
5514 case 'm':
5515 return OP_LAMBDA; /* lambda */
5516
5517 case 'f':
5518 return OP_DEF0; /* define */
5519
5520 default:
5521 return OP_LET0REC;/* letrec */
5522 }
5523
5524 default:
5525 return OP_C0STREAM; /* cons-stream */
5526 }
5527 }
5528
5529 #if USE_MULTIPLICITY
5530 ecb_cold scheme *
5531 scheme_init_new ()
5532 {
5533 scheme *sc = malloc (sizeof (scheme));
5534
5535 if (!scheme_init (SCHEME_A))
5536 {
5537 free (SCHEME_A);
5538 return 0;
5539 }
5540 else
5541 return sc;
5542 }
5543 #endif
5544
5545 ecb_cold int
5546 scheme_init (SCHEME_P)
5547 {
5548 int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5549 pointer x;
5550
5551 num_set_fixnum (num_zero, 1);
5552 num_set_ivalue (num_zero, 0);
5553 num_set_fixnum (num_one, 1);
5554 num_set_ivalue (num_one, 1);
5555
5556 #if USE_INTERFACE
5557 SCHEME_V->vptr = &vtbl;
5558 #endif
5559 SCHEME_V->gensym_cnt = 0;
5560 SCHEME_V->last_cell_seg = -1;
5561 SCHEME_V->free_cell = NIL;
5562 SCHEME_V->fcells = 0;
5563 SCHEME_V->no_memory = 0;
5564 SCHEME_V->inport = NIL;
5565 SCHEME_V->outport = NIL;
5566 SCHEME_V->save_inport = NIL;
5567 SCHEME_V->loadport = NIL;
5568 SCHEME_V->nesting = 0;
5569 SCHEME_V->interactive_repl = 0;
5570
5571 if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5572 {
5573 #if USE_ERROR_CHECKING
5574 SCHEME_V->no_memory = 1;
5575 return 0;
5576 #endif
5577 }
5578
5579 SCHEME_V->gc_verbose = 0;
5580 dump_stack_initialize (SCHEME_A);
5581 SCHEME_V->code = NIL;
5582 SCHEME_V->args = NIL;
5583 SCHEME_V->envir = NIL;
5584 SCHEME_V->tracing = 0;
5585
5586 /* init NIL */
5587 set_typeflag (NIL, T_ATOM | T_MARK);
5588 set_car (NIL, NIL);
5589 set_cdr (NIL, NIL);
5590 /* init T */
5591 set_typeflag (S_T, T_ATOM | T_MARK);
5592 set_car (S_T, S_T);
5593 set_cdr (S_T, S_T);
5594 /* init F */
5595 set_typeflag (S_F, T_ATOM | T_MARK);
5596 set_car (S_F, S_F);
5597 set_cdr (S_F, S_F);
5598 /* init EOF_OBJ */
5599 set_typeflag (S_EOF, T_ATOM | T_MARK);
5600 set_car (S_EOF, S_EOF);
5601 set_cdr (S_EOF, S_EOF);
5602 /* init sink */
5603 set_typeflag (S_SINK, T_PAIR | T_MARK);
5604 set_car (S_SINK, NIL);
5605
5606 /* init c_nest */
5607 SCHEME_V->c_nest = NIL;
5608
5609 SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5610 /* init global_env */
5611 new_frame_in_env (SCHEME_A_ NIL);
5612 SCHEME_V->global_env = SCHEME_V->envir;
5613 /* init else */
5614 x = mk_symbol (SCHEME_A_ "else");
5615 new_slot_in_env (SCHEME_A_ x, S_T);
5616
5617 {
5618 static const char *syntax_names[] = {
5619 "lambda", "quote", "define", "if", "begin", "set!",
5620 "let", "let*", "letrec", "cond", "delay", "and",
5621 "or", "cons-stream", "macro", "case"
5622 };
5623
5624 for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5625 assign_syntax (SCHEME_A_ syntax_names[i]);
5626 }
5627
5628 // TODO: should iterate via strlen, to avoid n² complexity
5629 for (i = 0; i < n; i++)
5630 if (dispatch_table[i].builtin)
5631 assign_proc (SCHEME_A_ i, opname (i));
5632
5633 /* initialization of global pointers to special symbols */
5634 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5635 SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5636 SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5637 SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5638 SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5639 SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5640 SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5641 SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5642 SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5643 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5644
5645 return !SCHEME_V->no_memory;
5646 }
5647
5648 #if USE_PORTS
5649 void
5650 scheme_set_input_port_file (SCHEME_P_ int fin)
5651 {
5652 SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5653 }
5654
5655 void
5656 scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5657 {
5658 SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5659 }
5660
5661 void
5662 scheme_set_output_port_file (SCHEME_P_ int fout)
5663 {
5664 SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5665 }
5666
5667 void
5668 scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5669 {
5670 SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5671 }
5672 #endif
5673
5674 void
5675 scheme_set_external_data (SCHEME_P_ void *p)
5676 {
5677 SCHEME_V->ext_data = p;
5678 }
5679
5680 ecb_cold void
5681 scheme_deinit (SCHEME_P)
5682 {
5683 int i;
5684
5685 #if SHOW_ERROR_LINE
5686 char *fname;
5687 #endif
5688
5689 SCHEME_V->oblist = NIL;
5690 SCHEME_V->global_env = NIL;
5691 dump_stack_free (SCHEME_A);
5692 SCHEME_V->envir = NIL;
5693 SCHEME_V->code = NIL;
5694 SCHEME_V->args = NIL;
5695 SCHEME_V->value = NIL;
5696
5697 if (is_port (SCHEME_V->inport))
5698 set_typeflag (SCHEME_V->inport, T_ATOM);
5699
5700 SCHEME_V->inport = NIL;
5701 SCHEME_V->outport = NIL;
5702
5703 if (is_port (SCHEME_V->save_inport))
5704 set_typeflag (SCHEME_V->save_inport, T_ATOM);
5705
5706 SCHEME_V->save_inport = NIL;
5707
5708 if (is_port (SCHEME_V->loadport))
5709 set_typeflag (SCHEME_V->loadport, T_ATOM);
5710
5711 SCHEME_V->loadport = NIL;
5712 SCHEME_V->gc_verbose = 0;
5713 gc (SCHEME_A_ NIL, NIL);
5714
5715 for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5716 free (SCHEME_V->alloc_seg[i]);
5717
5718 #if SHOW_ERROR_LINE
5719 for (i = 0; i <= SCHEME_V->file_i; i++)
5720 {
5721 if (SCHEME_V->load_stack[i].kind & port_file)
5722 {
5723 fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5724
5725 if (fname)
5726 free (fname);
5727 }
5728 }
5729 #endif
5730 }
5731
5732 void
5733 scheme_load_file (SCHEME_P_ int fin)
5734 {
5735 scheme_load_named_file (SCHEME_A_ fin, 0);
5736 }
5737
5738 void
5739 scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5740 {
5741 dump_stack_reset (SCHEME_A);
5742 SCHEME_V->envir = SCHEME_V->global_env;
5743 SCHEME_V->file_i = 0;
5744 SCHEME_V->load_stack[0].unget = -1;
5745 SCHEME_V->load_stack[0].kind = port_input | port_file;
5746 SCHEME_V->load_stack[0].rep.stdio.file = fin;
5747 #if USE_PORTS
5748 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5749 #endif
5750 SCHEME_V->retcode = 0;
5751
5752 #if USE_PORTS
5753 if (fin == STDIN_FILENO)
5754 SCHEME_V->interactive_repl = 1;
5755 #endif
5756
5757 #if USE_PORTS
5758 #if SHOW_ERROR_LINE
5759 SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5760
5761 if (fin != STDIN_FILENO && filename)
5762 SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5763 #endif
5764 #endif
5765
5766 SCHEME_V->inport = SCHEME_V->loadport;
5767 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5768 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5769 set_typeflag (SCHEME_V->loadport, T_ATOM);
5770
5771 if (SCHEME_V->retcode == 0)
5772 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5773 }
5774
5775 void
5776 scheme_load_string (SCHEME_P_ const char *cmd)
5777 {
5778 dump_stack_reset (SCHEME_A);
5779 SCHEME_V->envir = SCHEME_V->global_env;
5780 SCHEME_V->file_i = 0;
5781 SCHEME_V->load_stack[0].kind = port_input | port_string;
5782 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
5783 SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
5784 SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
5785 #if USE_PORTS
5786 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5787 #endif
5788 SCHEME_V->retcode = 0;
5789 SCHEME_V->interactive_repl = 0;
5790 SCHEME_V->inport = SCHEME_V->loadport;
5791 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5792 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5793 set_typeflag (SCHEME_V->loadport, T_ATOM);
5794
5795 if (SCHEME_V->retcode == 0)
5796 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5797 }
5798
5799 void
5800 scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
5801 {
5802 pointer x;
5803
5804 x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
5805
5806 if (x != NIL)
5807 set_slot_in_env (SCHEME_A_ x, value);
5808 else
5809 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
5810 }
5811
5812 #if !STANDALONE
5813
5814 void
5815 scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
5816 {
5817 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
5818 }
5819
5820 void
5821 scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
5822 {
5823 int i;
5824
5825 for (i = 0; i < count; i++)
5826 scheme_register_foreign_func (SCHEME_A_ list + i);
5827 }
5828
5829 pointer
5830 scheme_apply0 (SCHEME_P_ const char *procname)
5831 {
5832 return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
5833 }
5834
5835 void
5836 save_from_C_call (SCHEME_P)
5837 {
5838 pointer saved_data = cons (car (S_SINK),
5839 cons (SCHEME_V->envir,
5840 SCHEME_V->dump));
5841
5842 /* Push */
5843 SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
5844 /* Truncate the dump stack so TS will return here when done, not
5845 directly resume pre-C-call operations. */
5846 dump_stack_reset (SCHEME_A);
5847 }
5848
5849 void
5850 restore_from_C_call (SCHEME_P)
5851 {
5852 set_car (S_SINK, caar (SCHEME_V->c_nest));
5853 SCHEME_V->envir = cadar (SCHEME_V->c_nest);
5854 SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
5855 /* Pop */
5856 SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
5857 }
5858
5859 /* "func" and "args" are assumed to be already eval'ed. */
5860 pointer
5861 scheme_call (SCHEME_P_ pointer func, pointer args)
5862 {
5863 int old_repl = SCHEME_V->interactive_repl;
5864
5865 SCHEME_V->interactive_repl = 0;
5866 save_from_C_call (SCHEME_A);
5867 SCHEME_V->envir = SCHEME_V->global_env;
5868 SCHEME_V->args = args;
5869 SCHEME_V->code = func;
5870 SCHEME_V->retcode = 0;
5871 Eval_Cycle (SCHEME_A_ OP_APPLY);
5872 SCHEME_V->interactive_repl = old_repl;
5873 restore_from_C_call (SCHEME_A);
5874 return SCHEME_V->value;
5875 }
5876
5877 pointer
5878 scheme_eval (SCHEME_P_ pointer obj)
5879 {
5880 int old_repl = SCHEME_V->interactive_repl;
5881
5882 SCHEME_V->interactive_repl = 0;
5883 save_from_C_call (SCHEME_A);
5884 SCHEME_V->args = NIL;
5885 SCHEME_V->code = obj;
5886 SCHEME_V->retcode = 0;
5887 Eval_Cycle (SCHEME_A_ OP_EVAL);
5888 SCHEME_V->interactive_repl = old_repl;
5889 restore_from_C_call (SCHEME_A);
5890 return SCHEME_V->value;
5891 }
5892
5893 #endif
5894
5895 /* ========== Main ========== */
5896
5897 #if STANDALONE
5898
5899 int
5900 main (int argc, char **argv)
5901 {
5902 # if USE_MULTIPLICITY
5903 scheme ssc;
5904 scheme *const SCHEME_V = &ssc;
5905 # else
5906 # endif
5907 int fin;
5908 char *file_name = InitFile;
5909 int retcode;
5910 int isfile = 1;
5911
5912 if (argc == 2 && strcmp (argv[1], "-?") == 0)
5913 {
5914 xwrstr ("Usage: tinyscheme -?\n");
5915 xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
5916 xwrstr ("followed by\n");
5917 xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
5918 xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5919 xwrstr ("assuming that the executable is named tinyscheme.\n");
5920 xwrstr ("Use - as filename for stdin.\n");
5921 return 1;
5922 }
5923
5924 if (!scheme_init (SCHEME_A))
5925 {
5926 xwrstr ("Could not initialize!\n");
5927 return 2;
5928 }
5929
5930 # if USE_PORTS
5931 scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
5932 scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
5933 # endif
5934
5935 argv++;
5936
5937 #if 0
5938 if (access (file_name, 0) != 0)
5939 {
5940 char *p = getenv ("TINYSCHEMEINIT");
5941
5942 if (p != 0)
5943 file_name = p;
5944 }
5945 #endif
5946
5947 do
5948 {
5949 #if USE_PORTS
5950 if (strcmp (file_name, "-") == 0)
5951 fin = STDIN_FILENO;
5952 else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
5953 {
5954 pointer args = NIL;
5955
5956 isfile = file_name[1] == '1';
5957 file_name = *argv++;
5958
5959 if (strcmp (file_name, "-") == 0)
5960 fin = STDIN_FILENO;
5961 else if (isfile)
5962 fin = open (file_name, O_RDONLY);
5963
5964 for (; *argv; argv++)
5965 {
5966 pointer value = mk_string (SCHEME_A_ * argv);
5967
5968 args = cons (value, args);
5969 }
5970
5971 args = reverse_in_place (SCHEME_A_ NIL, args);
5972 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
5973
5974 }
5975 else
5976 fin = open (file_name, O_RDONLY);
5977 #endif
5978
5979 if (isfile && fin < 0)
5980 {
5981 xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
5982 }
5983 else
5984 {
5985 if (isfile)
5986 scheme_load_named_file (SCHEME_A_ fin, file_name);
5987 else
5988 scheme_load_string (SCHEME_A_ file_name);
5989
5990 #if USE_PORTS
5991 if (!isfile || fin != STDIN_FILENO)
5992 {
5993 if (SCHEME_V->retcode != 0)
5994 {
5995 xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
5996 }
5997
5998 if (isfile)
5999 close (fin);
6000 }
6001 #endif
6002 }
6003
6004 file_name = *argv++;
6005 }
6006 while (file_name != 0);
6007
6008 if (argc == 1)
6009 scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6010
6011 retcode = SCHEME_V->retcode;
6012 scheme_deinit (SCHEME_A);
6013
6014 return retcode;
6015 }
6016
6017 #endif
6018
6019 /*
6020 Local variables:
6021 c-file-style: "k&r"
6022 End:
6023 */