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