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