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