ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/microscheme/scheme.c
Revision: 1.8
Committed: Wed Nov 25 22:36:25 2015 UTC (8 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.7: +21 -54 lines
Log Message:
*** empty log message ***

File Contents

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