ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.31
Committed: Sat Nov 28 10:54:41 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.30: +21 -10 lines
Log Message:
*** empty log message ***

File Contents

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