ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.4
Committed: Wed Nov 25 10:49:29 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.3: +4 -4 lines
Log Message:
*** empty log message ***

File Contents

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