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