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