ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/microscheme/scheme.c
Revision: 1.23
Committed: Fri Nov 27 02:06:36 2015 UTC (8 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.22: +87 -105 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 "ecb.h"
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38
39 #include <string.h>
40 #include <stdlib.h>
41
42 #include <limits.h>
43 #include <inttypes.h>
44 #include <float.h>
45 //#include <ctype.h>
46
47 enum {
48 TOK_EOF,
49 TOK_LPAREN,
50 TOK_RPAREN,
51 TOK_DOT,
52 TOK_ATOM,
53 TOK_QUOTE,
54 TOK_DQUOTE,
55 TOK_BQUOTE,
56 TOK_COMMA,
57 TOK_ATMARK,
58 TOK_SHARP,
59 TOK_SHARP_CONST,
60 TOK_VEC
61 };
62
63 #define BACKQUOTE '`'
64 #define DELIMITERS "()\";\f\t\v\n\r "
65
66 #define NIL (&SCHEME_V->xNIL) //TODO: make this 0?
67 #define S_T (&SCHEME_V->xT) //TODO: magic ptr value?
68 #define S_F (&SCHEME_V->xF) //TODO: magic ptr value?
69 #define S_SINK (&SCHEME_V->xsink)
70 #define S_EOF (&SCHEME_V->xEOF_OBJ)
71
72 #if !USE_MULTIPLICITY
73 static scheme sc;
74 #endif
75
76 static void
77 xbase (char *s, long n, int base)
78 {
79 if (n < 0)
80 {
81 *s++ = '-';
82 n = -n;
83 }
84
85 char *p = s;
86
87 do {
88 *p++ = '0' + n % base;
89 n /= base;
90 } while (n);
91
92 *p-- = 0;
93
94 while (p > s)
95 {
96 char x = *s; *s = *p; *p = x;
97 --p; ++s;
98 }
99 }
100
101 static void
102 xnum (char *s, long n)
103 {
104 xbase (s, n, 10);
105 }
106
107 static void
108 xwrstr (const char *s)
109 {
110 write (1, s, strlen (s));
111 }
112
113 static void
114 xwrnum (long n)
115 {
116 char buf[64];
117
118 xnum (buf, n);
119 xwrstr (buf);
120 }
121
122 static char
123 xtoupper (char c)
124 {
125 if (c >= 'a' && c <= 'z')
126 c -= 'a' - 'A';
127
128 return c;
129 }
130
131 static char
132 xtolower (char c)
133 {
134 if (c >= 'A' && c <= 'Z')
135 c += 'a' - 'A';
136
137 return c;
138 }
139
140 static int
141 xisdigit (char c)
142 {
143 return c >= '0' && c <= '9';
144 }
145
146 #define toupper(c) xtoupper (c)
147 #define tolower(c) xtolower (c)
148 #define isdigit(c) xisdigit (c)
149
150 #if USE_IGNORECASE
151 static const char *
152 xstrlwr (char *s)
153 {
154 const char *p = s;
155
156 while (*s)
157 {
158 *s = tolower (*s);
159 s++;
160 }
161
162 return p;
163 }
164
165 #define stricmp(a,b) strcasecmp (a, b)
166 #define strlwr(s) xstrlwr (s)
167
168 #else
169 # define stricmp(a,b) strcmp (a, b)
170 # define strlwr(s) (s)
171 #endif
172
173 #ifndef prompt
174 # define prompt "ts> "
175 #endif
176
177 #ifndef InitFile
178 # define InitFile "init.scm"
179 #endif
180
181 #ifndef FIRST_CELLSEGS
182 # define FIRST_CELLSEGS 3
183 #endif
184
185 enum scheme_types
186 {
187 T_FREE,
188 T_STRING,
189 T_NUMBER,
190 T_SYMBOL,
191 T_PROC,
192 T_PAIR,
193 T_CLOSURE,
194 T_CONTINUATION,
195 T_FOREIGN,
196 T_CHARACTER,
197 T_PORT,
198 T_VECTOR,
199 T_MACRO,
200 T_PROMISE,
201 T_ENVIRONMENT,
202 /* one more... */
203 T_NUM_SYSTEM_TYPES
204 };
205
206 #define T_MASKTYPE 0x000f
207 #define T_SYNTAX 0x0010
208 #define T_IMMUTABLE 0x0020
209 #define T_ATOM 0x0040 /* only for gc */
210 #define T_MARK 0x0080 /* only for gc */
211
212 enum num_op { NUM_ADD, NUM_SUB, NUM_MUL, NUM_INTDIV };
213
214 static num num_op (enum num_op op, num a, num b);
215 static num num_intdiv (num a, num b);
216 static num num_rem (num a, num b);
217 static num num_mod (num a, num b);
218
219 #if USE_MATH
220 static double round_per_R5RS (double x);
221 #endif
222 static int is_zero_rvalue (RVALUE x);
223
224 ecb_inline int
225 num_is_integer (pointer p)
226 {
227 return num_is_fixnum (p->object.number);
228 }
229
230 static num num_zero;
231 static num num_one;
232
233 /* macros for cell operations */
234 #define typeflag(p) ((p)->flag + 0)
235 #define set_typeflag(p,v) ((p)->flag = (v))
236 #define type(p) (typeflag (p) & T_MASKTYPE)
237
238 INTERFACE int
239 is_string (pointer p)
240 {
241 return type (p) == T_STRING;
242 }
243
244 #define strvalue(p) ((p)->object.string.svalue)
245 #define strlength(p) ((p)->object.string.length)
246
247 INTERFACE int is_list (SCHEME_P_ pointer p);
248
249 INTERFACE int
250 is_vector (pointer p)
251 {
252 return type (p) == T_VECTOR;
253 }
254
255 #define vecvalue(p) ((p)->object.vector.vvalue)
256 #define veclength(p) ((p)->object.vector.length)
257 INTERFACE void fill_vector (pointer vec, pointer obj);
258 INTERFACE uint32_t vector_length (pointer vec);
259 INTERFACE pointer vector_elem (pointer vec, uint32_t ielem);
260 INTERFACE void set_vector_elem (pointer vec, uint32_t ielem, pointer a);
261
262 INTERFACE uint32_t
263 vector_length (pointer vec)
264 {
265 return vec->object.vector.length;
266 }
267
268 INTERFACE int
269 is_number (pointer p)
270 {
271 return type (p) == T_NUMBER;
272 }
273
274 INTERFACE int
275 is_integer (pointer p)
276 {
277 if (!is_number (p))
278 return 0;
279
280 if (num_is_integer (p) || ivalue (p) == rvalue (p))
281 return 1;
282
283 return 0;
284 }
285
286 INTERFACE int
287 is_real (pointer p)
288 {
289 return is_number (p) && !num_is_fixnum (p->object.number);
290 }
291
292 INTERFACE int
293 is_character (pointer p)
294 {
295 return type (p) == T_CHARACTER;
296 }
297
298 INTERFACE char *
299 string_value (pointer p)
300 {
301 return strvalue (p);
302 }
303
304 ecb_inline num
305 nvalue (pointer p)
306 {
307 return (p)->object.number;
308 }
309
310 static IVALUE
311 num_get_ivalue (const num n)
312 {
313 return num_is_fixnum (n) ? num_ivalue (n) : (IVALUE)num_rvalue (n);
314 }
315
316 static RVALUE
317 num_get_rvalue (const num n)
318 {
319 return num_is_fixnum (n) ? (RVALUE)num_ivalue (n) : num_rvalue (n);
320 }
321
322 INTERFACE IVALUE
323 ivalue (pointer p)
324 {
325 return num_get_ivalue (p->object.number);
326 }
327
328 INTERFACE RVALUE
329 rvalue (pointer p)
330 {
331 return num_get_rvalue (p->object.number);
332 }
333
334 #define ivalue_unchecked(p) ((p)->object.number.value.ivalue)
335 #if USE_REAL
336 # define rvalue_unchecked(p) ((p)->object.number.value.rvalue)
337 # define set_num_integer(p) (p)->object.number.is_fixnum=1;
338 # define set_num_real(p) (p)->object.number.is_fixnum=0;
339 #else
340 # define rvalue_unchecked(p) ((p)->object.number.value.ivalue)
341 # define set_num_integer(p) 0
342 # define set_num_real(p) 0
343 #endif
344
345 INTERFACE long
346 charvalue (pointer p)
347 {
348 return ivalue_unchecked (p);
349 }
350
351 INTERFACE int
352 is_port (pointer p)
353 {
354 return type (p) == T_PORT;
355 }
356
357 INTERFACE int
358 is_inport (pointer p)
359 {
360 return is_port (p) && p->object.port->kind & port_input;
361 }
362
363 INTERFACE int
364 is_outport (pointer p)
365 {
366 return is_port (p) && p->object.port->kind & port_output;
367 }
368
369 INTERFACE int
370 is_pair (pointer p)
371 {
372 return type (p) == T_PAIR;
373 }
374
375 #define car(p) ((p)->object.cons.car + 0)
376 #define cdr(p) ((p)->object.cons.cdr + 0)
377
378 static pointer caar (pointer p) { return car (car (p)); }
379 static pointer cadr (pointer p) { return car (cdr (p)); }
380 static pointer cdar (pointer p) { return cdr (car (p)); }
381 static pointer cddr (pointer p) { return cdr (cdr (p)); }
382
383 static pointer cadar (pointer p) { return car (cdr (car (p))); }
384 static pointer caddr (pointer p) { return car (cdr (cdr (p))); }
385 static pointer cdaar (pointer p) { return cdr (car (car (p))); }
386
387 INTERFACE void
388 set_car (pointer p, pointer q)
389 {
390 p->object.cons.car = q;
391 }
392
393 INTERFACE void
394 set_cdr (pointer p, pointer q)
395 {
396 p->object.cons.cdr = q;
397 }
398
399 INTERFACE pointer
400 pair_car (pointer p)
401 {
402 return car (p);
403 }
404
405 INTERFACE pointer
406 pair_cdr (pointer p)
407 {
408 return cdr (p);
409 }
410
411 INTERFACE int
412 is_symbol (pointer p)
413 {
414 return type (p) == T_SYMBOL;
415 }
416
417 INTERFACE char *
418 symname (pointer p)
419 {
420 return strvalue (car (p));
421 }
422
423 #if USE_PLIST
424 SCHEME_EXPORT int
425 hasprop (pointer p)
426 {
427 return typeflag (p) & T_SYMBOL;
428 }
429
430 # define symprop(p) cdr(p)
431 #endif
432
433 INTERFACE int
434 is_syntax (pointer p)
435 {
436 return typeflag (p) & T_SYNTAX;
437 }
438
439 INTERFACE int
440 is_proc (pointer p)
441 {
442 return type (p) == T_PROC;
443 }
444
445 INTERFACE int
446 is_foreign (pointer p)
447 {
448 return type (p) == T_FOREIGN;
449 }
450
451 INTERFACE char *
452 syntaxname (pointer p)
453 {
454 return strvalue (car (p));
455 }
456
457 #define procnum(p) ivalue (p)
458 static const char *procname (pointer x);
459
460 INTERFACE int
461 is_closure (pointer p)
462 {
463 return type (p) == T_CLOSURE;
464 }
465
466 INTERFACE int
467 is_macro (pointer p)
468 {
469 return type (p) == T_MACRO;
470 }
471
472 INTERFACE pointer
473 closure_code (pointer p)
474 {
475 return car (p);
476 }
477
478 INTERFACE pointer
479 closure_env (pointer p)
480 {
481 return cdr (p);
482 }
483
484 INTERFACE int
485 is_continuation (pointer p)
486 {
487 return type (p) == T_CONTINUATION;
488 }
489
490 #define cont_dump(p) cdr (p)
491 #define set_cont_dump(p,v) set_cdr ((p), (v))
492
493 /* To do: promise should be forced ONCE only */
494 INTERFACE int
495 is_promise (pointer p)
496 {
497 return type (p) == T_PROMISE;
498 }
499
500 INTERFACE int
501 is_environment (pointer p)
502 {
503 return type (p) == T_ENVIRONMENT;
504 }
505
506 #define setenvironment(p) set_typeflag ((p), T_ENVIRONMENT)
507
508 #define is_atom(p) (typeflag (p) & T_ATOM)
509 #define setatom(p) set_typeflag ((p), typeflag (p) | T_ATOM)
510 #define clratom(p) set_typeflag ((p), typeflag (p) & ~T_ATOM)
511
512 #define is_mark(p) (typeflag (p) & T_MARK)
513 #define setmark(p) set_typeflag ((p), typeflag (p) | T_MARK)
514 #define clrmark(p) set_typeflag ((p), typeflag (p) & ~T_MARK)
515
516 INTERFACE int
517 is_immutable (pointer p)
518 {
519 return typeflag (p) & T_IMMUTABLE && USE_ERROR_CHECKING;
520 }
521
522 INTERFACE void
523 setimmutable (pointer p)
524 {
525 #if USE_ERROR_CHECKING
526 set_typeflag (p, typeflag (p) | T_IMMUTABLE);
527 #endif
528 }
529
530 #if USE_CHAR_CLASSIFIERS
531 ecb_inline int
532 Cisalpha (int c)
533 {
534 return isascii (c) && isalpha (c);
535 }
536
537 ecb_inline int
538 Cisdigit (int c)
539 {
540 return isascii (c) && isdigit (c);
541 }
542
543 ecb_inline int
544 Cisspace (int c)
545 {
546 return isascii (c) && isspace (c);
547 }
548
549 ecb_inline int
550 Cisupper (int c)
551 {
552 return isascii (c) && isupper (c);
553 }
554
555 ecb_inline int
556 Cislower (int c)
557 {
558 return isascii (c) && islower (c);
559 }
560 #endif
561
562 #if USE_ASCII_NAMES
563 static const char *charnames[32] = {
564 "nul",
565 "soh",
566 "stx",
567 "etx",
568 "eot",
569 "enq",
570 "ack",
571 "bel",
572 "bs",
573 "ht",
574 "lf",
575 "vt",
576 "ff",
577 "cr",
578 "so",
579 "si",
580 "dle",
581 "dc1",
582 "dc2",
583 "dc3",
584 "dc4",
585 "nak",
586 "syn",
587 "etb",
588 "can",
589 "em",
590 "sub",
591 "esc",
592 "fs",
593 "gs",
594 "rs",
595 "us"
596 };
597
598 static int
599 is_ascii_name (const char *name, int *pc)
600 {
601 int i;
602
603 for (i = 0; i < 32; i++)
604 {
605 if (stricmp (name, charnames[i]) == 0)
606 {
607 *pc = i;
608 return 1;
609 }
610 }
611
612 if (stricmp (name, "del") == 0)
613 {
614 *pc = 127;
615 return 1;
616 }
617
618 return 0;
619 }
620
621 #endif
622
623 static int file_push (SCHEME_P_ const char *fname);
624 static void file_pop (SCHEME_P);
625 static int file_interactive (SCHEME_P);
626 ecb_inline int is_one_of (char *s, int c);
627 static int alloc_cellseg (SCHEME_P_ int n);
628 ecb_inline pointer get_cell (SCHEME_P_ pointer a, pointer b);
629 static void finalize_cell (SCHEME_P_ pointer a);
630 static int count_consecutive_cells (pointer x, int needed);
631 static pointer find_slot_in_env (SCHEME_P_ pointer env, pointer sym, int all);
632 static pointer mk_number (SCHEME_P_ const num n);
633 static char *store_string (SCHEME_P_ uint32_t len, const char *str, char fill);
634 static pointer mk_vector (SCHEME_P_ uint32_t len);
635 static pointer mk_atom (SCHEME_P_ char *q);
636 static pointer mk_sharp_const (SCHEME_P_ char *name);
637
638 #if USE_PORTS
639 static pointer mk_port (SCHEME_P_ port *p);
640 static pointer port_from_filename (SCHEME_P_ const char *fn, int prop);
641 static pointer port_from_file (SCHEME_P_ int, int prop);
642 static pointer port_from_string (SCHEME_P_ char *start, char *past_the_end, int prop);
643 static port *port_rep_from_filename (SCHEME_P_ const char *fn, int prop);
644 static port *port_rep_from_file (SCHEME_P_ int, int prop);
645 static port *port_rep_from_string (SCHEME_P_ char *start, char *past_the_end, int prop);
646 static void port_close (SCHEME_P_ pointer p, int flag);
647 #endif
648 static void mark (pointer a);
649 static void gc (SCHEME_P_ pointer a, pointer b);
650 static int basic_inchar (port *pt);
651 static int inchar (SCHEME_P);
652 static void backchar (SCHEME_P_ int c);
653 static char *readstr_upto (SCHEME_P_ char *delim);
654 static pointer readstrexp (SCHEME_P);
655 ecb_inline int skipspace (SCHEME_P);
656 static int token (SCHEME_P);
657 static void printslashstring (SCHEME_P_ char *s, int len);
658 static void atom2str (SCHEME_P_ pointer l, int f, char **pp, int *plen);
659 static void printatom (SCHEME_P_ pointer l, int f);
660 static pointer mk_proc (SCHEME_P_ enum scheme_opcodes op);
661 static pointer mk_closure (SCHEME_P_ pointer c, pointer e);
662 static pointer mk_continuation (SCHEME_P_ pointer d);
663 static pointer reverse (SCHEME_P_ pointer a);
664 static pointer reverse_in_place (SCHEME_P_ pointer term, pointer list);
665 static pointer revappend (SCHEME_P_ pointer a, pointer b);
666 static pointer ss_get_cont (SCHEME_P);
667 static void ss_set_cont (SCHEME_P_ pointer cont);
668 static void dump_stack_mark (SCHEME_P);
669 static int opexe_0 (SCHEME_P_ enum scheme_opcodes op);
670 static int opexe_1 (SCHEME_P_ enum scheme_opcodes op);
671 static int opexe_2 (SCHEME_P_ enum scheme_opcodes op);
672 static int opexe_3 (SCHEME_P_ enum scheme_opcodes op);
673 static int opexe_4 (SCHEME_P_ enum scheme_opcodes op);
674 static int opexe_5 (SCHEME_P_ enum scheme_opcodes op);
675 static int opexe_6 (SCHEME_P_ enum scheme_opcodes op);
676 static void Eval_Cycle (SCHEME_P_ enum scheme_opcodes op);
677 static void assign_syntax (SCHEME_P_ const char *name);
678 static int syntaxnum (pointer p);
679 static void assign_proc (SCHEME_P_ enum scheme_opcodes, const char *name);
680
681 static num
682 num_op (enum num_op op, num a, num b)
683 {
684 num ret;
685
686 num_set_fixnum (ret, num_is_fixnum (a) && num_is_fixnum (b));
687
688 if (num_is_fixnum (ret))
689 {
690 IVALUE av = num_get_ivalue (a);
691 IVALUE bv = num_get_ivalue (b);
692
693 switch (op)
694 {
695 case NUM_ADD: av += bv; break;
696 case NUM_SUB: av -= bv; break;
697 case NUM_MUL: av *= bv; break;
698 case NUM_INTDIV: av /= bv; break;
699 }
700
701 num_set_ivalue (ret, av);
702 }
703 else
704 {
705 RVALUE av = num_get_rvalue (a);
706 RVALUE bv = num_get_rvalue (b);
707
708 switch (op)
709 {
710 case NUM_ADD: av += bv; break;
711 case NUM_SUB: av -= bv; break;
712 case NUM_MUL: av *= bv; break;
713 case NUM_INTDIV: av /= bv; break;
714 }
715
716 num_set_rvalue (ret, av);
717 }
718
719 return ret;
720 }
721
722 static num
723 num_div (num a, num b)
724 {
725 num ret;
726
727 num_set_fixnum (ret, num_is_fixnum (a) && num_is_fixnum (b) && num_get_ivalue (a) % num_get_ivalue (b) == 0);
728
729 if (num_is_fixnum (ret))
730 num_set_ivalue (ret, num_get_ivalue (a) / num_get_ivalue (b));
731 else
732 num_set_rvalue (ret, num_get_rvalue (a) / num_get_rvalue (b));
733
734 return ret;
735 }
736
737 static num
738 num_rem (num a, num b)
739 {
740 num ret;
741 long e1, e2, res;
742
743 num_set_fixnum (ret, num_is_fixnum (a) && num_is_fixnum (b));
744 e1 = num_get_ivalue (a);
745 e2 = num_get_ivalue (b);
746 res = e1 % e2;
747
748 /* remainder should have same sign as second operand */
749 if (res > 0)
750 {
751 if (e1 < 0)
752 res -= labs (e2);
753 }
754 else if (res < 0)
755 {
756 if (e1 > 0)
757 res += labs (e2);
758 }
759
760 num_set_ivalue (ret, res);
761 return ret;
762 }
763
764 static num
765 num_mod (num a, num b)
766 {
767 num ret;
768 long e1, e2, res;
769
770 num_set_fixnum (ret, num_is_fixnum (a) && num_is_fixnum (b));
771 e1 = num_get_ivalue (a);
772 e2 = num_get_ivalue (b);
773 res = e1 % e2;
774
775 /* modulo should have same sign as second operand */
776 if (res * e2 < 0)
777 res += e2;
778
779 num_set_ivalue (ret, res);
780 return ret;
781 }
782
783 /* this completely disrespects NaNs, but r5rs doesn't even allow NaNs */
784 static int
785 num_cmp (num a, num b)
786 {
787 int is_fixnum = num_is_fixnum (a) && num_is_fixnum (b);
788 int ret;
789
790 if (is_fixnum)
791 {
792 IVALUE av = num_get_ivalue (a);
793 IVALUE bv = num_get_ivalue (b);
794
795 ret = av == bv ? 0 : av < bv ? -1 : +1;
796 }
797 else
798 {
799 RVALUE av = num_get_rvalue (a);
800 RVALUE bv = num_get_rvalue (b);
801
802 ret = av == bv ? 0 : av < bv ? -1 : +1;
803 }
804
805 return ret;
806 }
807
808 #if USE_MATH
809
810 /* Round to nearest. Round to even if midway */
811 static double
812 round_per_R5RS (double x)
813 {
814 double fl = floor (x);
815 double ce = ceil (x);
816 double dfl = x - fl;
817 double dce = ce - x;
818
819 if (dfl > dce)
820 return ce;
821 else if (dfl < dce)
822 return fl;
823 else
824 {
825 if (fmod (fl, 2) == 0) /* I imagine this holds */
826 return fl;
827 else
828 return ce;
829 }
830 }
831 #endif
832
833 static int
834 is_zero_rvalue (RVALUE x)
835 {
836 return x == 0;
837 #if 0
838 #if USE_REAL
839 return x < DBL_MIN && x > -DBL_MIN; /* why the hate of denormals? this should be == 0. */
840 #else
841 return x == 0;
842 #endif
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 ecb_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 ecb_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 ecb_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 ecb_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 ecb_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 ecb_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 ecb_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 ecb_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 ecb_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 ecb_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 ecb_inline void
2924 set_slot_in_env (SCHEME_P_ pointer slot, pointer value)
2925 {
2926 set_cdr (slot, value);
2927 }
2928
2929 ecb_inline pointer
2930 slot_value_in_env (pointer slot)
2931 {
2932 return cdr (slot);
2933 }
2934
2935 /* ========== Evaluation Cycle ========== */
2936
2937 static int
2938 xError_1 (SCHEME_P_ const char *s, pointer a)
2939 {
2940 #if USE_ERROR_HOOK
2941 pointer x;
2942 pointer hdl = SCHEME_V->ERROR_HOOK;
2943 #endif
2944
2945 #if USE_PRINTF
2946 #if SHOW_ERROR_LINE
2947 char sbuf[STRBUFFSIZE];
2948
2949 /* make sure error is not in REPL */
2950 if ((SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file) && SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.file != STDIN_FILENO)
2951 {
2952 int ln = SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line;
2953 const char *fname = SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.filename;
2954
2955 /* should never happen */
2956 if (!fname)
2957 fname = "<unknown>";
2958
2959 /* we started from 0 */
2960 ln++;
2961 snprintf (sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s);
2962
2963 s = sbuf;
2964 }
2965 #endif
2966 #endif
2967
2968 #if USE_ERROR_HOOK
2969 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, hdl, 1);
2970
2971 if (x != NIL)
2972 {
2973 pointer code = a
2974 ? cons (cons (SCHEME_V->QUOTE, cons (a, NIL)), NIL)
2975 : NIL;
2976
2977 code = cons (mk_string (SCHEME_A_ s), code);
2978 setimmutable (car (code));
2979 SCHEME_V->code = cons (slot_value_in_env (x), code);
2980 SCHEME_V->op = OP_EVAL;
2981
2982 return 0;
2983 }
2984 #endif
2985
2986 if (a)
2987 SCHEME_V->args = cons (a, NIL);
2988 else
2989 SCHEME_V->args = NIL;
2990
2991 SCHEME_V->args = cons (mk_string (SCHEME_A_ s), SCHEME_V->args);
2992 setimmutable (car (SCHEME_V->args));
2993 SCHEME_V->op = OP_ERR0;
2994
2995 return 0;
2996 }
2997
2998 #define Error_1(s, a) return xError_1(SCHEME_A_ USE_ERROR_CHECKING ? s : "", a)
2999 #define Error_0(s) Error_1 (s, 0)
3000
3001 /* Too small to turn into function */
3002 #define BEGIN do {
3003 #define END } while (0)
3004 #define s_goto(a) BEGIN \
3005 SCHEME_V->op = a; \
3006 return 0; END
3007
3008 #define s_return(a) return xs_return (SCHEME_A_ a)
3009
3010 #ifndef USE_SCHEME_STACK
3011
3012 /* this structure holds all the interpreter's registers */
3013 struct dump_stack_frame
3014 {
3015 enum scheme_opcodes op;
3016 pointer args;
3017 pointer envir;
3018 pointer code;
3019 };
3020
3021 # define STACK_GROWTH 3
3022
3023 static void
3024 s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3025 {
3026 int nframes = (uintptr_t)SCHEME_V->dump;
3027 struct dump_stack_frame *next_frame;
3028
3029 /* enough room for the next frame? */
3030 if (nframes >= SCHEME_V->dump_size)
3031 {
3032 SCHEME_V->dump_size += STACK_GROWTH;
3033 SCHEME_V->dump_base = realloc (SCHEME_V->dump_base, sizeof (struct dump_stack_frame) * SCHEME_V->dump_size);
3034 }
3035
3036 next_frame = SCHEME_V->dump_base + nframes;
3037
3038 next_frame->op = op;
3039 next_frame->args = args;
3040 next_frame->envir = SCHEME_V->envir;
3041 next_frame->code = code;
3042
3043 SCHEME_V->dump = (pointer)(uintptr_t)(nframes + 1);
3044 }
3045
3046 static int
3047 xs_return (SCHEME_P_ pointer a)
3048 {
3049 int nframes = (uintptr_t)SCHEME_V->dump;
3050 struct dump_stack_frame *frame;
3051
3052 SCHEME_V->value = a;
3053
3054 if (nframes <= 0)
3055 return -1;
3056
3057 frame = &SCHEME_V->dump_base[--nframes];
3058 SCHEME_V->op = frame->op;
3059 SCHEME_V->args = frame->args;
3060 SCHEME_V->envir = frame->envir;
3061 SCHEME_V->code = frame->code;
3062 SCHEME_V->dump = (pointer)(uintptr_t)nframes;
3063
3064 return 0;
3065 }
3066
3067 ecb_inline void
3068 dump_stack_reset (SCHEME_P)
3069 {
3070 /* in this implementation, SCHEME_V->dump is the number of frames on the stack */
3071 SCHEME_V->dump = (pointer)+0;
3072 }
3073
3074 ecb_inline void
3075 dump_stack_initialize (SCHEME_P)
3076 {
3077 SCHEME_V->dump_size = 0;
3078 SCHEME_V->dump_base = 0;
3079 dump_stack_reset (SCHEME_A);
3080 }
3081
3082 static void
3083 dump_stack_free (SCHEME_P)
3084 {
3085 free (SCHEME_V->dump_base);
3086 SCHEME_V->dump_base = 0;
3087 SCHEME_V->dump = (pointer)0;
3088 SCHEME_V->dump_size = 0;
3089 }
3090
3091 static void
3092 dump_stack_mark (SCHEME_P)
3093 {
3094 int nframes = (uintptr_t)SCHEME_V->dump;
3095 int i;
3096
3097 for (i = 0; i < nframes; i++)
3098 {
3099 struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3100
3101 mark (frame->args);
3102 mark (frame->envir);
3103 mark (frame->code);
3104 }
3105 }
3106
3107 static pointer
3108 ss_get_cont (SCHEME_P)
3109 {
3110 int nframes = (uintptr_t)SCHEME_V->dump;
3111 int i;
3112
3113 pointer cont = NIL;
3114
3115 for (i = nframes; i--; )
3116 {
3117 struct dump_stack_frame *frame = SCHEME_V->dump_base + i;
3118
3119 cont = cons (mk_integer (SCHEME_A_ frame->op),
3120 cons (frame->args,
3121 cons (frame->envir,
3122 cons (frame->code,
3123 cont))));
3124 }
3125
3126 return cont;
3127 }
3128
3129 static void
3130 ss_set_cont (SCHEME_P_ pointer cont)
3131 {
3132 int i = 0;
3133 struct dump_stack_frame *frame = SCHEME_V->dump_base;
3134
3135 while (cont != NIL)
3136 {
3137 frame->op = ivalue (car (cont)); cont = cdr (cont);
3138 frame->args = car (cont) ; cont = cdr (cont);
3139 frame->envir = car (cont) ; cont = cdr (cont);
3140 frame->code = car (cont) ; cont = cdr (cont);
3141
3142 ++frame;
3143 ++i;
3144 }
3145
3146 SCHEME_V->dump = (pointer)(uintptr_t)i;
3147 }
3148
3149 #else
3150
3151 ecb_inline void
3152 dump_stack_reset (SCHEME_P)
3153 {
3154 SCHEME_V->dump = NIL;
3155 }
3156
3157 ecb_inline void
3158 dump_stack_initialize (SCHEME_P)
3159 {
3160 dump_stack_reset (SCHEME_A);
3161 }
3162
3163 static void
3164 dump_stack_free (SCHEME_P)
3165 {
3166 SCHEME_V->dump = NIL;
3167 }
3168
3169 static int
3170 xs_return (SCHEME_P_ pointer a)
3171 {
3172 pointer dump = SCHEME_V->dump;
3173
3174 SCHEME_V->value = a;
3175
3176 if (dump == NIL)
3177 return -1;
3178
3179 SCHEME_V->op = ivalue (car (dump)); dump = cdr (dump);
3180 SCHEME_V->args = car (dump) ; dump = cdr (dump);
3181 SCHEME_V->envir = car (dump) ; dump = cdr (dump);
3182 SCHEME_V->code = car (dump) ; dump = cdr (dump);
3183
3184 SCHEME_V->dump = dump;
3185
3186 return 0;
3187 }
3188
3189 static void
3190 s_save (SCHEME_P_ enum scheme_opcodes op, pointer args, pointer code)
3191 {
3192 SCHEME_V->dump = cons (mk_integer (SCHEME_A_ op),
3193 cons (args,
3194 cons (SCHEME_V->envir,
3195 cons (code,
3196 SCHEME_V->dump))));
3197 }
3198
3199 static void
3200 dump_stack_mark (SCHEME_P)
3201 {
3202 mark (SCHEME_V->dump);
3203 }
3204
3205 static pointer
3206 ss_get_cont (SCHEME_P)
3207 {
3208 return SCHEME_V->dump;
3209 }
3210
3211 static void
3212 ss_set_cont (SCHEME_P_ pointer cont)
3213 {
3214 SCHEME_V->dump = cont;
3215 }
3216
3217 #endif
3218
3219 #define s_retbool(tf) s_return ((tf) ? S_T : S_F)
3220
3221 static int
3222 opexe_0 (SCHEME_P_ enum scheme_opcodes op)
3223 {
3224 pointer args = SCHEME_V->args;
3225 pointer x, y;
3226
3227 switch (op)
3228 {
3229 case OP_LOAD: /* load */
3230 if (file_interactive (SCHEME_A))
3231 {
3232 xwrstr ("Loading "); xwrstr (strvalue (car (args))); xwrstr ("\n");
3233 //D fprintf (SCHEME_V->outport->object.port->rep.stdio.file, "Loading %s\n", strvalue (car (args)));
3234 }
3235
3236 if (!file_push (SCHEME_A_ strvalue (car (args))))
3237 Error_1 ("unable to open", car (args));
3238 else
3239 {
3240 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
3241 s_goto (OP_T0LVL);
3242 }
3243
3244 case OP_T0LVL: /* top level */
3245
3246 /* If we reached the end of file, this loop is done. */
3247 if (SCHEME_V->loadport->object.port->kind & port_saw_EOF)
3248 {
3249 if (SCHEME_V->file_i == 0)
3250 {
3251 SCHEME_V->args = NIL;
3252 s_goto (OP_QUIT);
3253 }
3254 else
3255 {
3256 file_pop (SCHEME_A);
3257 s_return (SCHEME_V->value);
3258 }
3259
3260 /* NOTREACHED */
3261 }
3262
3263 /* If interactive, be nice to user. */
3264 if (file_interactive (SCHEME_A))
3265 {
3266 SCHEME_V->envir = SCHEME_V->global_env;
3267 dump_stack_reset (SCHEME_A);
3268 putstr (SCHEME_A_ "\n");
3269 putstr (SCHEME_A_ prompt);
3270 }
3271
3272 /* Set up another iteration of REPL */
3273 SCHEME_V->nesting = 0;
3274 SCHEME_V->save_inport = SCHEME_V->inport;
3275 SCHEME_V->inport = SCHEME_V->loadport;
3276 s_save (SCHEME_A_ OP_T0LVL, NIL, NIL);
3277 s_save (SCHEME_A_ OP_VALUEPRINT, NIL, NIL);
3278 s_save (SCHEME_A_ OP_T1LVL, NIL, NIL);
3279 s_goto (OP_READ_INTERNAL);
3280
3281 case OP_T1LVL: /* top level */
3282 SCHEME_V->code = SCHEME_V->value;
3283 SCHEME_V->inport = SCHEME_V->save_inport;
3284 s_goto (OP_EVAL);
3285
3286 case OP_READ_INTERNAL: /* internal read */
3287 SCHEME_V->tok = token (SCHEME_A);
3288
3289 if (SCHEME_V->tok == TOK_EOF)
3290 s_return (S_EOF);
3291
3292 s_goto (OP_RDSEXPR);
3293
3294 case OP_GENSYM:
3295 s_return (gensym (SCHEME_A));
3296
3297 case OP_VALUEPRINT: /* print evaluation result */
3298
3299 /* OP_VALUEPRINT is always pushed, because when changing from
3300 non-interactive to interactive mode, it needs to be
3301 already on the stack */
3302 #if USE_TRACING
3303 if (SCHEME_V->tracing)
3304 putstr (SCHEME_A_ "\nGives: ");
3305 #endif
3306
3307 if (file_interactive (SCHEME_A))
3308 {
3309 SCHEME_V->print_flag = 1;
3310 SCHEME_V->args = SCHEME_V->value;
3311 s_goto (OP_P0LIST);
3312 }
3313 else
3314 s_return (SCHEME_V->value);
3315
3316 case OP_EVAL: /* main part of evaluation */
3317 #if USE_TRACING
3318 if (SCHEME_V->tracing)
3319 {
3320 /*s_save(SCHEME_A_ OP_VALUEPRINT,NIL,NIL); */
3321 s_save (SCHEME_A_ OP_REAL_EVAL, args, SCHEME_V->code);
3322 SCHEME_V->args = SCHEME_V->code;
3323 putstr (SCHEME_A_ "\nEval: ");
3324 s_goto (OP_P0LIST);
3325 }
3326
3327 /* fall through */
3328
3329 case OP_REAL_EVAL:
3330 #endif
3331 if (is_symbol (SCHEME_V->code)) /* symbol */
3332 {
3333 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3334
3335 if (x != NIL)
3336 s_return (slot_value_in_env (x));
3337 else
3338 Error_1 ("eval: unbound variable:", SCHEME_V->code);
3339 }
3340 else if (is_pair (SCHEME_V->code))
3341 {
3342 x = car (SCHEME_V->code);
3343
3344 if (is_syntax (x)) /* SYNTAX */
3345 {
3346 SCHEME_V->code = cdr (SCHEME_V->code);
3347 s_goto (syntaxnum (x));
3348 }
3349 else /* first, eval top element and eval arguments */
3350 {
3351 s_save (SCHEME_A_ OP_E0ARGS, NIL, SCHEME_V->code);
3352 /* If no macros => s_save(SCHEME_A_ OP_E1ARGS, NIL, cdr(SCHEME_V->code)); */
3353 SCHEME_V->code = x;
3354 s_goto (OP_EVAL);
3355 }
3356 }
3357 else
3358 s_return (SCHEME_V->code);
3359
3360 case OP_E0ARGS: /* eval arguments */
3361 if (is_macro (SCHEME_V->value)) /* macro expansion */
3362 {
3363 s_save (SCHEME_A_ OP_DOMACRO, NIL, NIL);
3364 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3365 SCHEME_V->code = SCHEME_V->value;
3366 s_goto (OP_APPLY);
3367 }
3368 else
3369 {
3370 SCHEME_V->code = cdr (SCHEME_V->code);
3371 s_goto (OP_E1ARGS);
3372 }
3373
3374 case OP_E1ARGS: /* eval arguments */
3375 args = cons (SCHEME_V->value, args);
3376
3377 if (is_pair (SCHEME_V->code)) /* continue */
3378 {
3379 s_save (SCHEME_A_ OP_E1ARGS, args, cdr (SCHEME_V->code));
3380 SCHEME_V->code = car (SCHEME_V->code);
3381 SCHEME_V->args = NIL;
3382 s_goto (OP_EVAL);
3383 }
3384 else /* end */
3385 {
3386 args = reverse_in_place (SCHEME_A_ NIL, args);
3387 SCHEME_V->code = car (args);
3388 SCHEME_V->args = cdr (args);
3389 s_goto (OP_APPLY);
3390 }
3391
3392 #if USE_TRACING
3393
3394 case OP_TRACING:
3395 {
3396 int tr = SCHEME_V->tracing;
3397
3398 SCHEME_V->tracing = ivalue (car (args));
3399 s_return (mk_integer (SCHEME_A_ tr));
3400 }
3401
3402 #endif
3403
3404 case OP_APPLY: /* apply 'code' to 'args' */
3405 #if USE_TRACING
3406 if (SCHEME_V->tracing)
3407 {
3408 s_save (SCHEME_A_ OP_REAL_APPLY, args, SCHEME_V->code);
3409 SCHEME_V->print_flag = 1;
3410 /* args=cons(SCHEME_V->code,args); */
3411 putstr (SCHEME_A_ "\nApply to: ");
3412 s_goto (OP_P0LIST);
3413 }
3414
3415 /* fall through */
3416
3417 case OP_REAL_APPLY:
3418 #endif
3419 if (is_proc (SCHEME_V->code))
3420 s_goto (procnum (SCHEME_V->code)); /* PROCEDURE */
3421 else if (is_foreign (SCHEME_V->code))
3422 {
3423 /* Keep nested calls from GC'ing the arglist */
3424 push_recent_alloc (SCHEME_A_ args, NIL);
3425 x = SCHEME_V->code->object.ff (SCHEME_A_ args);
3426
3427 s_return (x);
3428 }
3429 else if (is_closure (SCHEME_V->code) || is_macro (SCHEME_V->code) || is_promise (SCHEME_V->code)) /* CLOSURE */
3430 {
3431 /* Should not accept promise */
3432 /* make environment */
3433 new_frame_in_env (SCHEME_A_ closure_env (SCHEME_V->code));
3434
3435 for (x = car (closure_code (SCHEME_V->code)), y = args; is_pair (x); x = cdr (x), y = cdr (y))
3436 {
3437 if (y == NIL)
3438 Error_0 ("not enough arguments");
3439 else
3440 new_slot_in_env (SCHEME_A_ car (x), car (y));
3441 }
3442
3443 if (x == NIL)
3444 {
3445 /*--
3446 * if (y != NIL) {
3447 * Error_0("too many arguments");
3448 * }
3449 */
3450 }
3451 else if (is_symbol (x))
3452 new_slot_in_env (SCHEME_A_ x, y);
3453 else
3454 Error_1 ("syntax error in closure: not a symbol:", x);
3455
3456 SCHEME_V->code = cdr (closure_code (SCHEME_V->code));
3457 SCHEME_V->args = NIL;
3458 s_goto (OP_BEGIN);
3459 }
3460 else if (is_continuation (SCHEME_V->code)) /* CONTINUATION */
3461 {
3462 ss_set_cont (SCHEME_A_ cont_dump (SCHEME_V->code));
3463 s_return (args != NIL ? car (args) : NIL);
3464 }
3465 else
3466 Error_0 ("illegal function");
3467
3468 case OP_DOMACRO: /* do macro */
3469 SCHEME_V->code = SCHEME_V->value;
3470 s_goto (OP_EVAL);
3471
3472 #if 1
3473
3474 case OP_LAMBDA: /* lambda */
3475 /* If the hook is defined, apply it to SCHEME_V->code, otherwise
3476 set SCHEME_V->value fall thru */
3477 {
3478 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->COMPILE_HOOK, 1);
3479
3480 if (f != NIL)
3481 {
3482 s_save (SCHEME_A_ OP_LAMBDA1, args, SCHEME_V->code);
3483 SCHEME_V->args = cons (SCHEME_V->code, NIL);
3484 SCHEME_V->code = slot_value_in_env (f);
3485 s_goto (OP_APPLY);
3486 }
3487
3488 SCHEME_V->value = SCHEME_V->code;
3489 /* Fallthru */
3490 }
3491
3492 case OP_LAMBDA1:
3493 s_return (mk_closure (SCHEME_A_ SCHEME_V->value, SCHEME_V->envir));
3494
3495 #else
3496
3497 case OP_LAMBDA: /* lambda */
3498 s_return (mk_closure (SCHEME_A_ SCHEME_V->code, SCHEME_V->envir));
3499
3500 #endif
3501
3502 case OP_MKCLOSURE: /* make-closure */
3503 x = car (args);
3504
3505 if (car (x) == SCHEME_V->LAMBDA)
3506 x = cdr (x);
3507
3508 if (cdr (args) == NIL)
3509 y = SCHEME_V->envir;
3510 else
3511 y = cadr (args);
3512
3513 s_return (mk_closure (SCHEME_A_ x, y));
3514
3515 case OP_QUOTE: /* quote */
3516 s_return (car (SCHEME_V->code));
3517
3518 case OP_DEF0: /* define */
3519 if (is_immutable (car (SCHEME_V->code)))
3520 Error_1 ("define: unable to alter immutable", car (SCHEME_V->code));
3521
3522 if (is_pair (car (SCHEME_V->code)))
3523 {
3524 x = caar (SCHEME_V->code);
3525 SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3526 }
3527 else
3528 {
3529 x = car (SCHEME_V->code);
3530 SCHEME_V->code = cadr (SCHEME_V->code);
3531 }
3532
3533 if (!is_symbol (x))
3534 Error_0 ("variable is not a symbol");
3535
3536 s_save (SCHEME_A_ OP_DEF1, NIL, x);
3537 s_goto (OP_EVAL);
3538
3539 case OP_DEF1: /* define */
3540 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3541
3542 if (x != NIL)
3543 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3544 else
3545 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3546
3547 s_return (SCHEME_V->code);
3548
3549
3550 case OP_DEFP: /* defined? */
3551 x = SCHEME_V->envir;
3552
3553 if (cdr (args) != NIL)
3554 x = cadr (args);
3555
3556 s_retbool (find_slot_in_env (SCHEME_A_ x, car (args), 1) != NIL);
3557
3558 case OP_SET0: /* set! */
3559 if (is_immutable (car (SCHEME_V->code)))
3560 Error_1 ("set!: unable to alter immutable variable", car (SCHEME_V->code));
3561
3562 s_save (SCHEME_A_ OP_SET1, NIL, car (SCHEME_V->code));
3563 SCHEME_V->code = cadr (SCHEME_V->code);
3564 s_goto (OP_EVAL);
3565
3566 case OP_SET1: /* set! */
3567 y = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 1);
3568
3569 if (y != NIL)
3570 {
3571 set_slot_in_env (SCHEME_A_ y, SCHEME_V->value);
3572 s_return (SCHEME_V->value);
3573 }
3574 else
3575 Error_1 ("set!: unbound variable:", SCHEME_V->code);
3576
3577
3578 case OP_BEGIN: /* begin */
3579 if (!is_pair (SCHEME_V->code))
3580 s_return (SCHEME_V->code);
3581
3582 if (cdr (SCHEME_V->code) != NIL)
3583 s_save (SCHEME_A_ OP_BEGIN, NIL, cdr (SCHEME_V->code));
3584
3585 SCHEME_V->code = car (SCHEME_V->code);
3586 s_goto (OP_EVAL);
3587
3588 case OP_IF0: /* if */
3589 s_save (SCHEME_A_ OP_IF1, NIL, cdr (SCHEME_V->code));
3590 SCHEME_V->code = car (SCHEME_V->code);
3591 s_goto (OP_EVAL);
3592
3593 case OP_IF1: /* if */
3594 if (is_true (SCHEME_V->value))
3595 SCHEME_V->code = car (SCHEME_V->code);
3596 else
3597 SCHEME_V->code = cadr (SCHEME_V->code); /* (if #f 1) ==> () because * car(NIL) = NIL */
3598 s_goto (OP_EVAL);
3599
3600 case OP_LET0: /* let */
3601 SCHEME_V->args = NIL;
3602 SCHEME_V->value = SCHEME_V->code;
3603 SCHEME_V->code = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code);
3604 s_goto (OP_LET1);
3605
3606 case OP_LET1: /* let (calculate parameters) */
3607 args = cons (SCHEME_V->value, args);
3608
3609 if (is_pair (SCHEME_V->code)) /* continue */
3610 {
3611 if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3612 Error_1 ("Bad syntax of binding spec in let :", car (SCHEME_V->code));
3613
3614 s_save (SCHEME_A_ OP_LET1, args, cdr (SCHEME_V->code));
3615 SCHEME_V->code = cadar (SCHEME_V->code);
3616 SCHEME_V->args = NIL;
3617 s_goto (OP_EVAL);
3618 }
3619 else /* end */
3620 {
3621 args = reverse_in_place (SCHEME_A_ NIL, args);
3622 SCHEME_V->code = car (args);
3623 SCHEME_V->args = cdr (args);
3624 s_goto (OP_LET2);
3625 }
3626
3627 case OP_LET2: /* let */
3628 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3629
3630 for (x = is_symbol (car (SCHEME_V->code)) ? cadr (SCHEME_V->code) : car (SCHEME_V->code), y = args;
3631 y != NIL; x = cdr (x), y = cdr (y))
3632 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3633
3634 if (is_symbol (car (SCHEME_V->code))) /* named let */
3635 {
3636 for (x = cadr (SCHEME_V->code), args = NIL; x != NIL; x = cdr (x))
3637 {
3638 if (!is_pair (x))
3639 Error_1 ("Bad syntax of binding in let :", x);
3640
3641 if (!is_list (SCHEME_A_ car (x)))
3642 Error_1 ("Bad syntax of binding in let :", car (x));
3643
3644 args = cons (caar (x), args);
3645 }
3646
3647 x = mk_closure (SCHEME_A_ cons (reverse_in_place (SCHEME_A_ NIL, args), cddr (SCHEME_V->code)),
3648 SCHEME_V->envir);
3649 new_slot_in_env (SCHEME_A_ car (SCHEME_V->code), x);
3650 SCHEME_V->code = cddr (SCHEME_V->code);
3651 }
3652 else
3653 {
3654 SCHEME_V->code = cdr (SCHEME_V->code);
3655 }
3656
3657 SCHEME_V->args = NIL;
3658 s_goto (OP_BEGIN);
3659
3660 case OP_LET0AST: /* let* */
3661 if (car (SCHEME_V->code) == NIL)
3662 {
3663 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3664 SCHEME_V->code = cdr (SCHEME_V->code);
3665 s_goto (OP_BEGIN);
3666 }
3667
3668 if (!is_pair (car (SCHEME_V->code)) || !is_pair (caar (SCHEME_V->code)) || !is_pair (cdaar (SCHEME_V->code)))
3669 Error_1 ("Bad syntax of binding spec in let* :", car (SCHEME_V->code));
3670
3671 s_save (SCHEME_A_ OP_LET1AST, cdr (SCHEME_V->code), car (SCHEME_V->code));
3672 SCHEME_V->code = car (cdaar (SCHEME_V->code));
3673 s_goto (OP_EVAL);
3674
3675 case OP_LET1AST: /* let* (make new frame) */
3676 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3677 s_goto (OP_LET2AST);
3678
3679 case OP_LET2AST: /* let* (calculate parameters) */
3680 new_slot_in_env (SCHEME_A_ caar (SCHEME_V->code), SCHEME_V->value);
3681 SCHEME_V->code = cdr (SCHEME_V->code);
3682
3683 if (is_pair (SCHEME_V->code)) /* continue */
3684 {
3685 s_save (SCHEME_A_ OP_LET2AST, args, SCHEME_V->code);
3686 SCHEME_V->code = cadar (SCHEME_V->code);
3687 SCHEME_V->args = NIL;
3688 s_goto (OP_EVAL);
3689 }
3690 else /* end */
3691 {
3692 SCHEME_V->code = args;
3693 SCHEME_V->args = NIL;
3694 s_goto (OP_BEGIN);
3695 }
3696
3697 case OP_LET0REC: /* letrec */
3698 new_frame_in_env (SCHEME_A_ SCHEME_V->envir);
3699 SCHEME_V->args = NIL;
3700 SCHEME_V->value = SCHEME_V->code;
3701 SCHEME_V->code = car (SCHEME_V->code);
3702 s_goto (OP_LET1REC);
3703
3704 case OP_LET1REC: /* letrec (calculate parameters) */
3705 args = cons (SCHEME_V->value, args);
3706
3707 if (is_pair (SCHEME_V->code)) /* continue */
3708 {
3709 if (!is_pair (car (SCHEME_V->code)) || !is_pair (cdar (SCHEME_V->code)))
3710 Error_1 ("Bad syntax of binding spec in letrec :", car (SCHEME_V->code));
3711
3712 s_save (SCHEME_A_ OP_LET1REC, args, cdr (SCHEME_V->code));
3713 SCHEME_V->code = cadar (SCHEME_V->code);
3714 SCHEME_V->args = NIL;
3715 s_goto (OP_EVAL);
3716 }
3717 else /* end */
3718 {
3719 args = reverse_in_place (SCHEME_A_ NIL, args);
3720 SCHEME_V->code = car (args);
3721 SCHEME_V->args = cdr (args);
3722 s_goto (OP_LET2REC);
3723 }
3724
3725 case OP_LET2REC: /* letrec */
3726 for (x = car (SCHEME_V->code), y = args; y != NIL; x = cdr (x), y = cdr (y))
3727 new_slot_in_env (SCHEME_A_ caar (x), car (y));
3728
3729 SCHEME_V->code = cdr (SCHEME_V->code);
3730 SCHEME_V->args = NIL;
3731 s_goto (OP_BEGIN);
3732
3733 case OP_COND0: /* cond */
3734 if (!is_pair (SCHEME_V->code))
3735 Error_0 ("syntax error in cond");
3736
3737 s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3738 SCHEME_V->code = caar (SCHEME_V->code);
3739 s_goto (OP_EVAL);
3740
3741 case OP_COND1: /* cond */
3742 if (is_true (SCHEME_V->value))
3743 {
3744 if ((SCHEME_V->code = cdar (SCHEME_V->code)) == NIL)
3745 s_return (SCHEME_V->value);
3746
3747 if (car (SCHEME_V->code) == SCHEME_V->FEED_TO)
3748 {
3749 if (!is_pair (cdr (SCHEME_V->code)))
3750 Error_0 ("syntax error in cond");
3751
3752 x = cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL));
3753 SCHEME_V->code = cons (cadr (SCHEME_V->code), cons (x, NIL));
3754 s_goto (OP_EVAL);
3755 }
3756
3757 s_goto (OP_BEGIN);
3758 }
3759 else
3760 {
3761 if ((SCHEME_V->code = cdr (SCHEME_V->code)) == NIL)
3762 s_return (NIL);
3763 else
3764 {
3765 s_save (SCHEME_A_ OP_COND1, NIL, SCHEME_V->code);
3766 SCHEME_V->code = caar (SCHEME_V->code);
3767 s_goto (OP_EVAL);
3768 }
3769 }
3770
3771 case OP_DELAY: /* delay */
3772 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3773 set_typeflag (x, T_PROMISE);
3774 s_return (x);
3775
3776 case OP_AND0: /* and */
3777 if (SCHEME_V->code == NIL)
3778 s_return (S_T);
3779
3780 s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3781 SCHEME_V->code = car (SCHEME_V->code);
3782 s_goto (OP_EVAL);
3783
3784 case OP_AND1: /* and */
3785 if (is_false (SCHEME_V->value))
3786 s_return (SCHEME_V->value);
3787 else if (SCHEME_V->code == NIL)
3788 s_return (SCHEME_V->value);
3789 else
3790 {
3791 s_save (SCHEME_A_ OP_AND1, NIL, cdr (SCHEME_V->code));
3792 SCHEME_V->code = car (SCHEME_V->code);
3793 s_goto (OP_EVAL);
3794 }
3795
3796 case OP_OR0: /* or */
3797 if (SCHEME_V->code == NIL)
3798 s_return (S_F);
3799
3800 s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3801 SCHEME_V->code = car (SCHEME_V->code);
3802 s_goto (OP_EVAL);
3803
3804 case OP_OR1: /* or */
3805 if (is_true (SCHEME_V->value))
3806 s_return (SCHEME_V->value);
3807 else if (SCHEME_V->code == NIL)
3808 s_return (SCHEME_V->value);
3809 else
3810 {
3811 s_save (SCHEME_A_ OP_OR1, NIL, cdr (SCHEME_V->code));
3812 SCHEME_V->code = car (SCHEME_V->code);
3813 s_goto (OP_EVAL);
3814 }
3815
3816 case OP_C0STREAM: /* cons-stream */
3817 s_save (SCHEME_A_ OP_C1STREAM, NIL, cdr (SCHEME_V->code));
3818 SCHEME_V->code = car (SCHEME_V->code);
3819 s_goto (OP_EVAL);
3820
3821 case OP_C1STREAM: /* cons-stream */
3822 SCHEME_V->args = SCHEME_V->value; /* save SCHEME_V->value to register args for gc */
3823 x = mk_closure (SCHEME_A_ cons (NIL, SCHEME_V->code), SCHEME_V->envir);
3824 set_typeflag (x, T_PROMISE);
3825 s_return (cons (args, x));
3826
3827 case OP_MACRO0: /* macro */
3828 if (is_pair (car (SCHEME_V->code)))
3829 {
3830 x = caar (SCHEME_V->code);
3831 SCHEME_V->code = cons (SCHEME_V->LAMBDA, cons (cdar (SCHEME_V->code), cdr (SCHEME_V->code)));
3832 }
3833 else
3834 {
3835 x = car (SCHEME_V->code);
3836 SCHEME_V->code = cadr (SCHEME_V->code);
3837 }
3838
3839 if (!is_symbol (x))
3840 Error_0 ("variable is not a symbol");
3841
3842 s_save (SCHEME_A_ OP_MACRO1, NIL, x);
3843 s_goto (OP_EVAL);
3844
3845 case OP_MACRO1: /* macro */
3846 set_typeflag (SCHEME_V->value, T_MACRO);
3847 x = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->code, 0);
3848
3849 if (x != NIL)
3850 set_slot_in_env (SCHEME_A_ x, SCHEME_V->value);
3851 else
3852 new_slot_in_env (SCHEME_A_ SCHEME_V->code, SCHEME_V->value);
3853
3854 s_return (SCHEME_V->code);
3855
3856 case OP_CASE0: /* case */
3857 s_save (SCHEME_A_ OP_CASE1, NIL, cdr (SCHEME_V->code));
3858 SCHEME_V->code = car (SCHEME_V->code);
3859 s_goto (OP_EVAL);
3860
3861 case OP_CASE1: /* case */
3862 for (x = SCHEME_V->code; x != NIL; x = cdr (x))
3863 {
3864 if (!is_pair (y = caar (x)))
3865 break;
3866
3867 for (; y != NIL; y = cdr (y))
3868 if (eqv (car (y), SCHEME_V->value))
3869 break;
3870
3871 if (y != NIL)
3872 break;
3873 }
3874
3875 if (x != NIL)
3876 {
3877 if (is_pair (caar (x)))
3878 {
3879 SCHEME_V->code = cdar (x);
3880 s_goto (OP_BEGIN);
3881 }
3882 else /* else */
3883 {
3884 s_save (SCHEME_A_ OP_CASE2, NIL, cdar (x));
3885 SCHEME_V->code = caar (x);
3886 s_goto (OP_EVAL);
3887 }
3888 }
3889 else
3890 s_return (NIL);
3891
3892 case OP_CASE2: /* case */
3893 if (is_true (SCHEME_V->value))
3894 s_goto (OP_BEGIN);
3895 else
3896 s_return (NIL);
3897
3898 case OP_PAPPLY: /* apply */
3899 SCHEME_V->code = car (args);
3900 SCHEME_V->args = list_star (SCHEME_A_ cdr (args));
3901 /*SCHEME_V->args = cadr(args); */
3902 s_goto (OP_APPLY);
3903
3904 case OP_PEVAL: /* eval */
3905 if (cdr (args) != NIL)
3906 SCHEME_V->envir = cadr (args);
3907
3908 SCHEME_V->code = car (args);
3909 s_goto (OP_EVAL);
3910
3911 case OP_CONTINUATION: /* call-with-current-continuation */
3912 SCHEME_V->code = car (args);
3913 SCHEME_V->args = cons (mk_continuation (SCHEME_A_ ss_get_cont (SCHEME_A)), NIL);
3914 s_goto (OP_APPLY);
3915 }
3916
3917 abort ();
3918 }
3919
3920 static int
3921 opexe_1 (SCHEME_P_ enum scheme_opcodes op)
3922 {
3923 pointer args = SCHEME_V->args;
3924 pointer x = car (args);
3925 num v;
3926
3927 #if USE_MATH
3928 RVALUE dd;
3929 #endif
3930
3931 switch (op)
3932 {
3933 #if USE_MATH
3934 case OP_INEX2EX: /* inexact->exact */
3935 if (num_is_integer (x))
3936 s_return (x);
3937 else if (modf (rvalue_unchecked (x), &dd) == 0)
3938 s_return (mk_integer (SCHEME_A_ ivalue (x)));
3939 else
3940 Error_1 ("inexact->exact: not integral:", x);
3941
3942 case OP_EXP: s_return (mk_real (SCHEME_A_ exp (rvalue (x))));
3943 case OP_LOG: s_return (mk_real (SCHEME_A_ log (rvalue (x))));
3944 case OP_SIN: s_return (mk_real (SCHEME_A_ sin (rvalue (x))));
3945 case OP_COS: s_return (mk_real (SCHEME_A_ cos (rvalue (x))));
3946 case OP_TAN: s_return (mk_real (SCHEME_A_ tan (rvalue (x))));
3947 case OP_ASIN: s_return (mk_real (SCHEME_A_ asin (rvalue (x))));
3948 case OP_ACOS: s_return (mk_real (SCHEME_A_ acos (rvalue (x))));
3949
3950 case OP_ATAN:
3951 if (cdr (args) == NIL)
3952 s_return (mk_real (SCHEME_A_ atan (rvalue (x))));
3953 else
3954 {
3955 pointer y = cadr (args);
3956 s_return (mk_real (SCHEME_A_ atan2 (rvalue (x), rvalue (y))));
3957 }
3958
3959 case OP_SQRT:
3960 s_return (mk_real (SCHEME_A_ sqrt (rvalue (x))));
3961
3962 case OP_EXPT:
3963 {
3964 RVALUE result;
3965 int real_result = 1;
3966 pointer y = cadr (args);
3967
3968 if (num_is_integer (x) && num_is_integer (y))
3969 real_result = 0;
3970
3971 /* This 'if' is an R5RS compatibility fix. */
3972 /* NOTE: Remove this 'if' fix for R6RS. */
3973 if (rvalue (x) == 0 && rvalue (y) < 0)
3974 result = 0;
3975 else
3976 result = pow (rvalue (x), rvalue (y));
3977
3978 /* Before returning integer result make sure we can. */
3979 /* If the test fails, result is too big for integer. */
3980 if (!real_result)
3981 {
3982 long result_as_long = result;
3983
3984 if (result != (RVALUE) result_as_long)
3985 real_result = 1;
3986 }
3987
3988 if (real_result)
3989 s_return (mk_real (SCHEME_A_ result));
3990 else
3991 s_return (mk_integer (SCHEME_A_ result));
3992 }
3993
3994 case OP_FLOOR: s_return (mk_real (SCHEME_A_ floor (rvalue (x))));
3995 case OP_CEILING: s_return (mk_real (SCHEME_A_ ceil (rvalue (x))));
3996
3997 case OP_TRUNCATE:
3998 {
3999 RVALUE rvalue_of_x;
4000
4001 rvalue_of_x = rvalue (x);
4002
4003 if (rvalue_of_x > 0)
4004 s_return (mk_real (SCHEME_A_ floor (rvalue_of_x)));
4005 else
4006 s_return (mk_real (SCHEME_A_ ceil (rvalue_of_x)));
4007 }
4008
4009 case OP_ROUND:
4010 if (num_is_integer (x))
4011 s_return (x);
4012
4013 s_return (mk_real (SCHEME_A_ round_per_R5RS (rvalue (x))));
4014 #endif
4015
4016 case OP_ADD: /* + */
4017 v = num_zero;
4018
4019 for (x = args; x != NIL; x = cdr (x))
4020 v = num_op (NUM_ADD, v, nvalue (car (x)));
4021
4022 s_return (mk_number (SCHEME_A_ v));
4023
4024 case OP_MUL: /* * */
4025 v = num_one;
4026
4027 for (x = args; x != NIL; x = cdr (x))
4028 v = num_op (NUM_MUL, v, nvalue (car (x)));
4029
4030 s_return (mk_number (SCHEME_A_ v));
4031
4032 case OP_SUB: /* - */
4033 if (cdr (args) == NIL)
4034 {
4035 x = args;
4036 v = num_zero;
4037 }
4038 else
4039 {
4040 x = cdr (args);
4041 v = nvalue (car (args));
4042 }
4043
4044 for (; x != NIL; x = cdr (x))
4045 v = num_op (NUM_SUB, v, nvalue (car (x)));
4046
4047 s_return (mk_number (SCHEME_A_ v));
4048
4049 case OP_DIV: /* / */
4050 if (cdr (args) == NIL)
4051 {
4052 x = args;
4053 v = num_one;
4054 }
4055 else
4056 {
4057 x = cdr (args);
4058 v = nvalue (car (args));
4059 }
4060
4061 for (; x != NIL; x = cdr (x))
4062 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 s_return (mk_number (SCHEME_A_ v));
4068
4069 case OP_INTDIV: /* quotient */
4070 if (cdr (args) == NIL)
4071 {
4072 x = args;
4073 v = num_one;
4074 }
4075 else
4076 {
4077 x = cdr (args);
4078 v = nvalue (car (args));
4079 }
4080
4081 for (; x != NIL; x = cdr (x))
4082 {
4083 if (ivalue (car (x)) != 0)
4084 v = num_op (NUM_INTDIV, v, nvalue (car (x)));
4085 else
4086 Error_0 ("quotient: division by zero");
4087 }
4088
4089 s_return (mk_number (SCHEME_A_ v));
4090
4091 case OP_REM: /* remainder */
4092 v = nvalue (x);
4093
4094 if (ivalue (cadr (args)) != 0)
4095 v = num_rem (v, nvalue (cadr (args)));
4096 else
4097 Error_0 ("remainder: division by zero");
4098
4099 s_return (mk_number (SCHEME_A_ v));
4100
4101 case OP_MOD: /* modulo */
4102 v = nvalue (x);
4103
4104 if (ivalue (cadr (args)) != 0)
4105 v = num_mod (v, nvalue (cadr (args)));
4106 else
4107 Error_0 ("modulo: division by zero");
4108
4109 s_return (mk_number (SCHEME_A_ v));
4110
4111 case OP_CAR: /* car */
4112 s_return (caar (args));
4113
4114 case OP_CDR: /* cdr */
4115 s_return (cdar (args));
4116
4117 case OP_CONS: /* cons */
4118 set_cdr (args, cadr (args));
4119 s_return (args);
4120
4121 case OP_SETCAR: /* set-car! */
4122 if (!is_immutable (x))
4123 {
4124 set_car (x, cadr (args));
4125 s_return (car (args));
4126 }
4127 else
4128 Error_0 ("set-car!: unable to alter immutable pair");
4129
4130 case OP_SETCDR: /* set-cdr! */
4131 if (!is_immutable (x))
4132 {
4133 set_cdr (x, cadr (args));
4134 s_return (car (args));
4135 }
4136 else
4137 Error_0 ("set-cdr!: unable to alter immutable pair");
4138
4139 case OP_CHAR2INT: /* char->integer */
4140 s_return (mk_integer (SCHEME_A_ ivalue (x)));
4141
4142 case OP_INT2CHAR: /* integer->char */
4143 s_return (mk_character (SCHEME_A_ ivalue (x)));
4144
4145 case OP_CHARUPCASE:
4146 {
4147 unsigned char c = ivalue (x);
4148 c = toupper (c);
4149 s_return (mk_character (SCHEME_A_ c));
4150 }
4151
4152 case OP_CHARDNCASE:
4153 {
4154 unsigned char c = ivalue (x);
4155 c = tolower (c);
4156 s_return (mk_character (SCHEME_A_ c));
4157 }
4158
4159 case OP_STR2SYM: /* string->symbol */
4160 s_return (mk_symbol (SCHEME_A_ strvalue (x)));
4161
4162 case OP_STR2ATOM: /* string->atom */
4163 {
4164 char *s = strvalue (x);
4165 long pf = 0;
4166
4167 if (cdr (args) != NIL)
4168 {
4169 /* we know cadr(args) is a natural number */
4170 /* see if it is 2, 8, 10, or 16, or error */
4171 pf = ivalue_unchecked (cadr (args));
4172
4173 if (pf == 16 || pf == 10 || pf == 8 || pf == 2)
4174 {
4175 /* base is OK */
4176 }
4177 else
4178 pf = -1;
4179 }
4180
4181 if (pf < 0)
4182 Error_1 ("string->atom: bad base:", cadr (args));
4183 else if (*s == '#') /* no use of base! */
4184 s_return (mk_sharp_const (SCHEME_A_ s + 1));
4185 else
4186 {
4187 if (pf == 0 || pf == 10)
4188 s_return (mk_atom (SCHEME_A_ s));
4189 else
4190 {
4191 char *ep;
4192 long iv = strtol (s, &ep, (int) pf);
4193
4194 if (*ep == 0)
4195 s_return (mk_integer (SCHEME_A_ iv));
4196 else
4197 s_return (S_F);
4198 }
4199 }
4200 }
4201
4202 case OP_SYM2STR: /* symbol->string */
4203 x = mk_string (SCHEME_A_ symname (x));
4204 setimmutable (x);
4205 s_return (x);
4206
4207 case OP_ATOM2STR: /* atom->string */
4208 {
4209 long pf = 0;
4210
4211 if (cdr (args) != NIL)
4212 {
4213 /* we know cadr(args) is a natural number */
4214 /* see if it is 2, 8, 10, or 16, or error */
4215 pf = ivalue_unchecked (cadr (args));
4216
4217 if (is_number (x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2))
4218 {
4219 /* base is OK */
4220 }
4221 else
4222 pf = -1;
4223 }
4224
4225 if (pf < 0)
4226 Error_1 ("atom->string: bad base:", cadr (args));
4227 else if (is_number (x) || is_character (x) || is_string (x) || is_symbol (x))
4228 {
4229 char *p;
4230 int len;
4231
4232 atom2str (SCHEME_A_ x, pf, &p, &len);
4233 s_return (mk_counted_string (SCHEME_A_ p, len));
4234 }
4235 else
4236 Error_1 ("atom->string: not an atom:", x);
4237 }
4238
4239 case OP_MKSTRING: /* make-string */
4240 {
4241 int fill = ' ';
4242 int len;
4243
4244 len = ivalue (x);
4245
4246 if (cdr (args) != NIL)
4247 fill = charvalue (cadr (args));
4248
4249 s_return (mk_empty_string (SCHEME_A_ len, fill));
4250 }
4251
4252 case OP_STRLEN: /* string-length */
4253 s_return (mk_integer (SCHEME_A_ strlength (x)));
4254
4255 case OP_STRREF: /* string-ref */
4256 {
4257 char *str;
4258 int index;
4259
4260 str = strvalue (x);
4261
4262 index = ivalue (cadr (args));
4263
4264 if (index >= strlength (x))
4265 Error_1 ("string-ref: out of bounds:", cadr (args));
4266
4267 s_return (mk_character (SCHEME_A_ ((unsigned char *)str)[index]));
4268 }
4269
4270 case OP_STRSET: /* string-set! */
4271 {
4272 char *str;
4273 int index;
4274 int c;
4275
4276 if (is_immutable (x))
4277 Error_1 ("string-set!: unable to alter immutable string:", x);
4278
4279 str = strvalue (x);
4280
4281 index = ivalue (cadr (args));
4282
4283 if (index >= strlength (x))
4284 Error_1 ("string-set!: out of bounds:", cadr (args));
4285
4286 c = charvalue (caddr (args));
4287
4288 str[index] = c;
4289 s_return (car (args));
4290 }
4291
4292 case OP_STRAPPEND: /* string-append */
4293 {
4294 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
4295 int len = 0;
4296 pointer newstr;
4297 char *pos;
4298
4299 /* compute needed length for new string */
4300 for (x = args; x != NIL; x = cdr (x))
4301 len += strlength (car (x));
4302
4303 newstr = mk_empty_string (SCHEME_A_ len, ' ');
4304
4305 /* store the contents of the argument strings into the new string */
4306 for (pos = strvalue (newstr), x = args; x != NIL; pos += strlength (car (x)), x = cdr (x))
4307 memcpy (pos, strvalue (car (x)), strlength (car (x)));
4308
4309 s_return (newstr);
4310 }
4311
4312 case OP_SUBSTR: /* substring */
4313 {
4314 char *str;
4315 int index0;
4316 int index1;
4317 int len;
4318
4319 str = strvalue (x);
4320
4321 index0 = ivalue (cadr (args));
4322
4323 if (index0 > strlength (x))
4324 Error_1 ("substring: start out of bounds:", cadr (args));
4325
4326 if (cddr (args) != NIL)
4327 {
4328 index1 = ivalue (caddr (args));
4329
4330 if (index1 > strlength (x) || index1 < index0)
4331 Error_1 ("substring: end out of bounds:", caddr (args));
4332 }
4333 else
4334 index1 = strlength (x);
4335
4336 len = index1 - index0;
4337 x = mk_empty_string (SCHEME_A_ len, ' ');
4338 memcpy (strvalue (x), str + index0, len);
4339 strvalue (x)[len] = 0;
4340
4341 s_return (x);
4342 }
4343
4344 case OP_VECTOR: /* vector */
4345 {
4346 int i;
4347 pointer vec;
4348 int len = list_length (SCHEME_A_ args);
4349
4350 if (len < 0)
4351 Error_1 ("vector: not a proper list:", args);
4352
4353 vec = mk_vector (SCHEME_A_ len);
4354
4355 #if USE_ERROR_CHECKING
4356 if (SCHEME_V->no_memory)
4357 s_return (S_SINK);
4358 #endif
4359
4360 for (x = args, i = 0; is_pair (x); x = cdr (x), i++)
4361 set_vector_elem (vec, i, car (x));
4362
4363 s_return (vec);
4364 }
4365
4366 case OP_MKVECTOR: /* make-vector */
4367 {
4368 pointer fill = NIL;
4369 int len;
4370 pointer vec;
4371
4372 len = ivalue (x);
4373
4374 if (cdr (args) != NIL)
4375 fill = cadr (args);
4376
4377 vec = mk_vector (SCHEME_A_ len);
4378
4379 #if USE_ERROR_CHECKING
4380 if (SCHEME_V->no_memory)
4381 s_return (S_SINK);
4382 #endif
4383
4384 if (fill != NIL)
4385 fill_vector (vec, fill);
4386
4387 s_return (vec);
4388 }
4389
4390 case OP_VECLEN: /* vector-length */
4391 s_return (mk_integer (SCHEME_A_ veclength (x)));
4392
4393 case OP_VECREF: /* vector-ref */
4394 {
4395 int index;
4396
4397 index = ivalue (cadr (args));
4398
4399 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4400 Error_1 ("vector-ref: out of bounds:", cadr (args));
4401
4402 s_return (vector_elem (x, index));
4403 }
4404
4405 case OP_VECSET: /* vector-set! */
4406 {
4407 int index;
4408
4409 if (is_immutable (x))
4410 Error_1 ("vector-set!: unable to alter immutable vector:", x);
4411
4412 index = ivalue (cadr (args));
4413
4414 if (index >= veclength (car (args)) && USE_ERROR_CHECKING)
4415 Error_1 ("vector-set!: out of bounds:", cadr (args));
4416
4417 set_vector_elem (x, index, caddr (args));
4418 s_return (x);
4419 }
4420 }
4421
4422 abort ();
4423 }
4424
4425 INTERFACE int
4426 is_list (SCHEME_P_ pointer a)
4427 {
4428 return list_length (SCHEME_A_ a) >= 0;
4429 }
4430
4431 /* Result is:
4432 proper list: length
4433 circular list: -1
4434 not even a pair: -2
4435 dotted list: -2 minus length before dot
4436 */
4437 INTERFACE int
4438 list_length (SCHEME_P_ pointer a)
4439 {
4440 int i = 0;
4441 pointer slow, fast;
4442
4443 slow = fast = a;
4444
4445 while (1)
4446 {
4447 if (fast == NIL)
4448 return i;
4449
4450 if (!is_pair (fast))
4451 return -2 - i;
4452
4453 fast = cdr (fast);
4454 ++i;
4455
4456 if (fast == NIL)
4457 return i;
4458
4459 if (!is_pair (fast))
4460 return -2 - i;
4461
4462 ++i;
4463 fast = cdr (fast);
4464
4465 /* Safe because we would have already returned if `fast'
4466 encountered a non-pair. */
4467 slow = cdr (slow);
4468
4469 if (fast == slow)
4470 {
4471 /* the fast pointer has looped back around and caught up
4472 with the slow pointer, hence the structure is circular,
4473 not of finite length, and therefore not a list */
4474 return -1;
4475 }
4476 }
4477 }
4478
4479 static int
4480 opexe_2 (SCHEME_P_ enum scheme_opcodes op)
4481 {
4482 pointer x = SCHEME_V->args;
4483
4484 for (;;)
4485 {
4486 num v = nvalue (car (x));
4487 x = cdr (x);
4488
4489 if (x == NIL)
4490 break;
4491
4492 int r = num_cmp (v, nvalue (car (x)));
4493
4494 switch (op)
4495 {
4496 case OP_NUMEQ: r = r == 0; break;
4497 case OP_LESS: r = r < 0; break;
4498 case OP_GRE: r = r > 0; break;
4499 case OP_LEQ: r = r <= 0; break;
4500 case OP_GEQ: r = r >= 0; break;
4501 }
4502
4503 if (!r)
4504 s_return (S_F);
4505 }
4506
4507 s_return (S_T);
4508 }
4509
4510 static int
4511 opexe_3 (SCHEME_P_ enum scheme_opcodes op)
4512 {
4513 pointer args = SCHEME_V->args;
4514 pointer a = car (args);
4515 pointer d = cdr (args);
4516 int r;
4517
4518 switch (op)
4519 {
4520 case OP_NOT: /* not */ r = is_false (a) ; break;
4521 case OP_BOOLP: /* boolean? */ r = a == S_F || a == S_T; break;
4522 case OP_EOFOBJP: /* eof-object? */ r = a == S_EOF ; break;
4523 case OP_NULLP: /* null? */ r = a == NIL ; break;
4524 case OP_SYMBOLP: /* symbol? */ r = is_symbol (a) ; break;
4525 case OP_NUMBERP: /* number? */ r = is_number (a) ; break;
4526 case OP_STRINGP: /* string? */ r = is_string (a) ; break;
4527 case OP_INTEGERP: /* integer? */ r = is_integer (a) ; break;
4528 case OP_REALP: /* real? */ r = is_number (a) ; break; /* all numbers are real */
4529 case OP_CHARP: /* char? */ r = is_character (a) ; break;
4530
4531 #if USE_CHAR_CLASSIFIERS
4532 case OP_CHARAP: /* char-alphabetic? */ r = Cisalpha (ivalue (a)); break;
4533 case OP_CHARNP: /* char-numeric? */ r = Cisdigit (ivalue (a)); break;
4534 case OP_CHARWP: /* char-whitespace? */ r = Cisspace (ivalue (a)); break;
4535 case OP_CHARUP: /* char-upper-case? */ r = Cisupper (ivalue (a)); break;
4536 case OP_CHARLP: /* char-lower-case? */ r = Cislower (ivalue (a)); break;
4537 #endif
4538
4539 #if USE_PORTS
4540 case OP_PORTP: /* port? */ r = is_port (a) ; break;
4541 case OP_INPORTP: /* input-port? */ r = is_inport (a) ; break;
4542 case OP_OUTPORTP: /* output-port? */ r = is_outport (a); break;
4543 #endif
4544
4545 case OP_PROCP: /* procedure? */
4546
4547 /*--
4548 * continuation should be procedure by the example
4549 * (call-with-current-continuation procedure?) ==> #t
4550 * in R^3 report sec. 6.9
4551 */
4552 r = is_proc (a) || is_closure (a) || is_continuation (a) || is_foreign (a);
4553 break;
4554
4555 case OP_PAIRP: /* pair? */ r = is_pair (a) ; break;
4556 case OP_LISTP: /* list? */ r = list_length (SCHEME_A_ a) >= 0; break;
4557 case OP_ENVP: /* environment? */ r = is_environment (a) ; break;
4558 case OP_VECTORP: /* vector? */ r = is_vector (a) ; break;
4559 case OP_EQ: /* eq? */ r = a == cadr (args) ; break;
4560 case OP_EQV: /* eqv? */ r = eqv (a, cadr (args)) ; break;
4561 }
4562
4563 s_retbool (r);
4564 }
4565
4566 static int
4567 opexe_4 (SCHEME_P_ enum scheme_opcodes op)
4568 {
4569 pointer args = SCHEME_V->args;
4570 pointer a = car (args);
4571 pointer x, y;
4572
4573 switch (op)
4574 {
4575 case OP_FORCE: /* force */
4576 SCHEME_V->code = a;
4577
4578 if (is_promise (SCHEME_V->code))
4579 {
4580 /* Should change type to closure here */
4581 s_save (SCHEME_A_ OP_SAVE_FORCED, NIL, SCHEME_V->code);
4582 SCHEME_V->args = NIL;
4583 s_goto (OP_APPLY);
4584 }
4585 else
4586 s_return (SCHEME_V->code);
4587
4588 case OP_SAVE_FORCED: /* Save forced value replacing promise */
4589 memcpy (SCHEME_V->code, SCHEME_V->value, sizeof (struct cell));
4590 s_return (SCHEME_V->value);
4591
4592 #if USE_PORTS
4593
4594 case OP_WRITE: /* write */
4595 case OP_DISPLAY: /* display */
4596 case OP_WRITE_CHAR: /* write-char */
4597 if (is_pair (cdr (SCHEME_V->args)))
4598 {
4599 if (cadr (SCHEME_V->args) != SCHEME_V->outport)
4600 {
4601 x = cons (SCHEME_V->outport, NIL);
4602 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4603 SCHEME_V->outport = cadr (SCHEME_V->args);
4604 }
4605 }
4606
4607 SCHEME_V->args = a;
4608
4609 if (op == OP_WRITE)
4610 SCHEME_V->print_flag = 1;
4611 else
4612 SCHEME_V->print_flag = 0;
4613
4614 s_goto (OP_P0LIST);
4615
4616 case OP_NEWLINE: /* newline */
4617 if (is_pair (args))
4618 {
4619 if (a != SCHEME_V->outport)
4620 {
4621 x = cons (SCHEME_V->outport, NIL);
4622 s_save (SCHEME_A_ OP_SET_OUTPORT, x, NIL);
4623 SCHEME_V->outport = a;
4624 }
4625 }
4626
4627 putstr (SCHEME_A_ "\n");
4628 s_return (S_T);
4629 #endif
4630
4631 case OP_ERR0: /* error */
4632 SCHEME_V->retcode = -1;
4633
4634 if (!is_string (a))
4635 {
4636 args = cons (mk_string (SCHEME_A_ " -- "), args);
4637 setimmutable (car (args));
4638 }
4639
4640 putstr (SCHEME_A_ "Error: ");
4641 putstr (SCHEME_A_ strvalue (car (args)));
4642 SCHEME_V->args = cdr (args);
4643 s_goto (OP_ERR1);
4644
4645 case OP_ERR1: /* error */
4646 putstr (SCHEME_A_ " ");
4647
4648 if (args != NIL)
4649 {
4650 s_save (SCHEME_A_ OP_ERR1, cdr (args), NIL);
4651 SCHEME_V->args = a;
4652 SCHEME_V->print_flag = 1;
4653 s_goto (OP_P0LIST);
4654 }
4655 else
4656 {
4657 putstr (SCHEME_A_ "\n");
4658
4659 if (SCHEME_V->interactive_repl)
4660 s_goto (OP_T0LVL);
4661 else
4662 return -1;
4663 }
4664
4665 case OP_REVERSE: /* reverse */
4666 s_return (reverse (SCHEME_A_ a));
4667
4668 case OP_LIST_STAR: /* list* */
4669 s_return (list_star (SCHEME_A_ SCHEME_V->args));
4670
4671 case OP_APPEND: /* append */
4672 x = NIL;
4673 y = args;
4674
4675 if (y == x)
4676 s_return (x);
4677
4678 /* cdr() in the while condition is not a typo. If car() */
4679 /* is used (append '() 'a) will return the wrong result. */
4680 while (cdr (y) != NIL)
4681 {
4682 x = revappend (SCHEME_A_ x, car (y));
4683 y = cdr (y);
4684
4685 if (x == S_F)
4686 Error_0 ("non-list argument to append");
4687 }
4688
4689 s_return (reverse_in_place (SCHEME_A_ car (y), x));
4690
4691 #if USE_PLIST
4692
4693 case OP_PUT: /* put */
4694 if (!hasprop (a) || !hasprop (cadr (args)))
4695 Error_0 ("illegal use of put");
4696
4697 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4698 {
4699 if (caar (x) == y)
4700 break;
4701 }
4702
4703 if (x != NIL)
4704 cdar (x) = caddr (args);
4705 else
4706 symprop (a) = cons (cons (y, caddr (args)), symprop (a));
4707
4708 s_return (S_T);
4709
4710 case OP_GET: /* get */
4711 if (!hasprop (a) || !hasprop (cadr (args)))
4712 Error_0 ("illegal use of get");
4713
4714 for (x = symprop (a), y = cadr (args); x != NIL; x = cdr (x))
4715 if (caar (x) == y)
4716 break;
4717
4718 if (x != NIL)
4719 s_return (cdar (x));
4720 else
4721 s_return (NIL);
4722
4723 #endif /* USE_PLIST */
4724
4725 case OP_QUIT: /* quit */
4726 if (is_pair (args))
4727 SCHEME_V->retcode = ivalue (a);
4728
4729 return -1;
4730
4731 case OP_GC: /* gc */
4732 gc (SCHEME_A_ NIL, NIL);
4733 s_return (S_T);
4734
4735 case OP_GCVERB: /* gc-verbose */
4736 {
4737 int was = SCHEME_V->gc_verbose;
4738
4739 SCHEME_V->gc_verbose = (a != S_F);
4740 s_retbool (was);
4741 }
4742
4743 case OP_NEWSEGMENT: /* new-segment */
4744 if (!is_pair (args) || !is_number (a))
4745 Error_0 ("new-segment: argument must be a number");
4746
4747 alloc_cellseg (SCHEME_A_ (int)ivalue (a));
4748
4749 s_return (S_T);
4750
4751 case OP_OBLIST: /* oblist */
4752 s_return (oblist_all_symbols (SCHEME_A));
4753
4754 #if USE_PORTS
4755
4756 case OP_CURR_INPORT: /* current-input-port */
4757 s_return (SCHEME_V->inport);
4758
4759 case OP_CURR_OUTPORT: /* current-output-port */
4760 s_return (SCHEME_V->outport);
4761
4762 case OP_OPEN_INFILE: /* open-input-file */
4763 case OP_OPEN_OUTFILE: /* open-output-file */
4764 case OP_OPEN_INOUTFILE: /* open-input-output-file */
4765 {
4766 int prop = 0;
4767 pointer p;
4768
4769 switch (op)
4770 {
4771 case OP_OPEN_INFILE:
4772 prop = port_input;
4773 break;
4774
4775 case OP_OPEN_OUTFILE:
4776 prop = port_output;
4777 break;
4778
4779 case OP_OPEN_INOUTFILE:
4780 prop = port_input | port_output;
4781 break;
4782 }
4783
4784 p = port_from_filename (SCHEME_A_ strvalue (a), prop);
4785
4786 s_return (p == NIL ? S_F : p);
4787 }
4788
4789 # if USE_STRING_PORTS
4790
4791 case OP_OPEN_INSTRING: /* open-input-string */
4792 case OP_OPEN_INOUTSTRING: /* open-input-output-string */
4793 {
4794 int prop = 0;
4795 pointer p;
4796
4797 switch (op)
4798 {
4799 case OP_OPEN_INSTRING:
4800 prop = port_input;
4801 break;
4802
4803 case OP_OPEN_INOUTSTRING:
4804 prop = port_input | port_output;
4805 break;
4806 }
4807
4808 p = port_from_string (SCHEME_A_ strvalue (a),
4809 strvalue (a) + strlength (a), prop);
4810
4811 s_return (p == NIL ? S_F : p);
4812 }
4813
4814 case OP_OPEN_OUTSTRING: /* open-output-string */
4815 {
4816 pointer p;
4817
4818 if (a == NIL)
4819 p = port_from_scratch (SCHEME_A);
4820 else
4821 p = port_from_string (SCHEME_A_ strvalue (a),
4822 strvalue (a) + strlength (a), port_output);
4823
4824 s_return (p == NIL ? S_F : p);
4825 }
4826
4827 case OP_GET_OUTSTRING: /* get-output-string */
4828 {
4829 port *p;
4830
4831 if ((p = a->object.port)->kind & port_string)
4832 {
4833 off_t size;
4834 char *str;
4835
4836 size = p->rep.string.curr - p->rep.string.start + 1;
4837 str = malloc (size);
4838
4839 if (str != NULL)
4840 {
4841 pointer s;
4842
4843 memcpy (str, p->rep.string.start, size - 1);
4844 str[size - 1] = '\0';
4845 s = mk_string (SCHEME_A_ str);
4846 free (str);
4847 s_return (s);
4848 }
4849 }
4850
4851 s_return (S_F);
4852 }
4853
4854 # endif
4855
4856 case OP_CLOSE_INPORT: /* close-input-port */
4857 port_close (SCHEME_A_ a, port_input);
4858 s_return (S_T);
4859
4860 case OP_CLOSE_OUTPORT: /* close-output-port */
4861 port_close (SCHEME_A_ a, port_output);
4862 s_return (S_T);
4863 #endif
4864
4865 case OP_INT_ENV: /* interaction-environment */
4866 s_return (SCHEME_V->global_env);
4867
4868 case OP_CURR_ENV: /* current-environment */
4869 s_return (SCHEME_V->envir);
4870
4871 }
4872
4873 abort ();
4874 }
4875
4876 static int
4877 opexe_5 (SCHEME_P_ enum scheme_opcodes op)
4878 {
4879 pointer args = SCHEME_V->args;
4880 pointer x;
4881
4882 if (SCHEME_V->nesting != 0)
4883 {
4884 int n = SCHEME_V->nesting;
4885
4886 SCHEME_V->nesting = 0;
4887 SCHEME_V->retcode = -1;
4888 Error_1 ("unmatched parentheses:", mk_integer (SCHEME_A_ n));
4889 }
4890
4891 switch (op)
4892 {
4893 /* ========== reading part ========== */
4894 #if USE_PORTS
4895 case OP_READ:
4896 if (!is_pair (args))
4897 s_goto (OP_READ_INTERNAL);
4898
4899 if (!is_inport (car (args)))
4900 Error_1 ("read: not an input port:", car (args));
4901
4902 if (car (args) == SCHEME_V->inport)
4903 s_goto (OP_READ_INTERNAL);
4904
4905 x = SCHEME_V->inport;
4906 SCHEME_V->inport = car (args);
4907 x = cons (x, NIL);
4908 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4909 s_goto (OP_READ_INTERNAL);
4910
4911 case OP_READ_CHAR: /* read-char */
4912 case OP_PEEK_CHAR: /* peek-char */
4913 {
4914 int c;
4915
4916 if (is_pair (args))
4917 {
4918 if (car (args) != SCHEME_V->inport)
4919 {
4920 x = SCHEME_V->inport;
4921 x = cons (x, NIL);
4922 s_save (SCHEME_A_ OP_SET_INPORT, x, NIL);
4923 SCHEME_V->inport = car (args);
4924 }
4925 }
4926
4927 c = inchar (SCHEME_A);
4928
4929 if (c == EOF)
4930 s_return (S_EOF);
4931
4932 if (SCHEME_V->op == OP_PEEK_CHAR)
4933 backchar (SCHEME_A_ c);
4934
4935 s_return (mk_character (SCHEME_A_ c));
4936 }
4937
4938 case OP_CHAR_READY: /* char-ready? */
4939 {
4940 pointer p = SCHEME_V->inport;
4941 int res;
4942
4943 if (is_pair (args))
4944 p = car (args);
4945
4946 res = p->object.port->kind & port_string;
4947
4948 s_retbool (res);
4949 }
4950
4951 case OP_SET_INPORT: /* set-input-port */
4952 SCHEME_V->inport = car (args);
4953 s_return (SCHEME_V->value);
4954
4955 case OP_SET_OUTPORT: /* set-output-port */
4956 SCHEME_V->outport = car (args);
4957 s_return (SCHEME_V->value);
4958 #endif
4959
4960 case OP_RDSEXPR:
4961 switch (SCHEME_V->tok)
4962 {
4963 case TOK_EOF:
4964 s_return (S_EOF);
4965 /* NOTREACHED */
4966
4967 case TOK_VEC:
4968 s_save (SCHEME_A_ OP_RDVEC, NIL, NIL);
4969 /* fall through */
4970
4971 case TOK_LPAREN:
4972 SCHEME_V->tok = token (SCHEME_A);
4973
4974 if (SCHEME_V->tok == TOK_RPAREN)
4975 s_return (NIL);
4976 else if (SCHEME_V->tok == TOK_DOT)
4977 Error_0 ("syntax error: illegal dot expression");
4978 else
4979 {
4980 SCHEME_V->nesting_stack[SCHEME_V->file_i]++;
4981 s_save (SCHEME_A_ OP_RDLIST, NIL, NIL);
4982 s_goto (OP_RDSEXPR);
4983 }
4984
4985 case TOK_QUOTE:
4986 s_save (SCHEME_A_ OP_RDQUOTE, NIL, NIL);
4987 SCHEME_V->tok = token (SCHEME_A);
4988 s_goto (OP_RDSEXPR);
4989
4990 case TOK_BQUOTE:
4991 SCHEME_V->tok = token (SCHEME_A);
4992
4993 if (SCHEME_V->tok == TOK_VEC)
4994 {
4995 s_save (SCHEME_A_ OP_RDQQUOTEVEC, NIL, NIL);
4996 SCHEME_V->tok = TOK_LPAREN;
4997 s_goto (OP_RDSEXPR);
4998 }
4999 else
5000 s_save (SCHEME_A_ OP_RDQQUOTE, NIL, NIL);
5001
5002 s_goto (OP_RDSEXPR);
5003
5004 case TOK_COMMA:
5005 s_save (SCHEME_A_ OP_RDUNQUOTE, NIL, NIL);
5006 SCHEME_V->tok = token (SCHEME_A);
5007 s_goto (OP_RDSEXPR);
5008
5009 case TOK_ATMARK:
5010 s_save (SCHEME_A_ OP_RDUQTSP, NIL, NIL);
5011 SCHEME_V->tok = token (SCHEME_A);
5012 s_goto (OP_RDSEXPR);
5013
5014 case TOK_ATOM:
5015 s_return (mk_atom (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS)));
5016
5017 case TOK_DQUOTE:
5018 x = readstrexp (SCHEME_A);
5019
5020 if (x == S_F)
5021 Error_0 ("Error reading string");
5022
5023 setimmutable (x);
5024 s_return (x);
5025
5026 case TOK_SHARP:
5027 {
5028 pointer f = find_slot_in_env (SCHEME_A_ SCHEME_V->envir, SCHEME_V->SHARP_HOOK, 1);
5029
5030 if (f == NIL)
5031 Error_0 ("undefined sharp expression");
5032 else
5033 {
5034 SCHEME_V->code = cons (slot_value_in_env (f), NIL);
5035 s_goto (OP_EVAL);
5036 }
5037 }
5038
5039 case TOK_SHARP_CONST:
5040 if ((x = mk_sharp_const (SCHEME_A_ readstr_upto (SCHEME_A_ DELIMITERS))) == NIL)
5041 Error_0 ("undefined sharp expression");
5042 else
5043 s_return (x);
5044
5045 default:
5046 Error_0 ("syntax error: illegal token");
5047 }
5048
5049 break;
5050
5051 case OP_RDLIST:
5052 SCHEME_V->args = cons (SCHEME_V->value, args);
5053 SCHEME_V->tok = token (SCHEME_A);
5054
5055 switch (SCHEME_V->tok)
5056 {
5057 case TOK_EOF:
5058 s_return (S_EOF);
5059
5060 case TOK_RPAREN:
5061 {
5062 int c = inchar (SCHEME_A);
5063
5064 if (c != '\n')
5065 backchar (SCHEME_A_ c);
5066 #if SHOW_ERROR_LINE
5067 else if (SCHEME_V->load_stack[SCHEME_V->file_i].kind & port_file)
5068 SCHEME_V->load_stack[SCHEME_V->file_i].rep.stdio.curr_line++;
5069 #endif
5070
5071 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5072 s_return (reverse_in_place (SCHEME_A_ NIL, SCHEME_V->args));
5073 }
5074
5075 case TOK_DOT:
5076 s_save (SCHEME_A_ OP_RDDOT, SCHEME_V->args, NIL);
5077 SCHEME_V->tok = token (SCHEME_A);
5078 s_goto (OP_RDSEXPR);
5079
5080 default:
5081 s_save (SCHEME_A_ OP_RDLIST, SCHEME_V->args, NIL);
5082 s_goto (OP_RDSEXPR);
5083 }
5084
5085 case OP_RDDOT:
5086 if (token (SCHEME_A) != TOK_RPAREN)
5087 Error_0 ("syntax error: illegal dot expression");
5088
5089 SCHEME_V->nesting_stack[SCHEME_V->file_i]--;
5090 s_return (reverse_in_place (SCHEME_A_ SCHEME_V->value, args));
5091
5092 case OP_RDQUOTE:
5093 s_return (cons (SCHEME_V->QUOTE, cons (SCHEME_V->value, NIL)));
5094
5095 case OP_RDQQUOTE:
5096 s_return (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)));
5097
5098 case OP_RDQQUOTEVEC:
5099 s_return (cons (mk_symbol (SCHEME_A_ "apply"),
5100 cons (mk_symbol (SCHEME_A_ "vector"),
5101 cons (cons (SCHEME_V->QQUOTE, cons (SCHEME_V->value, NIL)), NIL))));
5102
5103 case OP_RDUNQUOTE:
5104 s_return (cons (SCHEME_V->UNQUOTE, cons (SCHEME_V->value, NIL)));
5105
5106 case OP_RDUQTSP:
5107 s_return (cons (SCHEME_V->UNQUOTESP, cons (SCHEME_V->value, NIL)));
5108
5109 case OP_RDVEC:
5110 /*SCHEME_V->code=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5111 s_goto(OP_EVAL); Cannot be quoted */
5112 /*x=cons(mk_proc(SCHEME_A_ OP_VECTOR),SCHEME_V->value);
5113 s_return(x); Cannot be part of pairs */
5114 /*SCHEME_V->code=mk_proc(SCHEME_A_ OP_VECTOR);
5115 SCHEME_V->args=SCHEME_V->value;
5116 s_goto(OP_APPLY); */
5117 SCHEME_V->args = SCHEME_V->value;
5118 s_goto (OP_VECTOR);
5119
5120 /* ========== printing part ========== */
5121 case OP_P0LIST:
5122 if (is_vector (args))
5123 {
5124 putstr (SCHEME_A_ "#(");
5125 SCHEME_V->args = cons (args, mk_integer (SCHEME_A_ 0));
5126 s_goto (OP_PVECFROM);
5127 }
5128 else if (is_environment (args))
5129 {
5130 putstr (SCHEME_A_ "#<ENVIRONMENT>");
5131 s_return (S_T);
5132 }
5133 else if (!is_pair (args))
5134 {
5135 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5136 s_return (S_T);
5137 }
5138 else
5139 {
5140 pointer a = car (args);
5141 pointer b = cdr (args);
5142 int ok_abbr = ok_abbrev (b);
5143 SCHEME_V->args = car (b);
5144
5145 if (a == SCHEME_V->QUOTE && ok_abbr)
5146 putstr (SCHEME_A_ "'");
5147 else if (a == SCHEME_V->QQUOTE && ok_abbr)
5148 putstr (SCHEME_A_ "`");
5149 else if (a == SCHEME_V->UNQUOTE && ok_abbr)
5150 putstr (SCHEME_A_ ",");
5151 else if (a == SCHEME_V->UNQUOTESP && ok_abbr)
5152 putstr (SCHEME_A_ ",@");
5153 else
5154 {
5155 putstr (SCHEME_A_ "(");
5156 s_save (SCHEME_A_ OP_P1LIST, b, NIL);
5157 SCHEME_V->args = a;
5158 }
5159
5160 s_goto (OP_P0LIST);
5161 }
5162
5163 case OP_P1LIST:
5164 if (is_pair (args))
5165 {
5166 s_save (SCHEME_A_ OP_P1LIST, cdr (args), NIL);
5167 putstr (SCHEME_A_ " ");
5168 SCHEME_V->args = car (args);
5169 s_goto (OP_P0LIST);
5170 }
5171 else if (is_vector (args))
5172 {
5173 s_save (SCHEME_A_ OP_P1LIST, NIL, NIL);
5174 putstr (SCHEME_A_ " . ");
5175 s_goto (OP_P0LIST);
5176 }
5177 else
5178 {
5179 if (args != NIL)
5180 {
5181 putstr (SCHEME_A_ " . ");
5182 printatom (SCHEME_A_ args, SCHEME_V->print_flag);
5183 }
5184
5185 putstr (SCHEME_A_ ")");
5186 s_return (S_T);
5187 }
5188
5189 case OP_PVECFROM:
5190 {
5191 int i = ivalue_unchecked (cdr (args));
5192 pointer vec = car (args);
5193 int len = veclength (vec);
5194
5195 if (i == len)
5196 {
5197 putstr (SCHEME_A_ ")");
5198 s_return (S_T);
5199 }
5200 else
5201 {
5202 pointer elem = vector_elem (vec, i);
5203
5204 ivalue_unchecked (cdr (args)) = i + 1;
5205 s_save (SCHEME_A_ OP_PVECFROM, args, NIL);
5206 SCHEME_V->args = elem;
5207
5208 if (i > 0)
5209 putstr (SCHEME_A_ " ");
5210
5211 s_goto (OP_P0LIST);
5212 }
5213 }
5214 }
5215
5216 abort ();
5217 }
5218
5219 static int
5220 opexe_6 (SCHEME_P_ enum scheme_opcodes op)
5221 {
5222 pointer args = SCHEME_V->args;
5223 pointer a = car (args);
5224 pointer x, y;
5225
5226 switch (op)
5227 {
5228 case OP_LIST_LENGTH: /* length *//* a.k */
5229 {
5230 long v = list_length (SCHEME_A_ a);
5231
5232 if (v < 0)
5233 Error_1 ("length: not a list:", a);
5234
5235 s_return (mk_integer (SCHEME_A_ v));
5236 }
5237
5238 case OP_ASSQ: /* assq *//* a.k */
5239 x = a;
5240
5241 for (y = cadr (args); is_pair (y); y = cdr (y))
5242 {
5243 if (!is_pair (car (y)))
5244 Error_0 ("unable to handle non pair element");
5245
5246 if (x == caar (y))
5247 break;
5248 }
5249
5250 if (is_pair (y))
5251 s_return (car (y));
5252 else
5253 s_return (S_F);
5254
5255
5256 case OP_GET_CLOSURE: /* get-closure-code *//* a.k */
5257 SCHEME_V->args = a;
5258
5259 if (SCHEME_V->args == NIL)
5260 s_return (S_F);
5261 else if (is_closure (SCHEME_V->args))
5262 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5263 else if (is_macro (SCHEME_V->args))
5264 s_return (cons (SCHEME_V->LAMBDA, closure_code (SCHEME_V->value)));
5265 else
5266 s_return (S_F);
5267
5268 case OP_CLOSUREP: /* closure? */
5269 /*
5270 * Note, macro object is also a closure.
5271 * Therefore, (closure? <#MACRO>) ==> #t
5272 */
5273 s_retbool (is_closure (a));
5274
5275 case OP_MACROP: /* macro? */
5276 s_retbool (is_macro (a));
5277 }
5278
5279 abort ();
5280 }
5281
5282 /* dispatch functions (opexe_x) return new opcode, or 0 for same opcode, or -1 to stop */
5283 typedef int (*dispatch_func)(SCHEME_P_ enum scheme_opcodes);
5284
5285 typedef int (*test_predicate)(pointer);
5286 static int
5287 is_any (pointer p)
5288 {
5289 return 1;
5290 }
5291
5292 static int
5293 is_nonneg (pointer p)
5294 {
5295 return ivalue (p) >= 0 && is_integer (p);
5296 }
5297
5298 static int
5299 tst_is_list (pointer p)
5300 {
5301 return p == NIL || is_pair (p);
5302 }
5303
5304 /* Correspond carefully with following defines! */
5305 static struct
5306 {
5307 test_predicate fct;
5308 const char *kind;
5309 } tests[] =
5310 {
5311 { is_any, 0 },
5312 { is_string, "string" },
5313 { is_symbol, "symbol" },
5314 { is_port, "port" },
5315 { is_inport, "input port" },
5316 { is_outport, "output port" },
5317 { is_environment, "environment" },
5318 { is_pair, "pair" },
5319 { tst_is_list, "pair or '()" },
5320 { is_character, "character" },
5321 { is_vector, "vector" },
5322 { is_number, "number" },
5323 { is_integer, "integer" },
5324 { is_nonneg, "non-negative integer" }
5325 };
5326
5327 #define TST_NONE 0 /* TST_NONE used for built-ins, 0 for internal ops */
5328 #define TST_ANY "\001"
5329 #define TST_STRING "\002"
5330 #define TST_SYMBOL "\003"
5331 #define TST_PORT "\004"
5332 #define TST_INPORT "\005"
5333 #define TST_OUTPORT "\006"
5334 #define TST_ENVIRONMENT "\007"
5335 #define TST_PAIR "\010"
5336 #define TST_LIST "\011"
5337 #define TST_CHAR "\012"
5338 #define TST_VECTOR "\013"
5339 #define TST_NUMBER "\014"
5340 #define TST_INTEGER "\015"
5341 #define TST_NATURAL "\016"
5342
5343 #define INF_ARG 0xff
5344 #define UNNAMED_OP ""
5345
5346 static const char opnames[] =
5347 #define OP_DEF(func,name,minarity,maxarity,argtest,op) name "\x00"
5348 #include "opdefines.h"
5349 #undef OP_DEF
5350 ;
5351
5352 static const char *
5353 opname (int idx)
5354 {
5355 const char *name = opnames;
5356
5357 /* should do this at compile time, but would require external program, right? */
5358 while (idx--)
5359 name += strlen (name) + 1;
5360
5361 return *name ? name : "ILLEGAL";
5362 }
5363
5364 static const char *
5365 procname (pointer x)
5366 {
5367 return opname (procnum (x));
5368 }
5369
5370 typedef struct
5371 {
5372 uint8_t func;
5373 /*dispatch_func func;*//*TODO: maybe optionally keep the pointer, for speed? */
5374 uint8_t builtin;
5375 uint8_t min_arity;
5376 uint8_t max_arity;
5377 char arg_tests_encoding[3];
5378 } op_code_info;
5379
5380 static const op_code_info dispatch_table[] = {
5381 #define OP_DEF(func,name,minarity,maxarity,argtest,op) { func, sizeof (name) > 1, minarity, maxarity, argtest },
5382 #include "opdefines.h"
5383 #undef OP_DEF
5384 {0}
5385 };
5386
5387 /* kernel of this interpreter */
5388 static void ecb_hot
5389 Eval_Cycle (SCHEME_P_ enum scheme_opcodes op)
5390 {
5391 SCHEME_V->op = op;
5392
5393 for (;;)
5394 {
5395 const op_code_info *pcd = dispatch_table + SCHEME_V->op;
5396
5397 #if USE_ERROR_CHECKING
5398 if (pcd->builtin) /* if built-in function, check arguments */
5399 {
5400 char msg[STRBUFFSIZE];
5401 int n = list_length (SCHEME_A_ SCHEME_V->args);
5402
5403 /* Check number of arguments */
5404 if (ecb_expect_false (n < pcd->min_arity))
5405 {
5406 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5407 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at least", pcd->min_arity);
5408 xError_1 (SCHEME_A_ msg, 0);
5409 continue;
5410 }
5411 else if (ecb_expect_false (n > pcd->max_arity && pcd->max_arity != INF_ARG))
5412 {
5413 snprintf (msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
5414 opname (SCHEME_V->op), pcd->min_arity == pcd->max_arity ? "" : " at most", pcd->max_arity);
5415 xError_1 (SCHEME_A_ msg, 0);
5416 continue;
5417 }
5418 else
5419 {
5420 if (*pcd->arg_tests_encoding) /* literal 0 and TST_NONE treated the same */
5421 {
5422 int i = 0;
5423 int j;
5424 const char *t = pcd->arg_tests_encoding;
5425 pointer arglist = SCHEME_V->args;
5426
5427 do
5428 {
5429 pointer arg = car (arglist);
5430
5431 j = t[0];
5432
5433 if (!tests[j - 1].fct (arg))
5434 break;
5435
5436 if (t[1]) /* last test is replicated as necessary */
5437 t++;
5438
5439 arglist = cdr (arglist);
5440 i++;
5441 }
5442 while (i < n);
5443
5444 if (i < n)
5445 {
5446 snprintf (msg, STRBUFFSIZE, "%s: argument %d must be: %s", opname (SCHEME_V->op), i + 1, tests[j].kind);
5447 xError_1 (SCHEME_A_ msg, 0);
5448 continue;
5449 }
5450 }
5451 }
5452 }
5453 #endif
5454
5455 ok_to_freely_gc (SCHEME_A);
5456
5457 static const dispatch_func dispatch_funcs[] = {
5458 opexe_0,
5459 opexe_1,
5460 opexe_2,
5461 opexe_3,
5462 opexe_4,
5463 opexe_5,
5464 opexe_6,
5465 };
5466
5467 if (ecb_expect_false (dispatch_funcs [pcd->func] (SCHEME_A_ SCHEME_V->op) != 0))
5468 return;
5469
5470 if (SCHEME_V->no_memory && USE_ERROR_CHECKING)
5471 {
5472 xwrstr ("No memory!\n");
5473 return;
5474 }
5475 }
5476 }
5477
5478 /* ========== Initialization of internal keywords ========== */
5479
5480 static void
5481 assign_syntax (SCHEME_P_ const char *name)
5482 {
5483 pointer x = oblist_add_by_name (SCHEME_A_ name);
5484 set_typeflag (x, typeflag (x) | T_SYNTAX);
5485 }
5486
5487 static void
5488 assign_proc (SCHEME_P_ enum scheme_opcodes op, const char *name)
5489 {
5490 pointer x = mk_symbol (SCHEME_A_ name);
5491 pointer y = mk_proc (SCHEME_A_ op);
5492 new_slot_in_env (SCHEME_A_ x, y);
5493 }
5494
5495 static pointer
5496 mk_proc (SCHEME_P_ enum scheme_opcodes op)
5497 {
5498 pointer y = get_cell (SCHEME_A_ NIL, NIL);
5499 set_typeflag (y, (T_PROC | T_ATOM));
5500 ivalue_unchecked (y) = op;
5501 set_num_integer (y);
5502 return y;
5503 }
5504
5505 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
5506 static int
5507 syntaxnum (pointer p)
5508 {
5509 const char *s = strvalue (car (p));
5510
5511 switch (strlength (car (p)))
5512 {
5513 case 2:
5514 if (s[0] == 'i')
5515 return OP_IF0; /* if */
5516 else
5517 return OP_OR0; /* or */
5518
5519 case 3:
5520 if (s[0] == 'a')
5521 return OP_AND0; /* and */
5522 else
5523 return OP_LET0; /* let */
5524
5525 case 4:
5526 switch (s[3])
5527 {
5528 case 'e':
5529 return OP_CASE0; /* case */
5530
5531 case 'd':
5532 return OP_COND0; /* cond */
5533
5534 case '*':
5535 return OP_LET0AST;/* let* */
5536
5537 default:
5538 return OP_SET0; /* set! */
5539 }
5540
5541 case 5:
5542 switch (s[2])
5543 {
5544 case 'g':
5545 return OP_BEGIN; /* begin */
5546
5547 case 'l':
5548 return OP_DELAY; /* delay */
5549
5550 case 'c':
5551 return OP_MACRO0; /* macro */
5552
5553 default:
5554 return OP_QUOTE; /* quote */
5555 }
5556
5557 case 6:
5558 switch (s[2])
5559 {
5560 case 'm':
5561 return OP_LAMBDA; /* lambda */
5562
5563 case 'f':
5564 return OP_DEF0; /* define */
5565
5566 default:
5567 return OP_LET0REC;/* letrec */
5568 }
5569
5570 default:
5571 return OP_C0STREAM; /* cons-stream */
5572 }
5573 }
5574
5575 #if USE_MULTIPLICITY
5576 ecb_cold scheme *
5577 scheme_init_new ()
5578 {
5579 scheme *sc = malloc (sizeof (scheme));
5580
5581 if (!scheme_init (SCHEME_A))
5582 {
5583 free (SCHEME_A);
5584 return 0;
5585 }
5586 else
5587 return sc;
5588 }
5589 #endif
5590
5591 ecb_cold int
5592 scheme_init (SCHEME_P)
5593 {
5594 int i, n = sizeof (dispatch_table) / sizeof (dispatch_table[0]);
5595 pointer x;
5596
5597 num_set_fixnum (num_zero, 1);
5598 num_set_ivalue (num_zero, 0);
5599 num_set_fixnum (num_one, 1);
5600 num_set_ivalue (num_one, 1);
5601
5602 #if USE_INTERFACE
5603 SCHEME_V->vptr = &vtbl;
5604 #endif
5605 SCHEME_V->gensym_cnt = 0;
5606 SCHEME_V->last_cell_seg = -1;
5607 SCHEME_V->free_cell = NIL;
5608 SCHEME_V->fcells = 0;
5609 SCHEME_V->no_memory = 0;
5610 SCHEME_V->inport = NIL;
5611 SCHEME_V->outport = NIL;
5612 SCHEME_V->save_inport = NIL;
5613 SCHEME_V->loadport = NIL;
5614 SCHEME_V->nesting = 0;
5615 SCHEME_V->interactive_repl = 0;
5616
5617 if (alloc_cellseg (SCHEME_A_ FIRST_CELLSEGS) != FIRST_CELLSEGS)
5618 {
5619 #if USE_ERROR_CHECKING
5620 SCHEME_V->no_memory = 1;
5621 return 0;
5622 #endif
5623 }
5624
5625 SCHEME_V->gc_verbose = 0;
5626 dump_stack_initialize (SCHEME_A);
5627 SCHEME_V->code = NIL;
5628 SCHEME_V->args = NIL;
5629 SCHEME_V->envir = NIL;
5630 SCHEME_V->tracing = 0;
5631
5632 /* init NIL */
5633 set_typeflag (NIL, T_ATOM | T_MARK);
5634 set_car (NIL, NIL);
5635 set_cdr (NIL, NIL);
5636 /* init T */
5637 set_typeflag (S_T, T_ATOM | T_MARK);
5638 set_car (S_T, S_T);
5639 set_cdr (S_T, S_T);
5640 /* init F */
5641 set_typeflag (S_F, T_ATOM | T_MARK);
5642 set_car (S_F, S_F);
5643 set_cdr (S_F, S_F);
5644 /* init EOF_OBJ */
5645 set_typeflag (S_EOF, T_ATOM | T_MARK);
5646 set_car (S_EOF, S_EOF);
5647 set_cdr (S_EOF, S_EOF);
5648 /* init sink */
5649 set_typeflag (S_SINK, T_PAIR | T_MARK);
5650 set_car (S_SINK, NIL);
5651
5652 /* init c_nest */
5653 SCHEME_V->c_nest = NIL;
5654
5655 SCHEME_V->oblist = oblist_initial_value (SCHEME_A);
5656 /* init global_env */
5657 new_frame_in_env (SCHEME_A_ NIL);
5658 SCHEME_V->global_env = SCHEME_V->envir;
5659 /* init else */
5660 x = mk_symbol (SCHEME_A_ "else");
5661 new_slot_in_env (SCHEME_A_ x, S_T);
5662
5663 {
5664 static const char *syntax_names[] = {
5665 "lambda", "quote", "define", "if", "begin", "set!",
5666 "let", "let*", "letrec", "cond", "delay", "and",
5667 "or", "cons-stream", "macro", "case"
5668 };
5669
5670 for (i = 0; i < sizeof (syntax_names) / sizeof (*syntax_names); ++i)
5671 assign_syntax (SCHEME_A_ syntax_names[i]);
5672 }
5673
5674 // TODO: should iterate via strlen, to avoid n² complexity
5675 for (i = 0; i < n; i++)
5676 if (dispatch_table[i].builtin)
5677 assign_proc (SCHEME_A_ i, opname (i));
5678
5679 /* initialization of global pointers to special symbols */
5680 SCHEME_V->LAMBDA = mk_symbol (SCHEME_A_ "lambda");
5681 SCHEME_V->QUOTE = mk_symbol (SCHEME_A_ "quote");
5682 SCHEME_V->QQUOTE = mk_symbol (SCHEME_A_ "quasiquote");
5683 SCHEME_V->UNQUOTE = mk_symbol (SCHEME_A_ "unquote");
5684 SCHEME_V->UNQUOTESP = mk_symbol (SCHEME_A_ "unquote-splicing");
5685 SCHEME_V->FEED_TO = mk_symbol (SCHEME_A_ "=>");
5686 SCHEME_V->COLON_HOOK = mk_symbol (SCHEME_A_ "*colon-hook*");
5687 SCHEME_V->ERROR_HOOK = mk_symbol (SCHEME_A_ "*error-hook*");
5688 SCHEME_V->SHARP_HOOK = mk_symbol (SCHEME_A_ "*sharp-hook*");
5689 SCHEME_V->COMPILE_HOOK = mk_symbol (SCHEME_A_ "*compile-hook*");
5690
5691 return !SCHEME_V->no_memory;
5692 }
5693
5694 #if USE_PORTS
5695 void
5696 scheme_set_input_port_file (SCHEME_P_ int fin)
5697 {
5698 SCHEME_V->inport = port_from_file (SCHEME_A_ fin, port_input);
5699 }
5700
5701 void
5702 scheme_set_input_port_string (SCHEME_P_ char *start, char *past_the_end)
5703 {
5704 SCHEME_V->inport = port_from_string (SCHEME_A_ start, past_the_end, port_input);
5705 }
5706
5707 void
5708 scheme_set_output_port_file (SCHEME_P_ int fout)
5709 {
5710 SCHEME_V->outport = port_from_file (SCHEME_A_ fout, port_output);
5711 }
5712
5713 void
5714 scheme_set_output_port_string (SCHEME_P_ char *start, char *past_the_end)
5715 {
5716 SCHEME_V->outport = port_from_string (SCHEME_A_ start, past_the_end, port_output);
5717 }
5718 #endif
5719
5720 void
5721 scheme_set_external_data (SCHEME_P_ void *p)
5722 {
5723 SCHEME_V->ext_data = p;
5724 }
5725
5726 ecb_cold void
5727 scheme_deinit (SCHEME_P)
5728 {
5729 int i;
5730
5731 #if SHOW_ERROR_LINE
5732 char *fname;
5733 #endif
5734
5735 SCHEME_V->oblist = NIL;
5736 SCHEME_V->global_env = NIL;
5737 dump_stack_free (SCHEME_A);
5738 SCHEME_V->envir = NIL;
5739 SCHEME_V->code = NIL;
5740 SCHEME_V->args = NIL;
5741 SCHEME_V->value = NIL;
5742
5743 if (is_port (SCHEME_V->inport))
5744 set_typeflag (SCHEME_V->inport, T_ATOM);
5745
5746 SCHEME_V->inport = NIL;
5747 SCHEME_V->outport = NIL;
5748
5749 if (is_port (SCHEME_V->save_inport))
5750 set_typeflag (SCHEME_V->save_inport, T_ATOM);
5751
5752 SCHEME_V->save_inport = NIL;
5753
5754 if (is_port (SCHEME_V->loadport))
5755 set_typeflag (SCHEME_V->loadport, T_ATOM);
5756
5757 SCHEME_V->loadport = NIL;
5758 SCHEME_V->gc_verbose = 0;
5759 gc (SCHEME_A_ NIL, NIL);
5760
5761 for (i = 0; i <= SCHEME_V->last_cell_seg; i++)
5762 free (SCHEME_V->alloc_seg[i]);
5763
5764 #if SHOW_ERROR_LINE
5765 for (i = 0; i <= SCHEME_V->file_i; i++)
5766 {
5767 if (SCHEME_V->load_stack[i].kind & port_file)
5768 {
5769 fname = SCHEME_V->load_stack[i].rep.stdio.filename;
5770
5771 if (fname)
5772 free (fname);
5773 }
5774 }
5775 #endif
5776 }
5777
5778 void
5779 scheme_load_file (SCHEME_P_ int fin)
5780 {
5781 scheme_load_named_file (SCHEME_A_ fin, 0);
5782 }
5783
5784 void
5785 scheme_load_named_file (SCHEME_P_ int fin, const char *filename)
5786 {
5787 dump_stack_reset (SCHEME_A);
5788 SCHEME_V->envir = SCHEME_V->global_env;
5789 SCHEME_V->file_i = 0;
5790 SCHEME_V->load_stack[0].unget = -1;
5791 SCHEME_V->load_stack[0].kind = port_input | port_file;
5792 SCHEME_V->load_stack[0].rep.stdio.file = fin;
5793 #if USE_PORTS
5794 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5795 #endif
5796 SCHEME_V->retcode = 0;
5797
5798 #if USE_PORTS
5799 if (fin == STDIN_FILENO)
5800 SCHEME_V->interactive_repl = 1;
5801 #endif
5802
5803 #if USE_PORTS
5804 #if SHOW_ERROR_LINE
5805 SCHEME_V->load_stack[0].rep.stdio.curr_line = 0;
5806
5807 if (fin != STDIN_FILENO && filename)
5808 SCHEME_V->load_stack[0].rep.stdio.filename = store_string (SCHEME_A_ strlen (filename), filename, 0);
5809 #endif
5810 #endif
5811
5812 SCHEME_V->inport = SCHEME_V->loadport;
5813 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5814 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5815 set_typeflag (SCHEME_V->loadport, T_ATOM);
5816
5817 if (SCHEME_V->retcode == 0)
5818 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5819 }
5820
5821 void
5822 scheme_load_string (SCHEME_P_ const char *cmd)
5823 {
5824 dump_stack_reset (SCHEME_A);
5825 SCHEME_V->envir = SCHEME_V->global_env;
5826 SCHEME_V->file_i = 0;
5827 SCHEME_V->load_stack[0].kind = port_input | port_string;
5828 SCHEME_V->load_stack[0].rep.string.start = (char *)cmd; /* This func respects const */
5829 SCHEME_V->load_stack[0].rep.string.past_the_end = (char *)cmd + strlen (cmd);
5830 SCHEME_V->load_stack[0].rep.string.curr = (char *)cmd;
5831 #if USE_PORTS
5832 SCHEME_V->loadport = mk_port (SCHEME_A_ SCHEME_V->load_stack);
5833 #endif
5834 SCHEME_V->retcode = 0;
5835 SCHEME_V->interactive_repl = 0;
5836 SCHEME_V->inport = SCHEME_V->loadport;
5837 SCHEME_V->args = mk_integer (SCHEME_A_ SCHEME_V->file_i);
5838 Eval_Cycle (SCHEME_A_ OP_T0LVL);
5839 set_typeflag (SCHEME_V->loadport, T_ATOM);
5840
5841 if (SCHEME_V->retcode == 0)
5842 SCHEME_V->retcode = SCHEME_V->nesting != 0;
5843 }
5844
5845 void
5846 scheme_define (SCHEME_P_ pointer envir, pointer symbol, pointer value)
5847 {
5848 pointer x;
5849
5850 x = find_slot_in_env (SCHEME_A_ envir, symbol, 0);
5851
5852 if (x != NIL)
5853 set_slot_in_env (SCHEME_A_ x, value);
5854 else
5855 new_slot_spec_in_env (SCHEME_A_ envir, symbol, value);
5856 }
5857
5858 #if !STANDALONE
5859
5860 void
5861 scheme_register_foreign_func (scheme * sc, scheme_registerable * sr)
5862 {
5863 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ sr->name), mk_foreign_func (SCHEME_A_ sr->f));
5864 }
5865
5866 void
5867 scheme_register_foreign_func_list (scheme * sc, scheme_registerable * list, int count)
5868 {
5869 int i;
5870
5871 for (i = 0; i < count; i++)
5872 scheme_register_foreign_func (SCHEME_A_ list + i);
5873 }
5874
5875 pointer
5876 scheme_apply0 (SCHEME_P_ const char *procname)
5877 {
5878 return scheme_eval (SCHEME_A_ cons (mk_symbol (SCHEME_A_ procname), NIL));
5879 }
5880
5881 void
5882 save_from_C_call (SCHEME_P)
5883 {
5884 pointer saved_data = cons (car (S_SINK),
5885 cons (SCHEME_V->envir,
5886 SCHEME_V->dump));
5887
5888 /* Push */
5889 SCHEME_V->c_nest = cons (saved_data, SCHEME_V->c_nest);
5890 /* Truncate the dump stack so TS will return here when done, not
5891 directly resume pre-C-call operations. */
5892 dump_stack_reset (SCHEME_A);
5893 }
5894
5895 void
5896 restore_from_C_call (SCHEME_P)
5897 {
5898 set_car (S_SINK, caar (SCHEME_V->c_nest));
5899 SCHEME_V->envir = cadar (SCHEME_V->c_nest);
5900 SCHEME_V->dump = cdr (cdar (SCHEME_V->c_nest));
5901 /* Pop */
5902 SCHEME_V->c_nest = cdr (SCHEME_V->c_nest);
5903 }
5904
5905 /* "func" and "args" are assumed to be already eval'ed. */
5906 pointer
5907 scheme_call (SCHEME_P_ pointer func, pointer args)
5908 {
5909 int old_repl = SCHEME_V->interactive_repl;
5910
5911 SCHEME_V->interactive_repl = 0;
5912 save_from_C_call (SCHEME_A);
5913 SCHEME_V->envir = SCHEME_V->global_env;
5914 SCHEME_V->args = args;
5915 SCHEME_V->code = func;
5916 SCHEME_V->retcode = 0;
5917 Eval_Cycle (SCHEME_A_ OP_APPLY);
5918 SCHEME_V->interactive_repl = old_repl;
5919 restore_from_C_call (SCHEME_A);
5920 return SCHEME_V->value;
5921 }
5922
5923 pointer
5924 scheme_eval (SCHEME_P_ pointer obj)
5925 {
5926 int old_repl = SCHEME_V->interactive_repl;
5927
5928 SCHEME_V->interactive_repl = 0;
5929 save_from_C_call (SCHEME_A);
5930 SCHEME_V->args = NIL;
5931 SCHEME_V->code = obj;
5932 SCHEME_V->retcode = 0;
5933 Eval_Cycle (SCHEME_A_ OP_EVAL);
5934 SCHEME_V->interactive_repl = old_repl;
5935 restore_from_C_call (SCHEME_A);
5936 return SCHEME_V->value;
5937 }
5938
5939 #endif
5940
5941 /* ========== Main ========== */
5942
5943 #if STANDALONE
5944
5945 int
5946 main (int argc, char **argv)
5947 {
5948 # if USE_MULTIPLICITY
5949 scheme ssc;
5950 scheme *const SCHEME_V = &ssc;
5951 # else
5952 # endif
5953 int fin;
5954 char *file_name = InitFile;
5955 int retcode;
5956 int isfile = 1;
5957
5958 if (argc == 2 && strcmp (argv[1], "-?") == 0)
5959 {
5960 xwrstr ("Usage: tinyscheme -?\n");
5961 xwrstr ("or: tinyscheme [<file1> <file2> ...]\n");
5962 xwrstr ("followed by\n");
5963 xwrstr (" -1 <file> [<arg1> <arg2> ...]\n");
5964 xwrstr (" -c <Scheme commands> [<arg1> <arg2> ...]\n");
5965 xwrstr ("assuming that the executable is named tinyscheme.\n");
5966 xwrstr ("Use - as filename for stdin.\n");
5967 return 1;
5968 }
5969
5970 if (!scheme_init (SCHEME_A))
5971 {
5972 xwrstr ("Could not initialize!\n");
5973 return 2;
5974 }
5975
5976 # if USE_PORTS
5977 scheme_set_input_port_file (SCHEME_A_ STDIN_FILENO);
5978 scheme_set_output_port_file (SCHEME_A_ STDOUT_FILENO);
5979 # endif
5980
5981 argv++;
5982
5983 #if 0
5984 if (access (file_name, 0) != 0)
5985 {
5986 char *p = getenv ("TINYSCHEMEINIT");
5987
5988 if (p != 0)
5989 file_name = p;
5990 }
5991 #endif
5992
5993 do
5994 {
5995 #if USE_PORTS
5996 if (strcmp (file_name, "-") == 0)
5997 fin = STDIN_FILENO;
5998 else if (strcmp (file_name, "-1") == 0 || strcmp (file_name, "-c") == 0)
5999 {
6000 pointer args = NIL;
6001
6002 isfile = file_name[1] == '1';
6003 file_name = *argv++;
6004
6005 if (strcmp (file_name, "-") == 0)
6006 fin = STDIN_FILENO;
6007 else if (isfile)
6008 fin = open (file_name, O_RDONLY);
6009
6010 for (; *argv; argv++)
6011 {
6012 pointer value = mk_string (SCHEME_A_ * argv);
6013
6014 args = cons (value, args);
6015 }
6016
6017 args = reverse_in_place (SCHEME_A_ NIL, args);
6018 scheme_define (SCHEME_A_ SCHEME_V->global_env, mk_symbol (SCHEME_A_ "*args*"), args);
6019
6020 }
6021 else
6022 fin = open (file_name, O_RDONLY);
6023 #endif
6024
6025 if (isfile && fin < 0)
6026 {
6027 xwrstr ("Could not open file "); xwrstr (file_name); xwrstr ("\n");
6028 }
6029 else
6030 {
6031 if (isfile)
6032 scheme_load_named_file (SCHEME_A_ fin, file_name);
6033 else
6034 scheme_load_string (SCHEME_A_ file_name);
6035
6036 #if USE_PORTS
6037 if (!isfile || fin != STDIN_FILENO)
6038 {
6039 if (SCHEME_V->retcode != 0)
6040 {
6041 xwrstr ("Errors encountered reading "); xwrstr (file_name); xwrstr ("\n");
6042 }
6043
6044 if (isfile)
6045 close (fin);
6046 }
6047 #endif
6048 }
6049
6050 file_name = *argv++;
6051 }
6052 while (file_name != 0);
6053
6054 if (argc == 1)
6055 scheme_load_named_file (SCHEME_A_ STDIN_FILENO, 0);
6056
6057 retcode = SCHEME_V->retcode;
6058 scheme_deinit (SCHEME_A);
6059
6060 return retcode;
6061 }
6062
6063 #endif
6064
6065 /*
6066 Local variables:
6067 c-file-style: "k&r"
6068 End:
6069 */