ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/microscheme/scheme.c
Revision: 1.19
Committed: Thu Nov 26 21:36:11 2015 UTC (8 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.18: +24 -26 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 pointer opexe_0 (SCHEME_P_ enum scheme_opcodes op);
673 static pointer opexe_2 (SCHEME_P_ enum scheme_opcodes op);
674 static pointer opexe_r (SCHEME_P_ enum scheme_opcodes op);
675 static pointer opexe_3 (SCHEME_P_ enum scheme_opcodes op);
676 static pointer opexe_4 (SCHEME_P_ enum scheme_opcodes op);
677 static pointer opexe_5 (SCHEME_P_ enum scheme_opcodes op);
678 static pointer 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 pointer
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 S_T;
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 return S_T;
2995 }
2996
2997 #define Error_1(s, a) return xError_1(SCHEME_A_ USE_ERROR_CHECKING ? s : "", a)
2998 #define Error_0(s) Error_1 (s, 0)
2999
3000 /* Too small to turn into function */
3001 #define BEGIN do {
3002 #define END } while (0)
3003 #define s_goto(a) BEGIN \
3004 SCHEME_V->op = a; \
3005 return S_T; END
3006
3007 #define s_return(a) return xs_return (SCHEME_A_ a)
3008
3009 #ifndef USE_SCHEME_STACK
3010
3011 /* this structure holds all the interpreter's registers */
3012 struct dump_stack_frame
3013 {
3014 enum scheme_opcodes op;
3015 pointer args;
3016 pointer envir;
3017 pointer code;
3018 };
3019
3020 # define STACK_GROWTH 3
3021
3022 static void
3023 s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3024 {
3025 int nframes = (uintptr_t)SCHEME_V->dump;
3026 struct dump_stack_frame *next_frame;
3027
3028 /* enough room for the next frame? */
3029 if (nframes >= SCHEME_V->dump_size)
3030 {
3031 SCHEME_V->dump_size += STACK_GROWTH;
3032 SCHEME_V->dump_base = realloc (SCHEME_V->dump_base, sizeof (struct dump_stack_frame) * SCHEME_V->dump_size);
3033 }
3034
3035 next_frame = SCHEME_V->dump_base + nframes;
3036
3037 next_frame->op = op;
3038 next_frame->args = args;
3039 next_frame->envir = SCHEME_V->envir;
3040 next_frame->code = code;
3041
3042 SCHEME_V->dump = (pointer)(uintptr_t)(nframes + 1);
3043 }
3044
3045 static pointer
3046 xs_return (SCHEME_P_ pointer a)
3047 {
3048 int nframes = (uintptr_t)SCHEME_V->dump;
3049 struct dump_stack_frame *frame;
3050
3051 SCHEME_V->value = a;
3052
3053 if (nframes <= 0)
3054 return NIL;
3055
3056 frame = &SCHEME_V->dump_base[--nframes];
3057 SCHEME_V->op = frame->op;
3058 SCHEME_V->args = frame->args;
3059 SCHEME_V->envir = frame->envir;
3060 SCHEME_V->code = frame->code;
3061 SCHEME_V->dump = (pointer)(uintptr_t)nframes;
3062
3063 return S_T;
3064 }
3065
3066 static INLINE void
3067 dump_stack_reset (SCHEME_P)
3068 {
3069 /* in this implementation, SCHEME_V->dump is the number of frames on the stack */
3070 SCHEME_V->dump = (pointer)+0;
3071 }
3072
3073 static INLINE void
3074 dump_stack_initialize (SCHEME_P)
3075 {
3076 SCHEME_V->dump_size = 0;
3077 SCHEME_V->dump_base = 0;
3078 dump_stack_reset (SCHEME_A);
3079 }
3080
3081 static void
3082 dump_stack_free (SCHEME_P)
3083 {
3084 free (SCHEME_V->dump_base);
3085 SCHEME_V->dump_base = 0;
3086 SCHEME_V->dump = (pointer)0;
3087 SCHEME_V->dump_size = 0;
3088 }
3089
3090 static void
3091 dump_stack_mark (SCHEME_P)
3092 {
3093 int nframes = (uintptr_t)SCHEME_V->dump;
3094 int i;
3095
3096 for (i = 0; i < nframes; i++)
3097 {
3098 struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3099
3100 mark (frame->args);
3101 mark (frame->envir);
3102 mark (frame->code);
3103 }
3104 }
3105
3106 static pointer
3107 ss_get_cont (SCHEME_P)
3108 {
3109 int nframes = (uintptr_t)SCHEME_V->dump;
3110 int i;
3111
3112 pointer cont = NIL;
3113
3114 for (i = nframes; i--; )
3115 {
3116 struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3117
3118 cont = cons (mk_integer (SCHEME_A_ frame->op),
3119 cons (frame->args,
3120 cons (frame->envir,
3121 cons (frame->code,
3122 cont))));
3123 }
3124
3125 return cont;
3126 }
3127
3128 static void
3129 ss_set_cont (SCHEME_P_ pointer cont)
3130 {
3131 int i = 0;
3132 struct dump_stack_frame *frame = SCHEME_V->dump_base;
3133
3134 while (cont != NIL)
3135 {
3136 frame->op = ivalue (car (cont)); cont = cdr (cont);
3137 frame->args = car (cont) ; cont = cdr (cont);
3138 frame->envir = car (cont) ; cont = cdr (cont);
3139 frame->code = car (cont) ; cont = cdr (cont);
3140
3141 ++frame;
3142 ++i;
3143 }
3144
3145 SCHEME_V->dump = (pointer)(uintptr_t)i;
3146 }
3147
3148 #else
3149
3150 static INLINE void
3151 dump_stack_reset (SCHEME_P)
3152 {
3153 SCHEME_V->dump = NIL;
3154 }
3155
3156 static INLINE void
3157 dump_stack_initialize (SCHEME_P)
3158 {
3159 dump_stack_reset (SCHEME_A);
3160 }
3161
3162 static void
3163 dump_stack_free (SCHEME_P)
3164 {
3165 SCHEME_V->dump = NIL;
3166 }
3167
3168 static pointer
3169 xs_return (SCHEME_P_ pointer a)
3170 {
3171 pointer dump = SCHEME_V->dump;
3172
3173 SCHEME_V->value = a;
3174
3175 if (dump == NIL)
3176 return NIL;
3177
3178 SCHEME_V->op = ivalue (car (dump)); dump = cdr (dump);
3179 SCHEME_V->args = car (dump) ; dump = cdr (dump);
3180 SCHEME_V->envir = car (dump) ; dump = cdr (dump);
3181 SCHEME_V->code = car (dump) ; dump = cdr (dump);
3182
3183 SCHEME_V->dump = dump;
3184
3185 return S_T;
3186 }
3187
3188 static void
3189 s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3190 {
3191 SCHEME_V->dump = cons (mk_integer (SCHEME_A_ op),
3192 cons (args,
3193 cons (SCHEME_V->envir,
3194 cons (code,
3195 SCHEME_V->dump))));
3196 }
3197
3198 static void
3199 dump_stack_mark (SCHEME_P)
3200 {
3201 mark (SCHEME_V->dump);
3202 }
3203
3204 static pointer
3205 ss_get_cont (SCHEME_P)
3206 {
3207 return SCHEME_V->dump;
3208 }
3209
3210 static void
3211 ss_set_cont (SCHEME_P_ pointer cont)
3212 {
3213 SCHEME_V->dump = cont;
3214 }
3215
3216 #endif
3217
3218 #define s_retbool(tf) s_return ((tf) ? S_T : S_F)
3219
3220 static pointer
3221 opexe_0 (SCHEME_P_ enum scheme_opcodes op)
3222 {
3223 pointer args = SCHEME_V->args;
3224 pointer x, y;
3225
3226 switch (op)
3227 {
3228 case OP_LOAD: /* load */
3229 if (file_interactive (SCHEME_A))
3230 {
3231 xwrstr ("Loading "); xwrstr (strvalue (car (args))); xwrstr ("\n");
3232 //D fprintf (SCHEME_V->outport->object.port->rep.stdio.file, "Loading %s\n", strvalue (car (args)));
3233 }
3234
3235 if (!file_push (SCHEME_A_ strvalue (car (args))))
3236 Error_1 ("unable to open", car (args));
3237 else
3238 {
3239 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
3240 s_goto (OP_T0LVL);
3241 }
3242
3243 case OP_T0LVL: /* top level */
3244
3245 /* If we reached the end of file, this loop is done. */
3246 if (SCHEME_V->loadport->object.port->kind & port_saw_EOF)
3247 {
3248 if (SCHEME_V->file_i == 0)
3249 {
3250 SCHEME_V->args = NIL;
3251 s_goto (OP_QUIT);
3252 }
3253 else
3254 {
3255 file_pop (SCHEME_A);
3256 s_return (SCHEME_V->value);
3257 }
3258
3259 /* NOTREACHED */
3260 }
3261
3262 /* If interactive, be nice to user. */
3263 if (file_interactive (SCHEME_A))
3264 {
3265 SCHEME_V->envir = SCHEME_V->global_env;
3266 dump_stack_reset (SCHEME_A);
3267 putstr (SCHEME_A_ "\n");
3268 putstr (SCHEME_A_ prompt);
3269 }
3270
3271 /* Set up another iteration of REPL */
3272 SCHEME_V->nesting = 0;
3273 SCHEME_V->save_inport = SCHEME_V->inport;
3274 SCHEME_V->inport = SCHEME_V->loadport;
3275 s_save (SCHEME_A_ OP_T0LVL, NIL, NIL);
3276 s_save (SCHEME_A_ OP_VALUEPRINT, NIL, NIL);
3277 s_save (SCHEME_A_ OP_T1LVL, NIL, NIL);
3278 s_goto (OP_READ_INTERNAL);
3279
3280 case OP_T1LVL: /* top level */
3281 SCHEME_V->code = SCHEME_V->value;
3282 SCHEME_V->inport = SCHEME_V->save_inport;
3283 s_goto (OP_EVAL);
3284
3285 case OP_READ_INTERNAL: /* internal read */
3286 SCHEME_V->tok = token (SCHEME_A);
3287
3288 if (SCHEME_V->tok == TOK_EOF)
3289 s_return (S_EOF);
3290
3291 s_goto (OP_RDSEXPR);
3292
3293 case OP_GENSYM:
3294 s_return (gensym (SCHEME_A));
3295
3296 case OP_VALUEPRINT: /* print evaluation result */
3297
3298 /* OP_VALUEPRINT is always pushed, because when changing from
3299 non-interactive to interactive mode, it needs to be
3300 already on the stack */
3301 #if USE_TRACING
3302 if (SCHEME_V->tracing)
3303 putstr (SCHEME_A_ "\nGives: ");
3304 #endif
3305
3306 if (file_interactive (SCHEME_A))
3307 {
3308 SCHEME_V->print_flag = 1;
3309 SCHEME_V->args = SCHEME_V->value;
3310 s_goto (OP_P0LIST);
3311 }
3312 else
3313 s_return (SCHEME_V->value);
3314
3315 case OP_EVAL: /* main part of evaluation */
3316 #if USE_TRACING
3317 if (SCHEME_V->tracing)
3318 {
3319 /*s_save(SCHEME_A_ OP_VALUEPRINT,NIL,NIL); */
3320 s_save (SCHEME_A_ OP_REAL_EVAL, args, SCHEME_V->code);
3321 SCHEME_V->args = SCHEME_V->code;
3322 putstr (SCHEME_A_ "\nEval: ");
3323 s_goto (OP_P0LIST);
3324 }
3325
3326 /* fall through */
3327
3328 case OP_REAL_EVAL:
3329 #endif
3330 if (is_symbol (SCHEME_V->code)) /* symbol */
3331 {
3332 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3333
3334 if (x != NIL)
3335 s_return (slot_value_in_env (x));
3336 else
3337 Error_1 ("eval: unbound variable:", SCHEME_V->code);
3338 }
3339 else if (is_pair (SCHEME_V->code))
3340 {
3341 x = car (SCHEME_V->code);
3342
3343 if (is_syntax (x)) /* SYNTAX */
3344 {
3345 SCHEME_V->code = cdr (SCHEME_V->code);
3346 s_goto (syntaxnum (x));
3347 }
3348 else /* first, eval top element and eval arguments */
3349 {
3350 s_save (SCHEME_A_ OP_E0ARGS, NIL, SCHEME_V->code);
3351 /* If no macros => s_save(SCHEME_A_ OP_E1ARGS, NIL, cdr(SCHEME_V->code)); */
3352 SCHEME_V->code = x;
3353 s_goto (OP_EVAL);
3354 }
3355 }
3356 else
3357 s_return (SCHEME_V->code);
3358
3359 case OP_E0ARGS: /* eval arguments */
3360 if (is_macro (SCHEME_V->value)) /* macro expansion */
3361 {
3362 s_save (SCHEME_A_ OP_DOMACRO, NIL, NIL);
3363 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3364 SCHEME_V->code = SCHEME_V->value;
3365 s_goto (OP_APPLY);
3366 }
3367 else
3368 {
3369 SCHEME_V->code = cdr (SCHEME_V->code);
3370 s_goto (OP_E1ARGS);
3371 }
3372
3373 case OP_E1ARGS: /* eval arguments */
3374 args = cons (SCHEME_V->value, args);
3375
3376 if (is_pair (SCHEME_V->code)) /* continue */
3377 {
3378 s_save (SCHEME_A_ OP_E1ARGS, args, cdr (SCHEME_V->code));
3379 SCHEME_V->code = car (SCHEME_V->code);
3380 SCHEME_V->args = NIL;
3381 s_goto (OP_EVAL);
3382 }
3383 else /* end */
3384 {
3385 args = reverse_in_place (SCHEME_A_ NIL, args);
3386 SCHEME_V->code = car (args);
3387 SCHEME_V->args = cdr (args);
3388 s_goto (OP_APPLY);
3389 }
3390
3391 #if USE_TRACING
3392
3393 case OP_TRACING:
3394 {
3395 int tr = SCHEME_V->tracing;
3396
3397 SCHEME_V->tracing = ivalue (car (args));
3398 s_return (mk_integer (SCHEME_A_ tr));
3399 }
3400
3401 #endif
3402
3403 case OP_APPLY: /* apply 'code' to 'args' */
3404 #if USE_TRACING
3405 if (SCHEME_V->tracing)
3406 {
3407 s_save (SCHEME_A_ OP_REAL_APPLY, args, SCHEME_V->code);
3408 SCHEME_V->print_flag = 1;
3409 /* args=cons(SCHEME_V->code,args); */
3410 putstr (SCHEME_A_ "\nApply to: ");
3411 s_goto (OP_P0LIST);
3412 }
3413
3414 /* fall through */
3415
3416 case OP_REAL_APPLY:
3417 #endif
3418 if (is_proc (SCHEME_V->code))
3419 s_goto (procnum (SCHEME_V->code)); /* PROCEDURE */
3420 else if (is_foreign (SCHEME_V->code))
3421 {
3422 /* Keep nested calls from GC'ing the arglist */
3423 push_recent_alloc (SCHEME_A_ args, NIL);
3424 x = SCHEME_V->code->object.ff (SCHEME_A_ args);
3425
3426 s_return (x);
3427 }
3428 else if (is_closure (SCHEME_V->code) || is_macro (SCHEME_V->code) || is_promise (SCHEME_V->code)) /* CLOSURE */
3429 {
3430 /* Should not accept promise */
3431 /* make environment */
3432 new_frame_in_env (SCHEME_A_ closure_env (SCHEME_V->code));
3433
3434 for (x = car (closure_code (SCHEME_V->code)), y = args; is_pair (x); x = cdr (x), y = cdr (y))
3435 {
3436 if (y == NIL)
3437 Error_0 ("not enough arguments");
3438 else
3439 new_slot_in_env (SCHEME_A_ car (x), car (y));
3440 }
3441
3442 if (x == NIL)
3443 {
3444 /*--
3445 * if (y != NIL) {
3446 * Error_0("too many arguments");
3447 * }
3448 */
3449 }
3450 else if (is_symbol (x))
3451 new_slot_in_env (SCHEME_A_ x, y);
3452 else
3453 Error_1 ("syntax error in closure: not a symbol:", x);
3454
3455 SCHEME_V->code = cdr (closure_code (SCHEME_V->code));
3456 SCHEME_V->args = NIL;
3457 s_goto (OP_BEGIN);
3458 }
3459 else if (is_continuation (SCHEME_V->code)) /* CONTINUATION */
3460 {
3461 ss_set_cont (SCHEME_A_ cont_dump (SCHEME_V->code));
3462 s_return (args != NIL ? car (args) : NIL);
3463 }
3464 else
3465 Error_0 ("illegal function");
3466
3467 case OP_DOMACRO: /* do macro */
3468 SCHEME_V->code = SCHEME_V->value;
3469 s_goto (OP_EVAL);
3470
3471 #if 1
3472
3473 case OP_LAMBDA: /* lambda */
3474 /* If the hook is defined, apply it to SCHEME_V->code, otherwise
3475 set SCHEME_V->value fall thru */
3476 {
3477 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->COMPILE_HOOK, 1);
3478
3479 if (f != NIL)
3480 {
3481 s_save (SCHEME_A_ OP_LAMBDA1, args, SCHEME_V->code);
3482 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3483 SCHEME_V->code = slot_value_in_env (f);
3484 s_goto (OP_APPLY);
3485 }
3486
3487 SCHEME_V->value = SCHEME_V->code;
3488 /* Fallthru */
3489 }
3490
3491 case OP_LAMBDA1:
3492 s_return (mk_closure (SCHEME_A_ SCHEME_V->value, SCHEME_V->envir));
3493
3494 #else
3495
3496 case OP_LAMBDA: /* lambda */
3497 s_return (mk_closure (SCHEME_A_ SCHEME_V->code, SCHEME_V->envir));
3498
3499 #endif
3500
3501 case OP_MKCLOSURE: /* make-closure */
3502 x = car (args);
3503
3504 if (car (x) == SCHEME_V->LAMBDA)
3505 x = cdr (x);
3506
3507 if (cdr (args) == NIL)
3508 y = SCHEME_V->envir;
3509 else
3510 y = cadr (args);
3511
3512 s_return (mk_closure (SCHEME_A_ x, y));
3513
3514 case OP_QUOTE: /* quote */
3515 s_return (car (SCHEME_V->code));
3516
3517 case OP_DEF0: /* define */
3518 if (is_immutable (car (SCHEME_V->code)))
3519 Error_1 ("define: unable to alter immutable", car (SCHEME_V->code));
3520
3521 if (is_pair (car (SCHEME_V->code)))
3522 {
3523 x = caar (SCHEME_V->code);
3524 SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3525 }
3526 else
3527 {
3528 x = car (SCHEME_V->code);
3529 SCHEME_V->code = cadr (SCHEME_V->code);
3530 }
3531
3532 if (!is_symbol (x))
3533 Error_0 ("variable is not a symbol");
3534
3535 s_save (SCHEME_A_ OP_DEF1, NIL, x);
3536 s_goto (OP_EVAL);
3537
3538 case OP_DEF1: /* define */
3539 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3540
3541 if (x != NIL)
3542 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3543 else
3544 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3545
3546 s_return (SCHEME_V->code);
3547
3548
3549 case OP_DEFP: /* defined? */
3550 x = SCHEME_V->envir;
3551
3552 if (cdr (args) != NIL)
3553 x = cadr (args);
3554
3555 s_retbool (find_slot_in_env (SCHEME_A_ x, car (args), 1) != NIL);
3556
3557 case OP_SET0: /* set! */
3558 if (is_immutable (car (SCHEME_V->code)))
3559 Error_1 ("set!: unable to alter immutable variable", car (SCHEME_V->code));
3560
3561 s_save (SCHEME_A_ OP_SET1, NIL, car (SCHEME_V->code));
3562 SCHEME_V->code = cadr (SCHEME_V->code);
3563 s_goto (OP_EVAL);
3564
3565 case OP_SET1: /* set! */
3566 y = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3567
3568 if (y != NIL)
3569 {
3570 set_slot_in_env (SCHEME_A_ y, SCHEME_V->value);
3571 s_return (SCHEME_V->value);
3572 }
3573 else
3574 Error_1 ("set!: unbound variable:", SCHEME_V->code);
3575
3576
3577 case OP_BEGIN: /* begin */
3578 if (!is_pair (SCHEME_V->code))
3579 s_return (SCHEME_V->code);
3580
3581 if (cdr (SCHEME_V->code) != NIL)
3582 s_save (SCHEME_A_ OP_BEGIN, NIL, cdr (SCHEME_V->code));
3583
3584 SCHEME_V->code = car (SCHEME_V->code);
3585 s_goto (OP_EVAL);
3586
3587 case OP_IF0: /* if */
3588 s_save (SCHEME_A_ OP_IF1, NIL, cdr (SCHEME_V->code));
3589 SCHEME_V->code = car (SCHEME_V->code);
3590 s_goto (OP_EVAL);
3591
3592 case OP_IF1: /* if */
3593 if (is_true (SCHEME_V->value))
3594 SCHEME_V->code = car (SCHEME_V->code);
3595 else
3596 SCHEME_V->code = cadr (SCHEME_V->code); /* (if #f 1) ==> () because * car(NIL) = NIL */
3597 s_goto (OP_EVAL);
3598
3599 case OP_LET0: /* let */
3600 SCHEME_V->args = NIL;
3601 SCHEME_V->value = SCHEME_V->code;
3602 SCHEME_V->code = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code);
3603 s_goto (OP_LET1);
3604
3605 case OP_LET1: /* let (calculate parameters) */
3606 args = cons (SCHEME_V->value, args);
3607
3608 if (is_pair (SCHEME_V->code)) /* continue */
3609 {
3610 if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3611 Error_1 ("Bad syntax of binding spec in let :", car (SCHEME_V->code));
3612
3613 s_save (SCHEME_A_ OP_LET1, args, cdr (SCHEME_V->code));
3614 SCHEME_V->code = cadar (SCHEME_V->code);
3615 SCHEME_V->args = NIL;
3616 s_goto (OP_EVAL);
3617 }
3618 else /* end */
3619 {
3620 args = reverse_in_place (SCHEME_A_ NIL, args);
3621 SCHEME_V->code = car (args);
3622 SCHEME_V->args = cdr (args);
3623 s_goto (OP_LET2);
3624 }
3625
3626 case OP_LET2: /* let */
3627 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3628
3629 for (x = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code), y = args;
3630 y != NIL; x = cdr (x), y = cdr (y))
3631 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3632
3633 if (is_symbol (car (SCHEME_V->code))) /* named let */
3634 {
3635 for (x = cadr (SCHEME_V->code), args = NIL; x != NIL; x = cdr (x))
3636 {
3637 if (!is_pair (x))
3638 Error_1 ("Bad syntax of binding in let :", x);
3639
3640 if (!is_list (SCHEME_A_ car (x)))
3641 Error_1 ("Bad syntax of binding in let :", car (x));
3642
3643 args = cons (caar (x), args);
3644 }
3645
3646 x = mk_closure (SCHEME_A_ cons (reverse_in_place (SCHEME_A_ NIL, args), cddr (SCHEME_V->code)),
3647 SCHEME_V->envir);
3648 new_slot_in_env (SCHEME_A_ car (SCHEME_V->code), x);
3649 SCHEME_V->code = cddr (SCHEME_V->code);
3650 }
3651 else
3652 {
3653 SCHEME_V->code = cdr (SCHEME_V->code);
3654 }
3655
3656 SCHEME_V->args = NIL;
3657 s_goto (OP_BEGIN);
3658
3659 case OP_LET0AST: /* let* */
3660 if (car (SCHEME_V->code) == NIL)
3661 {
3662 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3663 SCHEME_V->code = cdr (SCHEME_V->code);
3664 s_goto (OP_BEGIN);
3665 }
3666
3667 if (!is_pair (car (SCHEME_V->code)) || !is_pair (caar (SCHEME_V->code)) || !is_pair (cdaar (SCHEME_V->code)))
3668 Error_1 ("Bad syntax of binding spec in let* :", car (SCHEME_V->code));
3669
3670 s_save (SCHEME_A_ OP_LET1AST, cdr (SCHEME_V->code), car (SCHEME_V->code));
3671 SCHEME_V->code = car (cdaar (SCHEME_V->code));
3672 s_goto (OP_EVAL);
3673
3674 case OP_LET1AST: /* let* (make new frame) */
3675 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3676 s_goto (OP_LET2AST);
3677
3678 case OP_LET2AST: /* let* (calculate parameters) */
3679 new_slot_in_env (SCHEME_A_ caar (SCHEME_V->code), SCHEME_V->value);
3680 SCHEME_V->code = cdr (SCHEME_V->code);
3681
3682 if (is_pair (SCHEME_V->code)) /* continue */
3683 {
3684 s_save (SCHEME_A_ OP_LET2AST, args, SCHEME_V->code);
3685 SCHEME_V->code = cadar (SCHEME_V->code);
3686 SCHEME_V->args = NIL;
3687 s_goto (OP_EVAL);
3688 }
3689 else /* end */
3690 {
3691 SCHEME_V->code = args;
3692 SCHEME_V->args = NIL;
3693 s_goto (OP_BEGIN);
3694 }
3695
3696 case OP_LET0REC: /* letrec */
3697 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3698 SCHEME_V->args = NIL;
3699 SCHEME_V->value = SCHEME_V->code;
3700 SCHEME_V->code = car (SCHEME_V->code);
3701 s_goto (OP_LET1REC);
3702
3703 case OP_LET1REC: /* letrec (calculate parameters) */
3704 args = cons (SCHEME_V->value, args);
3705
3706 if (is_pair (SCHEME_V->code)) /* continue */
3707 {
3708 if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3709 Error_1 ("Bad syntax of binding spec in letrec :", car (SCHEME_V->code));
3710
3711 s_save (SCHEME_A_ OP_LET1REC, args, cdr (SCHEME_V->code));
3712 SCHEME_V->code = cadar (SCHEME_V->code);
3713 SCHEME_V->args = NIL;
3714 s_goto (OP_EVAL);
3715 }
3716 else /* end */
3717 {
3718 args = reverse_in_place (SCHEME_A_ NIL, args);
3719 SCHEME_V->code = car (args);
3720 SCHEME_V->args = cdr (args);
3721 s_goto (OP_LET2REC);
3722 }
3723
3724 case OP_LET2REC: /* letrec */
3725 for (x = car (SCHEME_V->code), y = args; y != NIL; x = cdr (x), y = cdr (y))
3726 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3727
3728 SCHEME_V->code = cdr (SCHEME_V->code);
3729 SCHEME_V->args = NIL;
3730 s_goto (OP_BEGIN);
3731
3732 case OP_COND0: /* cond */
3733 if (!is_pair (SCHEME_V->code))
3734 Error_0 ("syntax error in cond");
3735
3736 s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3737 SCHEME_V->code = caar (SCHEME_V->code);
3738 s_goto (OP_EVAL);
3739
3740 case OP_COND1: /* cond */
3741 if (is_true (SCHEME_V->value))
3742 {
3743 if ((SCHEME_V->code = cdar (SCHEME_V->code)) == NIL)
3744 s_return (SCHEME_V->value);
3745
3746 if (car (SCHEME_V->code) == SCHEME_V->FEED_TO)
3747 {
3748 if (!is_pair (cdr (SCHEME_V->code)))
3749 Error_0 ("syntax error in cond");
3750
3751 x = cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL));
3752 SCHEME_V->code = cons (cadr (SCHEME_V->code), cons (x, NIL));
3753 s_goto (OP_EVAL);
3754 }
3755
3756 s_goto (OP_BEGIN);
3757 }
3758 else
3759 {
3760 if ((SCHEME_V->code = cdr (SCHEME_V->code)) == NIL)
3761 s_return (NIL);
3762 else
3763 {
3764 s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3765 SCHEME_V->code = caar (SCHEME_V->code);
3766 s_goto (OP_EVAL);
3767 }
3768 }
3769
3770 case OP_DELAY: /* delay */
3771 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3772 set_typeflag (x, T_PROMISE);
3773 s_return (x);
3774
3775 case OP_AND0: /* and */
3776 if (SCHEME_V->code == NIL)
3777 s_return (S_T);
3778
3779 s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3780 SCHEME_V->code = car (SCHEME_V->code);
3781 s_goto (OP_EVAL);
3782
3783 case OP_AND1: /* and */
3784 if (is_false (SCHEME_V->value))
3785 s_return (SCHEME_V->value);
3786 else if (SCHEME_V->code == NIL)
3787 s_return (SCHEME_V->value);
3788 else
3789 {
3790 s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3791 SCHEME_V->code = car (SCHEME_V->code);
3792 s_goto (OP_EVAL);
3793 }
3794
3795 case OP_OR0: /* or */
3796 if (SCHEME_V->code == NIL)
3797 s_return (S_F);
3798
3799 s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3800 SCHEME_V->code = car (SCHEME_V->code);
3801 s_goto (OP_EVAL);
3802
3803 case OP_OR1: /* or */
3804 if (is_true (SCHEME_V->value))
3805 s_return (SCHEME_V->value);
3806 else if (SCHEME_V->code == NIL)
3807 s_return (SCHEME_V->value);
3808 else
3809 {
3810 s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3811 SCHEME_V->code = car (SCHEME_V->code);
3812 s_goto (OP_EVAL);
3813 }
3814
3815 case OP_C0STREAM: /* cons-stream */
3816 s_save (SCHEME_A_ OP_C1STREAM, NIL, cdr (SCHEME_V->code));
3817 SCHEME_V->code = car (SCHEME_V->code);
3818 s_goto (OP_EVAL);
3819
3820 case OP_C1STREAM: /* cons-stream */
3821 SCHEME_V->args = SCHEME_V->value; /* save SCHEME_V->value to register args for gc */
3822 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3823 set_typeflag (x, T_PROMISE);
3824 s_return (cons (args, x));
3825
3826 case OP_MACRO0: /* macro */
3827 if (is_pair (car (SCHEME_V->code)))
3828 {
3829 x = caar (SCHEME_V->code);
3830 SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3831 }
3832 else
3833 {
3834 x = car (SCHEME_V->code);
3835 SCHEME_V->code = cadr (SCHEME_V->code);
3836 }
3837
3838 if (!is_symbol (x))
3839 Error_0 ("variable is not a symbol");
3840
3841 s_save (SCHEME_A_ OP_MACRO1, NIL, x);
3842 s_goto (OP_EVAL);
3843
3844 case OP_MACRO1: /* macro */
3845 set_typeflag (SCHEME_V->value, T_MACRO);
3846 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3847
3848 if (x != NIL)
3849 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3850 else
3851 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3852
3853 s_return (SCHEME_V->code);
3854
3855 case OP_CASE0: /* case */
3856 s_save (SCHEME_A_ OP_CASE1, NIL, cdr (SCHEME_V->code));
3857 SCHEME_V->code = car (SCHEME_V->code);
3858 s_goto (OP_EVAL);
3859
3860 case OP_CASE1: /* case */
3861 for (x = SCHEME_V->code; x != NIL; x = cdr (x))
3862 {
3863 if (!is_pair (y = caar (x)))
3864 break;
3865
3866 for (; y != NIL; y = cdr (y))
3867 if (eqv (car (y), SCHEME_V->value))
3868 break;
3869
3870 if (y != NIL)
3871 break;
3872 }
3873
3874 if (x != NIL)
3875 {
3876 if (is_pair (caar (x)))
3877 {
3878 SCHEME_V->code = cdar (x);
3879 s_goto (OP_BEGIN);
3880 }
3881 else /* else */
3882 {
3883 s_save (SCHEME_A_ OP_CASE2, NIL, cdar (x));
3884 SCHEME_V->code = caar (x);
3885 s_goto (OP_EVAL);
3886 }
3887 }
3888 else
3889 s_return (NIL);
3890
3891 case OP_CASE2: /* case */
3892 if (is_true (SCHEME_V->value))
3893 s_goto (OP_BEGIN);
3894 else
3895 s_return (NIL);
3896
3897 case OP_PAPPLY: /* apply */
3898 SCHEME_V->code = car (args);
3899 SCHEME_V->args = list_star (SCHEME_A_ cdr (args));
3900 /*SCHEME_V->args = cadr(args); */
3901 s_goto (OP_APPLY);
3902
3903 case OP_PEVAL: /* eval */
3904 if (cdr (args) != NIL)
3905 SCHEME_V->envir = cadr (args);
3906
3907 SCHEME_V->code = car (args);
3908 s_goto (OP_EVAL);
3909
3910 case OP_CONTINUATION: /* call-with-current-continuation */
3911 SCHEME_V->code = car (args);
3912 SCHEME_V->args = cons (mk_continuation (SCHEME_A_ ss_get_cont (SCHEME_A)), NIL);
3913 s_goto (OP_APPLY);
3914 }
3915
3916 abort ();
3917 }
3918
3919 static pointer
3920 opexe_2 (SCHEME_P_ enum scheme_opcodes op)
3921 {
3922 pointer args = SCHEME_V->args;
3923 pointer x = car (args);
3924 num v;
3925
3926 #if USE_MATH
3927 RVALUE dd;
3928 #endif
3929
3930 switch (op)
3931 {
3932 #if USE_MATH
3933 case OP_INEX2EX: /* inexact->exact */
3934 if (num_is_integer (x))
3935 s_return (x);
3936 else if (modf (rvalue_unchecked (x), &dd) == 0)
3937 s_return (mk_integer (SCHEME_A_ ivalue (x)));
3938 else
3939 Error_1 ("inexact->exact: not integral:", x);
3940
3941 case OP_EXP: s_return (mk_real (SCHEME_A_ exp (rvalue (x))));
3942 case OP_LOG: s_return (mk_real (SCHEME_A_ log (rvalue (x))));
3943 case OP_SIN: s_return (mk_real (SCHEME_A_ sin (rvalue (x))));
3944 case OP_COS: s_return (mk_real (SCHEME_A_ cos (rvalue (x))));
3945 case OP_TAN: s_return (mk_real (SCHEME_A_ tan (rvalue (x))));
3946 case OP_ASIN: s_return (mk_real (SCHEME_A_ asin (rvalue (x))));
3947 case OP_ACOS: s_return (mk_real (SCHEME_A_ acos (rvalue (x))));
3948
3949 case OP_ATAN:
3950 if (cdr (args) == NIL)
3951 s_return (mk_real (SCHEME_A_ atan (rvalue (x))));
3952 else
3953 {
3954 pointer y = cadr (args);
3955 s_return (mk_real (SCHEME_A_ atan2 (rvalue (x), rvalue (y))));
3956 }
3957
3958 case OP_SQRT:
3959 s_return (mk_real (SCHEME_A_ sqrt (rvalue (x))));
3960
3961 case OP_EXPT:
3962 {
3963 RVALUE result;
3964 int real_result = 1;
3965 pointer y = cadr (args);
3966
3967 if (num_is_integer (x) && num_is_integer (y))
3968 real_result = 0;
3969
3970 /* This 'if' is an R5RS compatibility fix. */
3971 /* NOTE: Remove this 'if' fix for R6RS. */
3972 if (rvalue (x) == 0 && rvalue (y) < 0)
3973 result = 0;
3974 else
3975 result = pow (rvalue (x), rvalue (y));
3976
3977 /* Before returning integer result make sure we can. */
3978 /* If the test fails, result is too big for integer. */
3979 if (!real_result)
3980 {
3981 long result_as_long = result;
3982
3983 if (result != (RVALUE) result_as_long)
3984 real_result = 1;
3985 }
3986
3987 if (real_result)
3988 s_return (mk_real (SCHEME_A_ result));
3989 else
3990 s_return (mk_integer (SCHEME_A_ result));
3991 }
3992
3993 case OP_FLOOR: s_return (mk_real (SCHEME_A_ floor (rvalue (x))));
3994 case OP_CEILING: s_return (mk_real (SCHEME_A_ ceil (rvalue (x))));
3995
3996 case OP_TRUNCATE:
3997 {
3998 RVALUE rvalue_of_x;
3999
4000 rvalue_of_x = rvalue (x);
4001
4002 if (rvalue_of_x > 0)
4003 s_return (mk_real (SCHEME_A_ floor (rvalue_of_x)));
4004 else
4005 s_return (mk_real (SCHEME_A_ ceil (rvalue_of_x)));
4006 }
4007
4008 case OP_ROUND:
4009 if (num_is_integer (x))
4010 s_return (x);
4011
4012 s_return (mk_real (SCHEME_A_ round_per_R5RS (rvalue (x))));
4013 #endif
4014
4015 case OP_ADD: /* + */
4016 v = num_zero;
4017
4018 for (x = args; x != NIL; x = cdr (x))
4019 v = num_op ('+', v, nvalue (car (x)));
4020
4021 s_return (mk_number (SCHEME_A_ v));
4022
4023 case OP_MUL: /* * */
4024 v = num_one;
4025
4026 for (x = args; x != NIL; x = cdr (x))
4027 v = num_op ('+', v, nvalue (car (x)));
4028
4029 s_return (mk_number (SCHEME_A_ v));
4030
4031 case OP_SUB: /* - */
4032 if (cdr (args) == NIL)
4033 {
4034 x = args;
4035 v = num_zero;
4036 }
4037 else
4038 {
4039 x = cdr (args);
4040 v = nvalue (car (args));
4041 }
4042
4043 for (; x != NIL; x = cdr (x))
4044 v = num_op ('+', v, nvalue (car (x)));
4045
4046 s_return (mk_number (SCHEME_A_ v));
4047
4048 case OP_DIV: /* / */
4049 if (cdr (args) == NIL)
4050 {
4051 x = args;
4052 v = num_one;
4053 }
4054 else
4055 {
4056 x = cdr (args);
4057 v = nvalue (car (args));
4058 }
4059
4060 for (; x != NIL; x = cdr (x))
4061 {
4062 if (!is_zero_rvalue (rvalue (car (x))))
4063 v = num_div (v, nvalue (car (x)));
4064 else
4065 Error_0 ("/: division by zero");
4066 }
4067
4068 s_return (mk_number (SCHEME_A_ v));
4069
4070 case OP_INTDIV: /* quotient */
4071 if (cdr (args) == NIL)
4072 {
4073 x = args;
4074 v = num_one;
4075 }
4076 else
4077 {
4078 x = cdr (args);
4079 v = nvalue (car (args));
4080 }
4081
4082 for (; x != NIL; x = cdr (x))
4083 {
4084 if (ivalue (car (x)) != 0)
4085 v = num_op ('/', v, nvalue (car (x)));
4086 else
4087 Error_0 ("quotient: division by zero");
4088 }
4089
4090 s_return (mk_number (SCHEME_A_ v));
4091
4092 case OP_REM: /* remainder */
4093 v = nvalue (x);
4094
4095 if (ivalue (cadr (args)) != 0)
4096 v = num_rem (v, nvalue (cadr (args)));
4097 else
4098 Error_0 ("remainder: division by zero");
4099
4100 s_return (mk_number (SCHEME_A_ v));
4101
4102 case OP_MOD: /* modulo */
4103 v = nvalue (x);
4104
4105 if (ivalue (cadr (args)) != 0)
4106 v = num_mod (v, nvalue (cadr (args)));
4107 else
4108 Error_0 ("modulo: division by zero");
4109
4110 s_return (mk_number (SCHEME_A_ v));
4111
4112 case OP_CAR: /* car */
4113 s_return (caar (args));
4114
4115 case OP_CDR: /* cdr */
4116 s_return (cdar (args));
4117
4118 case OP_CONS: /* cons */
4119 set_cdr (args, cadr (args));
4120 s_return (args);
4121
4122 case OP_SETCAR: /* set-car! */
4123 if (!is_immutable (x))
4124 {
4125 set_car (x, cadr (args));
4126 s_return (car (args));
4127 }
4128 else
4129 Error_0 ("set-car!: unable to alter immutable pair");
4130
4131 case OP_SETCDR: /* set-cdr! */
4132 if (!is_immutable (x))
4133 {
4134 set_cdr (x, cadr (args));
4135 s_return (car (args));
4136 }
4137 else
4138 Error_0 ("set-cdr!: unable to alter immutable pair");
4139
4140 case OP_CHAR2INT: /* char->integer */
4141 s_return (mk_integer (SCHEME_A_ ivalue (x)));
4142
4143 case OP_INT2CHAR: /* integer->char */
4144 s_return (mk_character (SCHEME_A_ ivalue (x)));
4145
4146 case OP_CHARUPCASE:
4147 {
4148 unsigned char c = ivalue (x);
4149 c = toupper (c);
4150 s_return (mk_character (SCHEME_A_ c));
4151 }
4152
4153 case OP_CHARDNCASE:
4154 {
4155 unsigned char c = ivalue (x);
4156 c = tolower (c);
4157 s_return (mk_character (SCHEME_A_ c));
4158 }
4159
4160 case OP_STR2SYM: /* string->symbol */
4161 s_return (mk_symbol (SCHEME_A_ strvalue (x)));
4162
4163 case OP_STR2ATOM: /* string->atom */
4164 {
4165 char *s = strvalue (x);
4166 long pf = 0;
4167
4168 if (cdr (args) != NIL)
4169 {
4170 /* we know cadr(args) is a natural number */
4171 /* see if it is 2, 8, 10, or 16, or error */
4172 pf = ivalue_unchecked (cadr (args));
4173
4174 if (pf == 16 || pf == 10 || pf == 8 || pf == 2)
4175 {
4176 /* base is OK */
4177 }
4178 else
4179 pf = -1;
4180 }
4181
4182 if (pf < 0)
4183 Error_1 ("string->atom: bad base:", cadr (args));
4184 else if (*s == '#') /* no use of base! */
4185 s_return (mk_sharp_const (SCHEME_A_ s + 1));
4186 else
4187 {
4188 if (pf == 0 || pf == 10)
4189 s_return (mk_atom (SCHEME_A_ s));
4190 else
4191 {
4192 char *ep;
4193 long iv = strtol (s, &ep, (int) pf);
4194
4195 if (*ep == 0)
4196 s_return (mk_integer (SCHEME_A_ iv));
4197 else
4198 s_return (S_F);
4199 }
4200 }
4201 }
4202
4203 case OP_SYM2STR: /* symbol->string */
4204 x = mk_string (SCHEME_A_ symname (x));
4205 setimmutable (x);
4206 s_return (x);
4207
4208 case OP_ATOM2STR: /* atom->string */
4209 {
4210 long pf = 0;
4211
4212 if (cdr (args) != NIL)
4213 {
4214 /* we know cadr(args) is a natural number */
4215 /* see if it is 2, 8, 10, or 16, or error */
4216 pf = ivalue_unchecked (cadr (args));
4217
4218 if (is_number (x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2))
4219 {
4220 /* base is OK */
4221 }
4222 else
4223 pf = -1;
4224 }
4225
4226 if (pf < 0)
4227 Error_1 ("atom->string: bad base:", cadr (args));
4228 else if (is_number (x) || is_character (x) || is_string (x) || is_symbol (x))
4229 {
4230 char *p;
4231 int len;
4232
4233 atom2str (SCHEME_A_ x, pf, &p, &len);
4234 s_return (mk_counted_string (SCHEME_A_ p, len));
4235 }
4236 else
4237 Error_1 ("atom->string: not an atom:", x);
4238 }
4239
4240 case OP_MKSTRING: /* make-string */
4241 {
4242 int fill = ' ';
4243 int len;
4244
4245 len = ivalue (x);
4246
4247 if (cdr (args) != NIL)
4248 fill = charvalue (cadr (args));
4249
4250 s_return (mk_empty_string (SCHEME_A_ len, fill));
4251 }
4252
4253 case OP_STRLEN: /* string-length */
4254 s_return (mk_integer (SCHEME_A_ strlength (x)));
4255
4256 case OP_STRREF: /* string-ref */
4257 {
4258 char *str;
4259 int index;
4260
4261 str = strvalue (x);
4262
4263 index = ivalue (cadr (args));
4264
4265 if (index >= strlength (x))
4266 Error_1 ("string-ref: out of bounds:", cadr (args));
4267
4268 s_return (mk_character (SCHEME_A_ ((unsigned char *)str)[index]));
4269 }
4270
4271 case OP_STRSET: /* string-set! */
4272 {
4273 char *str;
4274 int index;
4275 int c;
4276
4277 if (is_immutable (x))
4278 Error_1 ("string-set!: unable to alter immutable string:", x);
4279
4280 str = strvalue (x);
4281
4282 index = ivalue (cadr (args));
4283
4284 if (index >= strlength (x))
4285 Error_1 ("string-set!: out of bounds:", cadr (args));
4286
4287 c = charvalue (caddr (args));
4288
4289 str[index] = c;
4290 s_return (car (args));
4291 }
4292
4293 case OP_STRAPPEND: /* string-append */
4294 {
4295 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4296 int len = 0;
4297 pointer newstr;
4298 char *pos;
4299
4300 /* compute needed length for new string */
4301 for (x = args; x != NIL; x = cdr (x))
4302 len += strlength (car (x));
4303
4304 newstr = mk_empty_string (SCHEME_A_ len, ' ');
4305
4306 /* store the contents of the argument strings into the new string */
4307 for (pos = strvalue (newstr), x = args; x != NIL; pos += strlength (car (x)), x = cdr (x))
4308 memcpy (pos, strvalue (car (x)), strlength (car (x)));
4309
4310 s_return (newstr);
4311 }
4312
4313 case OP_SUBSTR: /* substring */
4314 {
4315 char *str;
4316 int index0;
4317 int index1;
4318 int len;
4319
4320 str = strvalue (x);
4321
4322 index0 = ivalue (cadr (args));
4323
4324 if (index0 > strlength (x))
4325 Error_1 ("substring: start out of bounds:", cadr (args));
4326
4327 if (cddr (args) != NIL)
4328 {
4329 index1 = ivalue (caddr (args));
4330
4331 if (index1 > strlength (x) || index1 < index0)
4332 Error_1 ("substring: end out of bounds:", caddr (args));
4333 }
4334 else
4335 index1 = strlength (x);
4336
4337 len = index1 - index0;
4338 x = mk_empty_string (SCHEME_A_ len, ' ');
4339 memcpy (strvalue (x), str + index0, len);
4340 strvalue (x)[len] = 0;
4341
4342 s_return (x);
4343 }
4344
4345 case OP_VECTOR: /* vector */
4346 {
4347 int i;
4348 pointer vec;
4349 int len = list_length (SCHEME_A_ args);
4350
4351 if (len < 0)
4352 Error_1 ("vector: not a proper list:", args);
4353
4354 vec = mk_vector (SCHEME_A_ len);
4355
4356 #if USE_ERROR_CHECKING
4357 if (SCHEME_V->no_memory)
4358 s_return (S_SINK);
4359 #endif
4360
4361 for (x = args, i = 0; is_pair (x); x = cdr (x), i++)
4362 set_vector_elem (vec, i, car (x));
4363
4364 s_return (vec);
4365 }
4366
4367 case OP_MKVECTOR: /* make-vector */
4368 {
4369 pointer fill = NIL;
4370 int len;
4371 pointer vec;
4372
4373 len = ivalue (x);
4374
4375 if (cdr (args) != NIL)
4376 fill = cadr (args);
4377
4378 vec = mk_vector (SCHEME_A_ len);
4379
4380 #if USE_ERROR_CHECKING
4381 if (SCHEME_V->no_memory)
4382 s_return (S_SINK);
4383 #endif
4384
4385 if (fill != NIL)
4386 fill_vector (vec, fill);
4387
4388 s_return (vec);
4389 }
4390
4391 case OP_VECLEN: /* vector-length */
4392 s_return (mk_integer (SCHEME_A_ veclength (x)));
4393
4394 case OP_VECREF: /* vector-ref */
4395 {
4396 int index;
4397
4398 index = ivalue (cadr (args));
4399
4400 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4401 Error_1 ("vector-ref: out of bounds:", cadr (args));
4402
4403 s_return (vector_elem (x, index));
4404 }
4405
4406 case OP_VECSET: /* vector-set! */
4407 {
4408 int index;
4409
4410 if (is_immutable (x))
4411 Error_1 ("vector-set!: unable to alter immutable vector:", x);
4412
4413 index = ivalue (cadr (args));
4414
4415 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4416 Error_1 ("vector-set!: out of bounds:", cadr (args));
4417
4418 set_vector_elem (x, index, caddr (args));
4419 s_return (x);
4420 }
4421 }
4422
4423 return S_T;
4424 }
4425
4426 INTERFACE int
4427 is_list (SCHEME_P_ pointer a)
4428 {
4429 return list_length (SCHEME_A_ a) >= 0;
4430 }
4431
4432 /* Result is:
4433 proper list: length
4434 circular list: -1
4435 not even a pair: -2
4436 dotted list: -2 minus length before dot
4437 */
4438 INTERFACE int
4439 list_length (SCHEME_P_ pointer a)
4440 {
4441 int i = 0;
4442 pointer slow, fast;
4443
4444 slow = fast = a;
4445
4446 while (1)
4447 {
4448 if (fast == NIL)
4449 return i;
4450
4451 if (!is_pair (fast))
4452 return -2 - i;
4453
4454 fast = cdr (fast);
4455 ++i;
4456
4457 if (fast == NIL)
4458 return i;
4459
4460 if (!is_pair (fast))
4461 return -2 - i;
4462
4463 ++i;
4464 fast = cdr (fast);
4465
4466 /* Safe because we would have already returned if `fast'
4467 encountered a non-pair. */
4468 slow = cdr (slow);
4469
4470 if (fast == slow)
4471 {
4472 /* the fast pointer has looped back around and caught up
4473 with the slow pointer, hence the structure is circular,
4474 not of finite length, and therefore not a list */
4475 return -1;
4476 }
4477 }
4478 }
4479
4480 static pointer
4481 opexe_r (SCHEME_P_ enum scheme_opcodes op)
4482 {
4483 pointer x = SCHEME_V->args;
4484
4485 for (;;)
4486 {
4487 num v = nvalue (car (x));
4488 x = cdr (x);
4489
4490 if (x == NIL)
4491 break;
4492
4493 int r = num_cmp (v, nvalue (car (x)));
4494
4495 switch (op)
4496 {
4497 case OP_NUMEQ: r = r == 0; break;
4498 case OP_LESS: r = r < 0; break;
4499 case OP_GRE: r = r > 0; break;
4500 case OP_LEQ: r = r <= 0; break;
4501 case OP_GEQ: r = r >= 0; break;
4502 }
4503
4504 if (!r)
4505 s_return (S_F);
4506 }
4507
4508 s_return (S_T);
4509 }
4510
4511 static pointer
4512 opexe_3 (SCHEME_P_ enum scheme_opcodes op)
4513 {
4514 pointer args = SCHEME_V->args;
4515 pointer a = car (args);
4516 pointer d = cdr (args);
4517 int r;
4518
4519 switch (op)
4520 {
4521 case OP_NOT: /* not */ r = is_false (a) ; break;
4522 case OP_BOOLP: /* boolean? */ r = a == S_F || a == S_T; break;
4523 case OP_EOFOBJP: /* eof-object? */ r = a == S_EOF ; break;
4524 case OP_NULLP: /* null? */ r = a == NIL ; break;
4525 case OP_SYMBOLP: /* symbol? */ r = is_symbol (a) ; break;
4526 case OP_NUMBERP: /* number? */ r = is_number (a) ; break;
4527 case OP_STRINGP: /* string? */ r = is_string (a) ; break;
4528 case OP_INTEGERP: /* integer? */ r = is_integer (a) ; break;
4529 case OP_REALP: /* real? */ r = is_number (a) ; break; /* all numbers are real */
4530 case OP_CHARP: /* char? */ r = is_character (a) ; break;
4531
4532 #if USE_CHAR_CLASSIFIERS
4533 case OP_CHARAP: /* char-alphabetic? */ r = Cisalpha (ivalue (a)); break;
4534 case OP_CHARNP: /* char-numeric? */ r = Cisdigit (ivalue (a)); break;
4535 case OP_CHARWP: /* char-whitespace? */ r = Cisspace (ivalue (a)); break;
4536 case OP_CHARUP: /* char-upper-case? */ r = Cisupper (ivalue (a)); break;
4537 case OP_CHARLP: /* char-lower-case? */ r = Cislower (ivalue (a)); break;
4538 #endif
4539
4540 #if USE_PORTS
4541 case OP_PORTP: /* port? */ r = is_port (a) ; break;
4542 case OP_INPORTP: /* input-port? */ r = is_inport (a) ; break;
4543 case OP_OUTPORTP: /* output-port? */ r = is_outport (a); break;
4544 #endif
4545
4546 case OP_PROCP: /* procedure? */
4547
4548 /*--
4549 * continuation should be procedure by the example
4550 * (call-with-current-continuation procedure?) ==> #t
4551 * in R^3 report sec. 6.9
4552 */
4553 r = is_proc (a) || is_closure (a) || is_continuation (a) || is_foreign (a);
4554 break;
4555
4556 case OP_PAIRP: /* pair? */ r = is_pair (a) ; break;
4557 case OP_LISTP: /* list? */ r = list_length (SCHEME_A_ a) >= 0; break;
4558 case OP_ENVP: /* environment? */ r = is_environment (a) ; break;
4559 case OP_VECTORP: /* vector? */ r = is_vector (a) ; break;
4560 case OP_EQ: /* eq? */ r = a == cadr (args) ; break;
4561 case OP_EQV: /* eqv? */ r = eqv (a, cadr (args)) ; break;
4562 }
4563
4564 s_retbool (r);
4565 }
4566
4567 static pointer
4568 opexe_4 (SCHEME_P_ enum scheme_opcodes op)
4569 {
4570 pointer args = SCHEME_V->args;
4571 pointer a = car (args);
4572 pointer x, y;
4573
4574 switch (op)
4575 {
4576 case OP_FORCE: /* force */
4577 SCHEME_V->code = a;
4578
4579 if (is_promise (SCHEME_V->code))
4580 {
4581 /* Should change type to closure here */
4582 s_save (SCHEME_A_ OP_SAVE_FORCED, NIL, SCHEME_V->code);
4583 SCHEME_V->args = NIL;
4584 s_goto (OP_APPLY);
4585 }
4586 else
4587 s_return (SCHEME_V->code);
4588
4589 case OP_SAVE_FORCED: /* Save forced value replacing promise */
4590 memcpy (SCHEME_V->code, SCHEME_V->value, sizeof (struct cell));
4591 s_return (SCHEME_V->value);
4592
4593 #if USE_PORTS
4594
4595 case OP_WRITE: /* write */
4596 case OP_DISPLAY: /* display */
4597 case OP_WRITE_CHAR: /* write-char */
4598 if (is_pair (cdr (SCHEME_V->args)))
4599 {
4600 if (cadr (SCHEME_V->args) != SCHEME_V->outport)
4601 {
4602 x = cons (SCHEME_V->outport, NIL);
4603 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4604 SCHEME_V->outport = cadr (SCHEME_V->args);
4605 }
4606 }
4607
4608 SCHEME_V->args = a;
4609
4610 if (op == OP_WRITE)
4611 SCHEME_V->print_flag = 1;
4612 else
4613 SCHEME_V->print_flag = 0;
4614
4615 s_goto (OP_P0LIST);
4616
4617 case OP_NEWLINE: /* newline */
4618 if (is_pair (args))
4619 {
4620 if (a != SCHEME_V->outport)
4621 {
4622 x = cons (SCHEME_V->outport, NIL);
4623 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4624 SCHEME_V->outport = a;
4625 }
4626 }
4627
4628 putstr (SCHEME_A_ "\n");
4629 s_return (S_T);
4630 #endif
4631
4632 case OP_ERR0: /* error */
4633 SCHEME_V->retcode = -1;
4634
4635 if (!is_string (a))
4636 {
4637 args = cons (mk_string (SCHEME_A_ " -- "), args);
4638 setimmutable (car (args));
4639 }
4640
4641 putstr (SCHEME_A_ "Error: ");
4642 putstr (SCHEME_A_ strvalue (car (args)));
4643 SCHEME_V->args = cdr (args);
4644 s_goto (OP_ERR1);
4645
4646 case OP_ERR1: /* error */
4647 putstr (SCHEME_A_ " ");
4648
4649 if (args != NIL)
4650 {
4651 s_save (SCHEME_A_ OP_ERR1, cdr (args), NIL);
4652 SCHEME_V->args = a;
4653 SCHEME_V->print_flag = 1;
4654 s_goto (OP_P0LIST);
4655 }
4656 else
4657 {
4658 putstr (SCHEME_A_ "\n");
4659
4660 if (SCHEME_V->interactive_repl)
4661 s_goto (OP_T0LVL);
4662 else
4663 return NIL;
4664 }
4665
4666 case OP_REVERSE: /* reverse */
4667 s_return (reverse (SCHEME_A_ a));
4668
4669 case OP_LIST_STAR: /* list* */
4670 s_return (list_star (SCHEME_A_ SCHEME_V->args));
4671
4672 case OP_APPEND: /* append */
4673 x = NIL;
4674 y = args;
4675
4676 if (y == x)
4677 s_return (x);
4678
4679 /* cdr() in the while condition is not a typo. If car() */
4680 /* is used (append '() 'a) will return the wrong result. */
4681 while (cdr (y) != NIL)
4682 {
4683 x = revappend (SCHEME_A_ x, car (y));
4684 y = cdr (y);
4685
4686 if (x == S_F)
4687 Error_0 ("non-list argument to append");
4688 }
4689
4690 s_return (reverse_in_place (SCHEME_A_ car (y), x));
4691
4692 #if USE_PLIST
4693
4694 case OP_PUT: /* put */
4695 if (!hasprop (a) || !hasprop (cadr (args)))
4696 Error_0 ("illegal use of put");
4697
4698 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4699 {
4700 if (caar (x) == y)
4701 break;
4702 }
4703
4704 if (x != NIL)
4705 cdar (x) = caddr (args);
4706 else
4707 symprop (a) = cons (cons (y, caddr (args)), symprop (a));
4708
4709 s_return (S_T);
4710
4711 case OP_GET: /* get */
4712 if (!hasprop (a) || !hasprop (cadr (args)))
4713 Error_0 ("illegal use of get");
4714
4715 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4716 if (caar (x) == y)
4717 break;
4718
4719 if (x != NIL)
4720 s_return (cdar (x));
4721 else
4722 s_return (NIL);
4723
4724 #endif /* USE_PLIST */
4725
4726 case OP_QUIT: /* quit */
4727 if (is_pair (args))
4728 SCHEME_V->retcode = ivalue (a);
4729
4730 return NIL;
4731
4732 case OP_GC: /* gc */
4733 gc (SCHEME_A_ NIL, NIL);
4734 s_return (S_T);
4735
4736 case OP_GCVERB: /* gc-verbose */
4737 {
4738 int was = SCHEME_V->gc_verbose;
4739
4740 SCHEME_V->gc_verbose = (a != S_F);
4741 s_retbool (was);
4742 }
4743
4744 case OP_NEWSEGMENT: /* new-segment */
4745 if (!is_pair (args) || !is_number (a))
4746 Error_0 ("new-segment: argument must be a number");
4747
4748 alloc_cellseg (SCHEME_A_ (int)ivalue (a));
4749
4750 s_return (S_T);
4751
4752 case OP_OBLIST: /* oblist */
4753 s_return (oblist_all_symbols (SCHEME_A));
4754
4755 #if USE_PORTS
4756
4757 case OP_CURR_INPORT: /* current-input-port */
4758 s_return (SCHEME_V->inport);
4759
4760 case OP_CURR_OUTPORT: /* current-output-port */
4761 s_return (SCHEME_V->outport);
4762
4763 case OP_OPEN_INFILE: /* open-input-file */
4764 case OP_OPEN_OUTFILE: /* open-output-file */
4765 case OP_OPEN_INOUTFILE: /* open-input-output-file */
4766 {
4767 int prop = 0;
4768 pointer p;
4769
4770 switch (op)
4771 {
4772 case OP_OPEN_INFILE:
4773 prop = port_input;
4774 break;
4775
4776 case OP_OPEN_OUTFILE:
4777 prop = port_output;
4778 break;
4779
4780 case OP_OPEN_INOUTFILE:
4781 prop = port_input | port_output;
4782 break;
4783 }
4784
4785 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
4786
4787 if (p == NIL)
4788 s_return (S_F);
4789
4790 s_return (p);
4791 }
4792
4793 # if USE_STRING_PORTS
4794
4795 case OP_OPEN_INSTRING: /* open-input-string */
4796 case OP_OPEN_INOUTSTRING: /* open-input-output-string */
4797 {
4798 int prop = 0;
4799 pointer p;
4800
4801 switch (op)
4802 {
4803 case OP_OPEN_INSTRING:
4804 prop = port_input;
4805 break;
4806
4807 case OP_OPEN_INOUTSTRING:
4808 prop = port_input | port_output;
4809 break;
4810 }
4811
4812 p = port_from_string (SCHEME_A_ strvalue (a),
4813 strvalue (a) + strlength (a), prop);
4814
4815 if (p == NIL)
4816 s_return (S_F);
4817
4818 s_return (p);
4819 }
4820
4821 case OP_OPEN_OUTSTRING: /* open-output-string */
4822 {
4823 pointer p;
4824
4825 if (a == NIL)
4826 {
4827 p = port_from_scratch (SCHEME_A);
4828
4829 if (p == NIL)
4830 s_return (S_F);
4831 }
4832 else
4833 {
4834 p = port_from_string (SCHEME_A_ strvalue (a),
4835 strvalue (a) + strlength (a), port_output);
4836
4837 if (p == NIL)
4838 s_return (S_F);
4839 }
4840
4841 s_return (p);
4842 }
4843
4844 case OP_GET_OUTSTRING: /* get-output-string */
4845 {
4846 port *p;
4847
4848 if ((p = a->object.port)->kind & port_string)
4849 {
4850 off_t size;
4851 char *str;
4852
4853 size = p->rep.string.curr - p->rep.string.start + 1;
4854 str = malloc (size);
4855
4856 if (str != NULL)
4857 {
4858 pointer s;
4859
4860 memcpy (str, p->rep.string.start, size - 1);
4861 str[size - 1] = '\0';
4862 s = mk_string (SCHEME_A_ str);
4863 free (str);
4864 s_return (s);
4865 }
4866 }
4867
4868 s_return (S_F);
4869 }
4870
4871 # endif
4872
4873 case OP_CLOSE_INPORT: /* close-input-port */
4874 port_close (SCHEME_A_ a, port_input);
4875 s_return (S_T);
4876
4877 case OP_CLOSE_OUTPORT: /* close-output-port */
4878 port_close (SCHEME_A_ a, port_output);
4879 s_return (S_T);
4880 #endif
4881
4882 case OP_INT_ENV: /* interaction-environment */
4883 s_return (SCHEME_V->global_env);
4884
4885 case OP_CURR_ENV: /* current-environment */
4886 s_return (SCHEME_V->envir);
4887
4888 }
4889
4890 abort ();
4891 }
4892
4893 static pointer
4894 opexe_5 (SCHEME_P_ enum scheme_opcodes op)
4895 {
4896 pointer args = SCHEME_V->args;
4897 pointer x;
4898
4899 if (SCHEME_V->nesting != 0)
4900 {
4901 int n = SCHEME_V->nesting;
4902
4903 SCHEME_V->nesting = 0;
4904 SCHEME_V->retcode = -1;
4905 Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
4906 }
4907
4908 switch (op)
4909 {
4910 /* ========== reading part ========== */
4911 #if USE_PORTS
4912 case OP_READ:
4913 if (!is_pair (args))
4914 s_goto (OP_READ_INTERNAL);
4915
4916 if (!is_inport (car (args)))
4917 Error_1 ("read: not an input port:", car (args));
4918
4919 if (car (args) == SCHEME_V->inport)
4920 s_goto (OP_READ_INTERNAL);
4921
4922 x = SCHEME_V->inport;
4923 SCHEME_V->inport = car (args);
4924 x = cons (x, NIL);
4925 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4926 s_goto (OP_READ_INTERNAL);
4927
4928 case OP_READ_CHAR: /* read-char */
4929 case OP_PEEK_CHAR: /* peek-char */
4930 {
4931 int c;
4932
4933 if (is_pair (args))
4934 {
4935 if (car (args) != SCHEME_V->inport)
4936 {
4937 x = SCHEME_V->inport;
4938 x = cons (x, NIL);
4939 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4940 SCHEME_V->inport = car (args);
4941 }
4942 }
4943
4944 c = inchar (SCHEME_A);
4945
4946 if (c == EOF)
4947 s_return (S_EOF);
4948
4949 if (SCHEME_V->op == OP_PEEK_CHAR)
4950 backchar (SCHEME_A_ c);
4951
4952 s_return (mk_character (SCHEME_A_ c));
4953 }
4954
4955 case OP_CHAR_READY: /* char-ready? */
4956 {
4957 pointer p = SCHEME_V->inport;
4958 int res;
4959
4960 if (is_pair (args))
4961 p = car (args);
4962
4963 res = p->object.port->kind & port_string;
4964
4965 s_retbool (res);
4966 }
4967
4968 case OP_SET_INPORT: /* set-input-port */
4969 SCHEME_V->inport = car (args);
4970 s_return (SCHEME_V->value);
4971
4972 case OP_SET_OUTPORT: /* set-output-port */
4973 SCHEME_V->outport = car (args);
4974 s_return (SCHEME_V->value);
4975 #endif
4976
4977 case OP_RDSEXPR:
4978 switch (SCHEME_V->tok)
4979 {
4980 case TOK_EOF:
4981 s_return (S_EOF);
4982 /* NOTREACHED */
4983
4984 case TOK_VEC:
4985 s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
4986 /* fall through */
4987
4988 case TOK_LPAREN:
4989 SCHEME_V->tok = token (SCHEME_A);
4990
4991 if (SCHEME_V->tok == TOK_RPAREN)
4992 s_return (NIL);
4993 else if (SCHEME_V->tok == TOK_DOT)
4994 Error_0 ("syntax error: illegal dot expression");
4995 else
4996 {
4997 SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
4998 s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
4999 s_goto (OP_RDSEXPR);
5000 }
5001
5002 case TOK_QUOTE:
5003 s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
5004 SCHEME_V->tok = token (SCHEME_A);
5005 s_goto (OP_RDSEXPR);
5006
5007 case TOK_BQUOTE:
5008 SCHEME_V->tok = token (SCHEME_A);
5009
5010 if (SCHEME_V->tok == TOK_VEC)
5011 {
5012 s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
5013 SCHEME_V->tok = TOK_LPAREN;
5014 s_goto (OP_RDSEXPR);
5015 }
5016 else
5017 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
5018
5019 s_goto (OP_RDSEXPR);
5020
5021 case TOK_COMMA:
5022 s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
5023 SCHEME_V->tok = token (SCHEME_A);
5024 s_goto (OP_RDSEXPR);
5025
5026 case TOK_ATMARK:
5027 s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
5028 SCHEME_V->tok = token (SCHEME_A);
5029 s_goto (OP_RDSEXPR);
5030
5031 case TOK_ATOM:
5032 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS)));
5033
5034 case TOK_DQUOTE:
5035 x = readstrexp (SCHEME_A);
5036
5037 if (x == S_F)
5038 Error_0 ("Error reading string");
5039
5040 setimmutable (x);
5041 s_return (x);
5042
5043 case TOK_SHARP:
5044 {
5045 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
5046
5047 if (f == NIL)
5048 Error_0 ("undefined sharp expression");
5049 else
5050 {
5051 SCHEME_V->code = cons (slot_value_in_env (f), NIL);
5052 s_goto (OP_EVAL);
5053 }
5054 }
5055
5056 case TOK_SHARP_CONST:
5057 if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS))) == NIL)
5058 Error_0 ("undefined sharp expression");
5059 else
5060 s_return (x);
5061
5062 default:
5063 Error_0 ("syntax error: illegal token");
5064 }
5065
5066 break;
5067
5068 case OP_RDLIST:
5069 SCHEME_V->args = cons (SCHEME_V->value, args);
5070 SCHEME_V->tok = token (SCHEME_A);
5071
5072 switch (SCHEME_V->tok)
5073 {
5074 case TOK_EOF:
5075 s_return (S_EOF);
5076
5077 case TOK_RPAREN:
5078 {
5079 int c = inchar (SCHEME_A);
5080
5081 if (c != '\n')
5082 backchar (SCHEME_A_ c);
5083 #if SHOW_ERROR_LINE
5084 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5085 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5086 #endif
5087
5088 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5089 s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5090 }
5091
5092 case TOK_DOT:
5093 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5094 SCHEME_V->tok = token (SCHEME_A);
5095 s_goto (OP_RDSEXPR);
5096
5097 default:
5098 s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5099 s_goto (OP_RDSEXPR);
5100 }
5101
5102 case OP_RDDOT:
5103 if (token (SCHEME_A) != TOK_RPAREN)
5104 Error_0 ("syntax error: illegal dot expression");
5105
5106 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5107 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5108
5109 case OP_RDQUOTE:
5110 s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5111
5112 case OP_RDQQUOTE:
5113 s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5114
5115 case OP_RDQQUOTEVEC:
5116 s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5117 cons (mk_symbol (SCHEME_A_ "vector"),
5118 cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5119
5120 case OP_RDUNQUOTE:
5121 s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5122
5123 case OP_RDUQTSP:
5124 s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5125
5126 case OP_RDVEC:
5127 /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5128 s_goto(OP_EVAL); Cannot be quoted */
5129 /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5130 s_return(x); Cannot be part of pairs */
5131 /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5132 SCHEME_V->args=SCHEME_V->value;
5133 s_goto(OP_APPLY); */
5134 SCHEME_V->args = SCHEME_V->value;
5135 s_goto (OP_VECTOR);
5136
5137 /* ========== printing part ========== */
5138 case OP_P0LIST:
5139 if (is_vector (args))
5140 {
5141 putstr (SCHEME_A_ "#(");
5142 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5143 s_goto (OP_PVECFROM);
5144 }
5145 else if (is_environment (args))
5146 {
5147 putstr (SCHEME_A_ "#<ENVIRONMENT>");
5148 s_return (S_T);
5149 }
5150 else if (!is_pair (args))
5151 {
5152 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5153 s_return (S_T);
5154 }
5155 else
5156 {
5157 pointer a = car (args);
5158 pointer b = cdr (args);
5159 int ok_abbr = ok_abbrev (b);
5160 SCHEME_V->args = car (b);
5161
5162 if (a == SCHEME_V->QUOTE && ok_abbr)
5163 putstr (SCHEME_A_ "'");
5164 else if (a == SCHEME_V->QQUOTE && ok_abbr)
5165 putstr (SCHEME_A_ "`");
5166 else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5167 putstr (SCHEME_A_ ",");
5168 else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5169 putstr (SCHEME_A_ ",@");
5170 else
5171 {
5172 putstr (SCHEME_A_ "(");
5173 s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5174 SCHEME_V->args = a;
5175 }
5176
5177 s_goto (OP_P0LIST);
5178 }
5179
5180 case OP_P1LIST:
5181 if (is_pair (args))
5182 {
5183 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5184 putstr (SCHEME_A_ " ");
5185 SCHEME_V->args = car (args);
5186 s_goto (OP_P0LIST);
5187 }
5188 else if (is_vector (args))
5189 {
5190 s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5191 putstr (SCHEME_A_ " . ");
5192 s_goto (OP_P0LIST);
5193 }
5194 else
5195 {
5196 if (args != NIL)
5197 {
5198 putstr (SCHEME_A_ " . ");
5199 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5200 }
5201
5202 putstr (SCHEME_A_ ")");
5203 s_return (S_T);
5204 }
5205
5206 case OP_PVECFROM:
5207 {
5208 int i = ivalue_unchecked (cdr (args));
5209 pointer vec = car (args);
5210 int len = veclength (vec);
5211
5212 if (i == len)
5213 {
5214 putstr (SCHEME_A_ ")");
5215 s_return (S_T);
5216 }
5217 else
5218 {
5219 pointer elem = vector_elem (vec, i);
5220
5221 ivalue_unchecked (cdr (args)) = i + 1;
5222 s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5223 SCHEME_V->args = elem;
5224
5225 if (i > 0)
5226 putstr (SCHEME_A_ " ");
5227
5228 s_goto (OP_P0LIST);
5229 }
5230 }
5231 }
5232
5233 abort ();
5234 }
5235
5236 static pointer
5237 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5238 {
5239 pointer args = SCHEME_V->args;
5240 pointer a = car (args);
5241 pointer x, y;
5242
5243 switch (op)
5244 {
5245 case OP_LIST_LENGTH: /* length *//* a.k */
5246 {
5247 long v = list_length (SCHEME_A_ a);
5248
5249 if (v < 0)
5250 Error_1 ("length: not a list:", a);
5251
5252 s_return (mk_integer (SCHEME_A_ v));
5253 }
5254
5255 case OP_ASSQ: /* assq *//* a.k */
5256 x = a;
5257
5258 for (y = cadr (args); is_pair (y); y = cdr (y))
5259 {
5260 if (!is_pair (car (y)))
5261 Error_0 ("unable to handle non pair element");
5262
5263 if (x == caar (y))
5264 break;
5265 }
5266
5267 if (is_pair (y))
5268 s_return (car (y));
5269 else
5270 s_return (S_F);
5271
5272
5273 case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5274 SCHEME_V->args = a;
5275
5276 if (SCHEME_V->args == NIL)
5277 s_return (S_F);
5278 else if (is_closure (SCHEME_V->args))
5279 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5280 else if (is_macro (SCHEME_V->args))
5281 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5282 else
5283 s_return (S_F);
5284
5285 case OP_CLOSUREP: /* closure? */
5286 /*
5287 * Note, macro object is also a closure.
5288 * Therefore, (closure? <#MACRO>) ==> #t
5289 */
5290 s_retbool (is_closure (a));
5291
5292 case OP_MACROP: /* macro? */
5293 s_retbool (is_macro (a));
5294 }
5295
5296 abort ();
5297 }
5298
5299 typedef pointer (*dispatch_func) (SCHEME_P_ enum scheme_opcodes);
5300
5301 typedef int (*test_predicate)(pointer);
5302 static int
5303 is_any (pointer p)
5304 {
5305 return 1;
5306 }
5307
5308 static int
5309 is_nonneg (pointer p)
5310 {
5311 return ivalue (p) >= 0 && is_integer (p);
5312 }
5313
5314 static int
5315 tst_is_list (pointer p)
5316 {
5317 return p == NIL || is_pair (p);
5318 }
5319
5320 /* Correspond carefully with following defines! */
5321 static struct
5322 {
5323 test_predicate fct;
5324 const char *kind;
5325 } tests[] =
5326 {
5327 { is_any, 0 },
5328 { is_string, "string" },
5329 { is_symbol, "symbol" },
5330 { is_port, "port" },
5331 { is_inport, "input port" },
5332 { is_outport, "output port" },
5333 { is_environment, "environment" },
5334 { is_pair, "pair" },
5335 { tst_is_list, "pair or '()" },
5336 { is_character, "character" },
5337 { is_vector, "vector" },
5338 { is_number, "number" },
5339 { is_integer, "integer" },
5340 { is_nonneg, "non-negative integer" }
5341 };
5342
5343 #define TST_NONE 0 /* TST_NONE used for standard procedures, for internal ops, 0 is used */
5344 #define TST_ANY "\001"
5345 #define TST_STRING "\002"
5346 #define TST_SYMBOL "\003"
5347 #define TST_PORT "\004"
5348 #define TST_INPORT "\005"
5349 #define TST_OUTPORT "\006"
5350 #define TST_ENVIRONMENT "\007"
5351 #define TST_PAIR "\010"
5352 #define TST_LIST "\011"
5353 #define TST_CHAR "\012"
5354 #define TST_VECTOR "\013"
5355 #define TST_NUMBER "\014"
5356 #define TST_INTEGER "\015"
5357 #define TST_NATURAL "\016"
5358
5359 typedef struct
5360 {
5361 dispatch_func func;
5362 char *name;
5363 int min_arity;
5364 int max_arity;
5365 char arg_tests_encoding[3];
5366 } op_code_info;
5367
5368 #define INF_ARG 0xffff
5369
5370 static op_code_info dispatch_table[] = {
5371 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { opexe_ ## func, name, minarity, maxarity, argtest },
5372 #include "opdefines.h"
5373 #undef OP_DEF
5374 {0}
5375 };
5376
5377 static const char *
5378 procname (pointer x)
5379 {
5380 int n = procnum (x);
5381 const char *name = dispatch_table[n].name;
5382
5383 if (name == 0)
5384 name = "ILLEGAL!";
5385
5386 return name;
5387 }
5388
5389 /* kernel of this interpreter */
5390 static void
5391 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5392 {
5393 SCHEME_V->op = op;
5394
5395 for (;;)
5396 {
5397 op_code_info *pcd = dispatch_table + SCHEME_V->op;
5398
5399 #if USE_ERROR_CHECKING
5400 if (pcd->name) /* if built-in function, check arguments */
5401 {
5402 int ok = 1;
5403 char msg[STRBUFFSIZE];
5404 int n = list_length (SCHEME_A_ SCHEME_V->args);
5405
5406 /* Check number of arguments */
5407 if (ecb_expect_false (n < pcd->min_arity))
5408 {
5409 ok = 0;
5410 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5411 pcd->name, pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5412 }
5413 else if (ecb_expect_false (n > pcd->max_arity))
5414 {
5415 ok = 0;
5416 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5417 pcd->name, pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5418 }
5419
5420 if (ecb_expect_false (ok))
5421 {
5422 if (*pcd->arg_tests_encoding)
5423 {
5424 int i = 0;
5425 int j;
5426 const char *t = pcd->arg_tests_encoding;
5427 pointer arglist = SCHEME_V->args;
5428
5429 do
5430 {
5431 pointer arg = car (arglist);
5432
5433 j = t[0];
5434
5435 if (!tests[j - 1].fct (arg))
5436 break;
5437
5438 if (t[1]) /* last test is replicated as necessary */
5439 t++;
5440
5441 arglist = cdr (arglist);
5442 i++;
5443 }
5444 while (i < n);
5445
5446 if (i < n)
5447 {
5448 ok = 0;
5449 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", pcd->name, i + 1, tests[j].kind);
5450 }
5451 }
5452 }
5453
5454 if (!ok)
5455 {
5456 if (xError_1 (SCHEME_A_ msg, 0) == NIL)
5457 return;
5458
5459 pcd = dispatch_table + SCHEME_V->op;
5460 }
5461 }
5462 #endif
5463
5464 ok_to_freely_gc (SCHEME_A);
5465
5466 if (ecb_expect_false (pcd->func (SCHEME_A_ SCHEME_V->op) == NIL))
5467 return;
5468
5469 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5470 {
5471 xwrstr ("No memory!\n");
5472 return;
5473 }
5474 }
5475 }
5476
5477 /* ========== Initialization of internal keywords ========== */
5478
5479 static void
5480 assign_syntax (SCHEME_P_ const char *name)
5481 {
5482 pointer x = oblist_add_by_name (SCHEME_A_ name);
5483 set_typeflag (x, typeflag (x) | T_SYNTAX);
5484 }
5485
5486 static void
5487 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5488 {
5489 pointer x = mk_symbol (SCHEME_A_ name);
5490 pointer y = mk_proc (SCHEME_A_ op);
5491 new_slot_in_env (SCHEME_A_ x, y);
5492 }
5493
5494 static pointer
5495 mk_proc (SCHEME_P_ enum scheme_opcodes op)
5496 {
5497 pointer y = get_cell (SCHEME_A_ NIL, NIL);
5498 set_typeflag (y, (T_PROC | T_ATOM));
5499 ivalue_unchecked (y) = op;
5500 set_num_integer (y);
5501 return y;
5502 }
5503
5504 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5505 static int
5506 syntaxnum (pointer p)
5507 {
5508 const char *s = strvalue (car (p));
5509
5510 switch (strlength (car (p)))
5511 {
5512 case 2:
5513 if (s[0] == 'i')
5514 return OP_IF0; /* if */
5515 else
5516 return OP_OR0; /* or */
5517
5518 case 3:
5519 if (s[0] == 'a')
5520 return OP_AND0; /* and */
5521 else
5522 return OP_LET0; /* let */
5523
5524 case 4:
5525 switch (s[3])
5526 {
5527 case 'e':
5528 return OP_CASE0; /* case */
5529
5530 case 'd':
5531 return OP_COND0; /* cond */
5532
5533 case '*':
5534 return OP_LET0AST;/* let* */
5535
5536 default:
5537 return OP_SET0; /* set! */
5538 }
5539
5540 case 5:
5541 switch (s[2])
5542 {
5543 case 'g':
5544 return OP_BEGIN; /* begin */
5545
5546 case 'l':
5547 return OP_DELAY; /* delay */
5548
5549 case 'c':
5550 return OP_MACRO0; /* macro */
5551
5552 default:
5553 return OP_QUOTE; /* quote */
5554 }
5555
5556 case 6:
5557 switch (s[2])
5558 {
5559 case 'm':
5560 return OP_LAMBDA; /* lambda */
5561
5562 case 'f':
5563 return OP_DEF0; /* define */
5564
5565 default:
5566 return OP_LET0REC;/* letrec */
5567 }
5568
5569 default:
5570 return OP_C0STREAM; /* cons-stream */
5571 }
5572 }
5573
5574 #if USE_MULTIPLICITY
5575 scheme *
5576 scheme_init_new ()
5577 {
5578 scheme *sc = malloc (sizeof (scheme));
5579
5580 if (!scheme_init (SCHEME_A))
5581 {
5582 free (SCHEME_A);
5583 return 0;
5584 }
5585 else
5586 return sc;
5587 }
5588 #endif
5589
5590 int
5591 scheme_init (SCHEME_P)
5592 {
5593 int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5594 pointer x;
5595
5596 num_set_fixnum (num_zero, 1);
5597 num_set_ivalue (num_zero, 0);
5598 num_set_fixnum (num_one, 1);
5599 num_set_ivalue (num_one, 1);
5600
5601 #if USE_INTERFACE
5602 SCHEME_V->vptr = &vtbl;
5603 #endif
5604 SCHEME_V->gensym_cnt = 0;
5605 SCHEME_V->last_cell_seg = -1;
5606 SCHEME_V->free_cell = NIL;
5607 SCHEME_V->fcells = 0;
5608 SCHEME_V->no_memory = 0;
5609 SCHEME_V->inport = NIL;
5610 SCHEME_V->outport = NIL;
5611 SCHEME_V->save_inport = NIL;
5612 SCHEME_V->loadport = NIL;
5613 SCHEME_V->nesting = 0;
5614 SCHEME_V->interactive_repl = 0;
5615
5616 if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5617 {
5618 #if USE_ERROR_CHECKING
5619 SCHEME_V->no_memory = 1;
5620 return 0;
5621 #endif
5622 }
5623
5624 SCHEME_V->gc_verbose = 0;
5625 dump_stack_initialize (SCHEME_A);
5626 SCHEME_V->code = NIL;
5627 SCHEME_V->args = NIL;
5628 SCHEME_V->envir = NIL;
5629 SCHEME_V->tracing = 0;
5630
5631 /* init NIL */
5632 set_typeflag (NIL, T_ATOM | T_MARK);
5633 set_car (NIL, NIL);
5634 set_cdr (NIL, NIL);
5635 /* init T */
5636 set_typeflag (S_T, T_ATOM | T_MARK);
5637 set_car (S_T, S_T);
5638 set_cdr (S_T, S_T);
5639 /* init F */
5640 set_typeflag (S_F, T_ATOM | T_MARK);
5641 set_car (S_F, S_F);
5642 set_cdr (S_F, S_F);
5643 /* init EOF_OBJ */
5644 set_typeflag (S_EOF, T_ATOM | T_MARK);
5645 set_car (S_EOF, S_EOF);
5646 set_cdr (S_EOF, S_EOF);
5647 /* init sink */
5648 set_typeflag (S_SINK, T_PAIR | T_MARK);
5649 set_car (S_SINK, NIL);
5650
5651 /* init c_nest */
5652 SCHEME_V->c_nest = NIL;
5653
5654 SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5655 /* init global_env */
5656 new_frame_in_env (SCHEME_A_ NIL);
5657 SCHEME_V->global_env = SCHEME_V->envir;
5658 /* init else */
5659 x = mk_symbol (SCHEME_A_ "else");
5660 new_slot_in_env (SCHEME_A_ x, S_T);
5661
5662 {
5663 static const char *syntax_names[] = {
5664 "lambda", "quote", "define", "if", "begin", "set!",
5665 "let", "let*", "letrec", "cond", "delay", "and",
5666 "or", "cons-stream", "macro", "case"
5667 };
5668
5669 for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5670 assign_syntax (SCHEME_A_ syntax_names[i]);
5671 }
5672
5673 for (i = 0; i < n; i++)
5674 if (dispatch_table[i].name != 0)
5675 assign_proc (SCHEME_A_ i, dispatch_table[i].name);
5676
5677 /* initialization of global pointers to special symbols */
5678 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5679 SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5680 SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5681 SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5682 SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5683 SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5684 SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5685 SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5686 SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5687 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5688
5689 return !SCHEME_V->no_memory;
5690 }
5691
5692 #if USE_PORTS
5693 void
5694 scheme_set_input_port_file (SCHEME_P_ int fin)
5695 {
5696 SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5697 }
5698
5699 void
5700 scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5701 {
5702 SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5703 }
5704
5705 void
5706 scheme_set_output_port_file (SCHEME_P_ int fout)
5707 {
5708 SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5709 }
5710
5711 void
5712 scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5713 {
5714 SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5715 }
5716 #endif
5717
5718 void
5719 scheme_set_external_data (SCHEME_P_ void *p)
5720 {
5721 SCHEME_V->ext_data = p;
5722 }
5723
5724 void
5725 scheme_deinit (SCHEME_P)
5726 {
5727 int i;
5728
5729 #if SHOW_ERROR_LINE
5730 char *fname;
5731 #endif
5732
5733 SCHEME_V->oblist = NIL;
5734 SCHEME_V->global_env = NIL;
5735 dump_stack_free (SCHEME_A);
5736 SCHEME_V->envir = NIL;
5737 SCHEME_V->code = NIL;
5738 SCHEME_V->args = NIL;
5739 SCHEME_V->value = NIL;
5740
5741 if (is_port (SCHEME_V->inport))
5742 set_typeflag (SCHEME_V->inport, T_ATOM);
5743
5744 SCHEME_V->inport = NIL;
5745 SCHEME_V->outport = NIL;
5746
5747 if (is_port (SCHEME_V->save_inport))
5748 set_typeflag (SCHEME_V->save_inport, T_ATOM);
5749
5750 SCHEME_V->save_inport = NIL;
5751
5752 if (is_port (SCHEME_V->loadport))
5753 set_typeflag (SCHEME_V->loadport, T_ATOM);
5754
5755 SCHEME_V->loadport = NIL;
5756 SCHEME_V->gc_verbose = 0;
5757 gc (SCHEME_A_ NIL, NIL);
5758
5759 for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5760 free (SCHEME_V->alloc_seg[i]);
5761
5762 #if SHOW_ERROR_LINE
5763 for (i = 0; i <= SCHEME_V->file_i; i++)
5764 {
5765 if (SCHEME_V->load_stack[i].kind & port_file)
5766 {
5767 fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5768
5769 if (fname)
5770 free (fname);
5771 }
5772 }
5773 #endif
5774 }
5775
5776 void
5777 scheme_load_file (SCHEME_P_ int fin)
5778 {
5779 scheme_load_named_file (SCHEME_A_ fin, 0);
5780 }
5781
5782 void
5783 scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5784 {
5785 dump_stack_reset (SCHEME_A);
5786 SCHEME_V->envir = SCHEME_V->global_env;
5787 SCHEME_V->file_i = 0;
5788 SCHEME_V->load_stack[0].unget = -1;
5789 SCHEME_V->load_stack[0].kind = port_input | port_file;
5790 SCHEME_V->load_stack[0].rep.stdio.file = fin;
5791 #if USE_PORTS
5792 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5793 #endif
5794 SCHEME_V->retcode = 0;
5795
5796 #if USE_PORTS
5797 if (fin == STDIN_FILENO)
5798 SCHEME_V->interactive_repl = 1;
5799 #endif
5800
5801 #if USE_PORTS
5802 #if SHOW_ERROR_LINE
5803 SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5804
5805 if (fin != STDIN_FILENO && filename)
5806 SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5807 #endif
5808 #endif
5809
5810 SCHEME_V->inport = SCHEME_V->loadport;
5811 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5812 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5813 set_typeflag (SCHEME_V->loadport, T_ATOM);
5814
5815 if (SCHEME_V->retcode == 0)
5816 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5817 }
5818
5819 void
5820 scheme_load_string (SCHEME_P_ const char *cmd)
5821 {
5822 dump_stack_reset (SCHEME_A);
5823 SCHEME_V->envir = SCHEME_V->global_env;
5824 SCHEME_V->file_i = 0;
5825 SCHEME_V->load_stack[0].kind = port_input | port_string;
5826 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
5827 SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
5828 SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
5829 #if USE_PORTS
5830 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5831 #endif
5832 SCHEME_V->retcode = 0;
5833 SCHEME_V->interactive_repl = 0;
5834 SCHEME_V->inport = SCHEME_V->loadport;
5835 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5836 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5837 set_typeflag (SCHEME_V->loadport, T_ATOM);
5838
5839 if (SCHEME_V->retcode == 0)
5840 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5841 }
5842
5843 void
5844 scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
5845 {
5846 pointer x;
5847
5848 x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
5849
5850 if (x != NIL)
5851 set_slot_in_env (SCHEME_A_ x, value);
5852 else
5853 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
5854 }
5855
5856 #if !STANDALONE
5857
5858 void
5859 scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
5860 {
5861 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
5862 }
5863
5864 void
5865 scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
5866 {
5867 int i;
5868
5869 for (i = 0; i < count; i++)
5870 scheme_register_foreign_func (SCHEME_A_ list + i);
5871 }
5872
5873 pointer
5874 scheme_apply0 (SCHEME_P_ const char *procname)
5875 {
5876 return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
5877 }
5878
5879 void
5880 save_from_C_call (SCHEME_P)
5881 {
5882 pointer saved_data = cons (car (S_SINK),
5883 cons (SCHEME_V->envir,
5884 SCHEME_V->dump));
5885
5886 /* Push */
5887 SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
5888 /* Truncate the dump stack so TS will return here when done, not
5889 directly resume pre-C-call operations. */
5890 dump_stack_reset (SCHEME_A);
5891 }
5892
5893 void
5894 restore_from_C_call (SCHEME_P)
5895 {
5896 set_car (S_SINK, caar (SCHEME_V->c_nest));
5897 SCHEME_V->envir = cadar (SCHEME_V->c_nest);
5898 SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
5899 /* Pop */
5900 SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
5901 }
5902
5903 /* "func" and "args" are assumed to be already eval'ed. */
5904 pointer
5905 scheme_call (SCHEME_P_ pointer func, pointer args)
5906 {
5907 int old_repl = SCHEME_V->interactive_repl;
5908
5909 SCHEME_V->interactive_repl = 0;
5910 save_from_C_call (SCHEME_A);
5911 SCHEME_V->envir = SCHEME_V->global_env;
5912 SCHEME_V->args = args;
5913 SCHEME_V->code = func;
5914 SCHEME_V->retcode = 0;
5915 Eval_Cycle (SCHEME_A_ OP_APPLY);
5916 SCHEME_V->interactive_repl = old_repl;
5917 restore_from_C_call (SCHEME_A);
5918 return SCHEME_V->value;
5919 }
5920
5921 pointer
5922 scheme_eval (SCHEME_P_ pointer obj)
5923 {
5924 int old_repl = SCHEME_V->interactive_repl;
5925
5926 SCHEME_V->interactive_repl = 0;
5927 save_from_C_call (SCHEME_A);
5928 SCHEME_V->args = NIL;
5929 SCHEME_V->code = obj;
5930 SCHEME_V->retcode = 0;
5931 Eval_Cycle (SCHEME_A_ OP_EVAL);
5932 SCHEME_V->interactive_repl = old_repl;
5933 restore_from_C_call (SCHEME_A);
5934 return SCHEME_V->value;
5935 }
5936
5937 #endif
5938
5939 /* ========== Main ========== */
5940
5941 #if STANDALONE
5942
5943 int
5944 main (int argc, char **argv)
5945 {
5946 # if USE_MULTIPLICITY
5947 scheme ssc;
5948 scheme *const SCHEME_V = &ssc;
5949 # else
5950 # endif
5951 int fin;
5952 char *file_name = InitFile;
5953 int retcode;
5954 int isfile = 1;
5955
5956 if (argc == 2 && strcmp (argv[1], "-?") == 0)
5957 {
5958 xwrstr ("Usage: tinyscheme -?\n");
5959 xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
5960 xwrstr ("followed by\n");
5961 xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
5962 xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5963 xwrstr ("assuming that the executable is named tinyscheme.\n");
5964 xwrstr ("Use - as filename for stdin.\n");
5965 return 1;
5966 }
5967
5968 if (!scheme_init (SCHEME_A))
5969 {
5970 xwrstr ("Could not initialize!\n");
5971 return 2;
5972 }
5973
5974 # if USE_PORTS
5975 scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
5976 scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
5977 # endif
5978
5979 argv++;
5980
5981 #if 0
5982 if (access (file_name, 0) != 0)
5983 {
5984 char *p = getenv ("TINYSCHEMEINIT");
5985
5986 if (p != 0)
5987 file_name = p;
5988 }
5989 #endif
5990
5991 do
5992 {
5993 #if USE_PORTS
5994 if (strcmp (file_name, "-") == 0)
5995 fin = STDIN_FILENO;
5996 else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
5997 {
5998 pointer args = NIL;
5999
6000 isfile = file_name[1] == '1';
6001 file_name = *argv++;
6002
6003 if (strcmp (file_name, "-") == 0)
6004 fin = STDIN_FILENO;
6005 else if (isfile)
6006 fin = open (file_name, O_RDONLY);
6007
6008 for (; *argv; argv++)
6009 {
6010 pointer value = mk_string (SCHEME_A_ * argv);
6011
6012 args = cons (value, args);
6013 }
6014
6015 args = reverse_in_place (SCHEME_A_ NIL, args);
6016 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
6017
6018 }
6019 else
6020 fin = open (file_name, O_RDONLY);
6021 #endif
6022
6023 if (isfile && fin < 0)
6024 {
6025 xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
6026 }
6027 else
6028 {
6029 if (isfile)
6030 scheme_load_named_file (SCHEME_A_ fin, file_name);
6031 else
6032 scheme_load_string (SCHEME_A_ file_name);
6033
6034 #if USE_PORTS
6035 if (!isfile || fin != STDIN_FILENO)
6036 {
6037 if (SCHEME_V->retcode != 0)
6038 {
6039 xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
6040 }
6041
6042 if (isfile)
6043 close (fin);
6044 }
6045 #endif
6046 }
6047
6048 file_name = *argv++;
6049 }
6050 while (file_name != 0);
6051
6052 if (argc == 1)
6053 scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6054
6055 retcode = SCHEME_V->retcode;
6056 scheme_deinit (SCHEME_A);
6057
6058 return retcode;
6059 }
6060
6061 #endif
6062
6063 /*
6064 Local variables:
6065 c-file-style: "k&r"
6066 End:
6067 */