tree checksum vpatch file split hunks
all signers:
antecedents:
press order:
tinyscheme_genesis_fixed |
patch:
(0 . 0)(1 . 139)
5 Building TinyScheme
6 -------------------
7
8 The included makefile includes logic for Linux, Solaris and Win32, and can
9 readily serve as an example for other OSes, especially Unixes. There are
10 a lot of compile-time flags in TinyScheme (preprocessor defines) that can trim
11 unwanted features. See next section. 'make all' and 'make clean' function as
12 expected.
13
14 Autoconfing TinyScheme was once proposed, but the distribution would not be
15 so small anymore. There are few platform dependencies in TinyScheme, and in
16 general compiles out of the box.
17
18 Customizing
19 -----------
20
21 The following symbols are defined to default values in scheme.h.
22 Use the -D flag of cc to set to either 1 or 0.
23
24 STANDALONE
25 Define this to produce a standalone interpreter.
26
27 USE_MATH
28 Includes math routines.
29
30 USE_CHAR_CLASSIFIERS
31 Includes character classifier procedures.
32
33 USE_ASCII_NAMES
34 Enable extended character notation based on ASCII names.
35
36 USE_STRING_PORTS
37 Enables string ports.
38
39 USE_ERROR_HOOK
40 To force system errors through user-defined error handling.
41 (see "Error handling")
42
43 USE_TRACING
44 To enable use of TRACING.
45
46 USE_COLON_HOOK
47 Enable use of qualified identifiers. (see "Colon Qualifiers - Packages")
48 Defining this as 0 has the rather drastic consequence that any code using
49 packages will stop working, and will have to be modified. It should only
50 be used if you *absolutely* need to use '::' in identifiers.
51
52 USE_STRCASECMP
53 Defines stricmp as strcasecmp, for Unix.
54
55 STDIO_ADDS_CR
56 Informs TinyScheme that stdio translates "\n" to "\r\n". For DOS/Windows.
57
58 USE_DL
59 Enables dynamically loaded routines. If you define this symbol, you
60 should also include dynload.c in your compile.
61
62 USE_PLIST
63 Enables property lists (not Standard Scheme stuff). Off by default.
64
65 USE_NO_FEATURES
66 Shortcut to disable USE_MATH, USE_CHAR_CLASSIFIERS, USE_ASCII_NAMES,
67 USE_STRING_PORTS, USE_ERROR_HOOK, USE_TRACING, USE_COLON_HOOK,
68 USE_DL.
69
70 USE_SCHEME_STACK
71 Enables 'cons' stack (the alternative is a faster calling scheme, which
72 breaks continuations). Undefine it if you don't care about strict compatibility
73 but you do care about faster execution.
74
75
76 OS-X tip
77 --------
78 I don't have access to OS-X, but Brian Maher submitted the following tip:
79
80 [1] Download and install fink (I installed fink in
81 /usr/local/fink)
82 [2] Install the 'dlcompat' package using fink as such:
83 > fink install dlcompat
84 [3] Make the following changes to the
85 tinyscheme-1.32.tar.gz
86
87 diff -r tinyscheme-1.32/dynload.c
88 tinyscheme-1.32-new/dynload.c
89 24c24
90 < #define SUN_DL
91 ---
92 >
93 Only in tinyscheme-1.32-new/: dynload.o
94 Only in tinyscheme-1.32-new/: libtinyscheme.a Only in tinyscheme-1.32-new/: libtinyscheme.so diff -r tinyscheme-1.32/makefile tinyscheme-1.32-new/makefile
95 33,34c33,43
96 < LD = gcc
97 < LDFLAGS = -shared
98 ---
99 > #LD = gcc
100 > #LDFLAGS = -shared
101 > #DEBUG=-g -Wno-char-subscripts -O
102 > #SYS_LIBS= -ldl
103 > #PLATFORM_FEATURES= -DSUN_DL=1
104 >
105 > # Mac OS X
106 > CC = gcc
107 > CFLAGS = -I/usr/local/fink/include
108 > LD = gcc
109 > LDFLAGS = -L/usr/local/fink/lib
110 37c46
111 < PLATFORM_FEATURES= -DSUN_DL=1
112 ---
113 > PLATFORM_FEATURES= -DSUN_DL=1 -DOSX
114 60c69
115 < $(CC) -I. -c $(DEBUG) $(FEATURES)
116 $(DL_FLAGS) $<
117 ---
118 > $(CC) $(CFLAGS) -I. -c $(DEBUG)
119 $(FEATURES) $(DL_FLAGS) $<
120 66c75
121 < $(CC) -o $@ $(DEBUG) $(OBJS) $(SYS_LIBS)
122 ---
123 > $(CC) $(LDFLAGS) -o $@ $(DEBUG) $(OBJS)
124 $(SYS_LIBS)
125 Only in tinyscheme-1.32-new/: scheme
126 diff -r tinyscheme-1.32/scheme.c
127 tinyscheme-1.32-new/scheme.c
128 60,61c60,61
129 < #ifndef macintosh
130 < # include <malloc.h>
131 ---
132 > #ifdef OSX
133 > /* Do nothing */
134 62a63,65
135 > # ifndef macintosh
136 > # include <malloc.h>
137 > # else
138 77c80,81
139 < #endif /* macintosh */
140 ---
141 > # endif /* macintosh */
142 > #endif /* !OSX */
143 Only in tinyscheme-1.32-new/: scheme.o
-(0 . 0)(1 . 326)
148 Change Log
149 ----------
150
151 Version 1.41
152 Bugs fixed:
153 #3020389 - Added makefile section for Mac OS X (SL)
154 #3286135 - Fixed num_mod routine which caused errors in use of modulo
155 #3290232 - Corrected version number shown on startup (GM)
156 #3394882 - Added missing #if in opdefines.h around get and put (DC)
157 #3395547 - Fix for the modulo procedure (DC)
158 #3400290 - Optimized append to make it an O(n) operation (DC)
159 #3493926 - Corrected flag used when building shared files on OSX (J)
160
161 R5RS related changes:
162 #2866196 - Parser does not handle delimiters correctly
163 #3395548 - Add a decimal point to inexact numbers in atom2str (DC)
164 #3399331 - Make min/max return inexact when any argument is inexact
165 #3399332 - Compatability fix for expt.
166 #3399335 - Optional radix for string->number and number->string (DC)
167 #3400202 - Append with one argument should not return a list (DC)
168 #3400284 - Compatability fix for integer?
169
170 Other changes:
171 - Added flags to makefile for MinGW/MSYS (TC)
172 - Moved variable declarations to avoid warnings with some compilers
173 - Don't print space after initial #( when printing vectors.
174 - Minor optimization for is_nonneg().
175 - No need to round integers in OP_ROUND (#3400284)
176 - Fixes to code that reports line number with error (RC)
177
178 Contributors:
179 Kevin Cozens, Gordon McNutt, Doug Currie, Sean Long, Tim Cas, Joey,
180 Richard Copley, and CMarinier.
181
182 Version 1.40
183 Bugs fixed:
184 #1964950 - Stop core dumps due to bad syntax in LET (and variants)
185 #2826594 - allow reverse to work on empty list (Tony Garnock-Jones)
186 Potential problem of arglist to foreign calls being wrongly GC'ed.
187 Fixed bug that read could loop forever (tehom).
188
189 API changes:
190 Exposed is_list and list_length.
191 Added scheme_register_foreign_func_list and declarations for it (tehom)
192 Defined *compile-hook* (tehom)
193
194 Other changes:
195 Updated is_list and list_length to handle circular lists.
196 Nested calling thru C has been made now safer (tehom)
197 Peter Michaux cleaned up port_rep_from_file
198 Added unwind-protect (tehom)
199 Some cleanups to in/outport and Eval_Cycle by Peter Michaux
200 Report error line number (Mostly by Sanel Zukan, back-compatibility by Tehom)
201
202 Contributors:
203 Kevin Cozens, Dimitrios Souflis, Tom Breton, Peter Michaux, Sanel Zukan,
204 and Tony Garnock-Jones.
205
206 Version 1.39
207 Bugs fixed:
208 Fix for the load bug
209 Fixed parsing of octal coded characters. Fixes bug #1818018.
210 Added tests for when mk_vector is out of memory. Can't rely on sc->sink.
211 Fix for bug #1794369
212 Finished feature-request 1599947: scheme_apply0 etc return values.
213 Partly provided feature-request 1599947: Expose list_length, eqv, etc
214 Provided feature-request 1599945, Scheme->C->Scheme calling.
215 Fix for bug 1593861 (behavior of is_integer)
216 Fix for bug 1589711
217 Error checking of binding spec syntax in LET and LETREC. The bad syntax
218 was causing a segmentation fault in Linux. Complete fixes for bug #1817986.
219 Error checking of binding spec syntax in LET*
220 Bad syntax was causing core dump in Linux.
221 Fix for nasty gc bug
222
223 R5RS changes:
224 R5RS requires numbers to be of equal value AND of the same type (ie. both
225 exact or inexact) in order to return #t from eqv?. R5RS compliance fix.
226 String output ports now conform to SRFI-6
227
228 Other changes:
229 Drew Yao fixed buffer overflow problems in mk_sharp_const.
230 put OP_T0LVL in charge of reacting to EOF
231 file_push checks array bounds (patch from Ray Lehtiniemi)
232 Changed to always use snprintf (Patch due to Ramiro bsd1628)
233 Updated usage information using text from the Manual.txt file.
234
235 Version 1.38
236 Interim release until the rewrite, mostly incorporating modifications
237 from Kevin Cozens. Small addition for Cygwin in the makefile, and
238 modifications by Andrew Guenther for Apple platforms.
239
240 Version 1.37
241 Joe Buehler submitted reserve_cells.
242
243 Version 1.36
244 Joe Buehler fixed a patch in the allocator.
245 Alexander Shendi moved the comment handling in the scanner, which
246 fixed an obscure bug for which Mike E had provided a patch as well.
247 Kevin Cozens has submitted some fixes and modifications which have
248 not been incorporated yet in their entirety.
249
250 Version 1.35
251 Todd Showalter discovered that the number of free cells reported
252 after GC was incorrect, which could also cause unnecessary allocations.
253
254 Version 1.34
255 Long missing version. Lots of bugfixes have accumulated in my email, so
256 I had to start using them. In this version, Keenan Pepper has submitted
257 a bugfix for the string comparison library procedure, Wouter Boeke
258 modified some code that was casting to the wrong type and crashed on
259 some machines, "SheppardCo" submitted a replacement "modulo" code and
260 Scott Fenton submitted lots of corrections that shut up some compiler
261 warnings. Brian Maher submitted instructions on how to build on OS-X.
262 I have to dig deeper into my mailbox and find earlier emails, too.
263
264 Version 1.33
265 Charles Hayden fixed a nasty GC bug of the new stack frame, while in
266 the process of porting TinyScheme to C++. He also submitted other
267 changes, and other people also had comments or requests, but the GC
268 bug was so important that this version is put through the door to
269 correct it.
270
271 Version 1.32
272 Stephen Gildea put some quality time on TinyScheme again, and made
273 a whole lot of changes to the interpreter that made it noticeably
274 faster.
275
276 Version 1.31
277 Patches to the hastily-done version 1.30. Stephen Gildea fixed
278 some things done wrongly, and Richard Russo fixed the makefile
279 for building on Windows. Property lists (heritage from MiniScheme)
280 are now optional and have dissappeared from the interface. They
281 should be considered as deprecated.
282
283 Version 1.30
284 After many months, I followed Preston Bannister's advice of
285 using macros and a single source text to keep the enums and the
286 dispatch table in sync, and I used his contributed "opdefines.h".
287 Timothy Downs contributed a helpful function, "scheme_call".
288 Stephen Gildea contributed new versions of the makefile and
289 practically all other sources. He created a built-in STRING-APPEND,
290 and fixed a lot of other bugs.
291 Ruhi Bloodworth reported fixes necessary for OS X and a small
292 bug in dynload.c.
293
294 Version 1.29
295 The previous version contained a lot of corrections, but there
296 were a lot more that still wait on a sheet of paper lost in a
297 carton someplace after my house move... Manuel Heras-Gilsanz
298 noticed this and resent his own contribution, which relies on
299 another bugfix that v.1.28 was missing: a problem with string
300 output, that this version fixes. I hope other people will take
301 the time to resend their contributions, if they didn't make it
302 to v.1.28.
303
304 Version 1.28
305 Many people have contacted me with bugfixes or remarks in
306 the three months I was inactive. A lot of them spotted that
307 scheme_deinit crashed while reporting gc results. They suggested
308 that sc->outport be set to NIL in scheme_deinit, which I did.
309 Dennis Taylor remarked that OP_VALUEPRINT reset sc->value instead
310 of preserving it. He submitted a modification which I adopted
311 partially. David Hovemeyer sent me many little changes, that you
312 will find in version 1.28, and Partice Stoessel modified the
313 float reader to conform to R5RS.
314
315 Version 1.27
316 Version 1.27 is the successor of 1.25. Bug fixes only, but I had to
317 release them so that everybody can profit. 'Backchar' tried to write
318 back to the string, which obviously didn't work for const strings.
319 'Substring' didn't check for crossed start and end indices. Defines
320 changed to restore the ability to compile under MSVC.
321
322 Version 1.26
323 Version 1.26 was never released. I changed a lot of things, in fact
324 too much, even the garbage collector, and hell broke loose. I'll
325 try a more gradual approach next time.
326
327 Version 1.25
328 Types have been homogenized to be able to accommodate a different
329 representation. Plus, promises are no longer closures. Unfortunately,
330 I discovered that continuations and force/delay do not pass the SCM
331 test (and never did)... However, on the bright side, what little
332 modifications I did had a large impact on the footprint:
333 USE_NO_FEATURES now produces an object file of 63960 bytes on Linux!
334
335 Version 1.24
336 SCM tests now pass again after change in atom2str.
337
338 Version 1.23
339 Finally I managed to mess it up with my version control. Version
340 1.22 actually lacked some of the things I have been fixing in the
341 meantime. This should be considered as a complete replacement for
342 1.22.
343
344 Version 1.22
345 The new ports had a bug in LOAD. MK_CLOSURE is introduced.
346 Shawn Wagner inquired about string->number and number->string.
347 I added string->atom and atom->string and defined the number
348 functions from them. Doing that, I fixed WRITE applied to symbols
349 (it didn't quote them). Unfortunately, minimum build is now
350 slightly larger than 64k... I postpone action because Jason's idea
351 might solve it elegantly.
352
353 Version 1.21
354 Jason Felice submitted a radically different datatype representation
355 which he had implemented. While discussing its pros and cons, it
356 became apparent that the current implementation of ports suffered
357 from a grave fault: ports were not garbage-collected. I changed the
358 ports to be heap-allocated, which enabled the use of string ports
359 for loading. Jason also fixed errors in the garbage collection of
360 vectors. USE_VERBATIM is gone. "ssp_compiler.c" has a better solution
361 on HTML generation. A bug involving backslash notation in strings
362 has been fixed. '-c' flag now executes next argument as a stream of
363 Scheme commands. Foreign functions are now also heap allocated,
364 and scheme_define is used to define everything.
365
366 Version 1.20
367 Tracing has been added. The toplevel loop has been slightly
368 rearranged. Backquote reading for vector templates has been
369 sanitized. Symbol interning is now correct. Arithmetic functions
370 have been corrected. APPLY, MAP, FOR-EACH, numeric comparison
371 functions fixed. String reader/writer understands \xAA notation.
372
373 Version 1.19
374 Carriage Return now delimits identifiers. DOS-formatted Scheme files
375 can be used by Unix. Random number generator added to library.
376 Fixed some glitches of the new type-checking scheme. Fixed erroneous
377 (append '() 'a) behavior. Will continue with r4rstest.scm to
378 fix errors.
379
380 Version 1.18
381 The FFI has been extended. USE_VERBOSE_GC has gone. Anyone wanting
382 the same functionality can put (gcverbose #t) in init.scm.
383 print-width was removed, along with three corresponding op-codes.
384 Extended character constants with ASCII names were added.
385 mk_counted_string paves the way for full support of binary strings.
386 As much as possible of the type-checking chores were delegated
387 to the inner loop, thus reducing the code size to less than 4200 loc!
388
389 Version 1.17
390 Dynamically-loaded extensions are more fully integrated.
391 TinyScheme is now distributed under the BSD open-source license.
392
393 Version 1.16
394 Dynamically-loaded extensions introduced (USE_DL).
395 Santeri Paavolainen found a race condition: When a cons is executed,
396 and each of the two arguments is a constructing function, GC could
397 happen before all arguments are evaluated and cons() is called, and
398 the evaluated arguments would all be reclaimed!
399 Fortunately, such a case was rare in the code, although it is
400 a pitfall in new code and code in foreign functions. Currently, only
401 one such case remains, when COLON_HOOK is defined.
402
403 Version 1.15
404 David Gould also contributed some changes that speed up operation.
405 Kirk Zurell fixed HASPROP.
406 The Garbage Collection didn't collect all the garbage...fixed.
407
408 Version 1.14
409 Unfortunately, after Andre fixed the GC it became obvious that the
410 algorithm was too slow... Fortunately, David Gould found a way to
411 speed it up.
412
413 Version 1.13
414 Silly bug involving division by zero resolved by Roland Kaufman.
415 Macintoch support from Shmulik Regev.
416 Float parser bug fixed by Alexander Shendi.
417 GC bug from Andru Luvisi.
418
419 Version 1.12
420 Cis* incorrectly called isalpha() instead of isascii()
421 Added USE_CHAR_CLASSIFIERS, USE_STRING_PORTS.
422
423 Version 1.11
424 BSDI defines isnumber... changed all similar functions to is_*
425 EXPT now has correct definition. Added FLOOR,CEILING,TRUNCATE
426 and ROUND, courtesy of Bengt Kleberg. Preprocessor symbols now
427 have values 1 or 0, and can be set as compiler defines (proposed
428 by Andy Ganor *months* ago). 'prompt' and 'InitFile' can now be
429 defined during compilation, too.
430
431 Version 1.10
432 Another bug when file ends with comment!
433 Added DEFINE-MACRO in init.scm, courtesy of Andy Gaynor.
434
435 Version 1.09
436 Removed bug when READ met EOF. lcm.
437
438 Version 1.08
439 quotient,remainder and modulo. gcd.
440
441 Version 1.07
442 '=>' in cond now exists
443 list? now checks for circularity
444 some reader bugs removed
445 Reader is more consistent wrt vectors
446 Quote and Quasiquote work with vectors
447
448 Version 1.06
449 #! is now skipped
450 generic-assoc bug removed
451 strings are now managed differently, hack.txt is removed
452 various delicate points fixed
453
454 Version 1.05
455 Support for scripts, *args*, "-1" option.
456 Various R5RS procedures.
457 *sharp-hook*
458 Handles unmatched parentheses.
459 New architecture for procedures.
460
461 Version 1.04
462 Added missing T_ATOM bits...
463 Added vectors
464 Free-list is sorted by address, since vectors need consecutive cells.
465 (quit <exitcode>) for use with scripts
466
467 Version 1.03 (26 Aug 1998):
468 Extended .h with useful functions for FFI
469 Library: with-input-* etc.
470 Finished R5RS I/O, added string ports.
471
472 Version 1.02 (25 Aug 1998):
473 First part of R5RS I/O.
-(0 . 0)(1 . 31)
478 LICENSE TERMS
479
480 Copyright (c) 2000, Dimitrios Souflis
481 All rights reserved.
482
483 Redistribution and use in source and binary forms, with or without
484 modification, are permitted provided that the following conditions are
485 met:
486
487 Redistributions of source code must retain the above copyright notice,
488 this list of conditions and the following disclaimer.
489
490 Redistributions in binary form must reproduce the above copyright
491 notice, this list of conditions and the following disclaimer in the
492 documentation and/or other materials provided with the distribution.
493
494 Neither the name of Dimitrios Souflis nor the names of the
495 contributors may be used to endorse or promote products derived from
496 this software without specific prior written permission.
497
498 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
499 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
500 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
501 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
502 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
503 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
504 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
505 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
506 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
507 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
508 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-(0 . 0)(1 . 452)
513
514
515 TinySCHEME Version 1.41
516
517 "Safe if used as prescribed"
518 -- Philip K. Dick, "Ubik"
519
520 This software is open source, covered by a BSD-style license.
521 Please read accompanying file COPYING.
522 -------------------------------------------------------------------------------
523
524 This Scheme interpreter is based on MiniSCHEME version 0.85k4
525 (see miniscm.tar.gz in the Scheme Repository)
526 Original credits in file MiniSCHEMETribute.txt.
527
528 D. Souflis (dsouflis@acm.org)
529
530 -------------------------------------------------------------------------------
531 What is TinyScheme?
532 -------------------
533
534 TinyScheme is a lightweight Scheme interpreter that implements as large
535 a subset of R5RS as was possible without getting very large and
536 complicated. It is meant to be used as an embedded scripting interpreter
537 for other programs. As such, it does not offer IDEs or extensive toolkits
538 although it does sport a small top-level loop, included conditionally.
539 A lot of functionality in TinyScheme is included conditionally, to allow
540 developers freedom in balancing features and footprint.
541
542 As an embedded interpreter, it allows multiple interpreter states to
543 coexist in the same program, without any interference between them.
544 Programmatically, foreign functions in C can be added and values
545 can be defined in the Scheme environment. Being a quite small program,
546 it is easy to comprehend, get to grips with, and use.
547
548 Known bugs
549 ----------
550
551 TinyScheme is known to misbehave when memory is exhausted.
552
553
554 Things that keep missing, or that need fixing
555 ---------------------------------------------
556
557 There are no hygienic macros. No rational or
558 complex numbers. No unwind-protect and call-with-values.
559
560 Maybe (a subset of) SLIB will work with TinySCHEME...
561
562 Decent debugging facilities are missing. Only tracing is supported
563 natively.
564
565
566 Scheme Reference
567 ----------------
568
569 If something seems to be missing, please refer to the code and
570 "init.scm", since some are library functions. Refer to the MiniSCHEME
571 readme as a last resort.
572
573 Environments
574 (interaction-environment)
575 See R5RS. In TinySCHEME, immutable list of association lists.
576
577 (current-environment)
578 The environment in effect at the time of the call. An example of its
579 use and its utility can be found in the sample code that implements
580 packages in "init.scm":
581
582 (macro (package form)
583 `(apply (lambda ()
584 ,@(cdr form)
585 (current-environment))))
586
587 The environment containing the (local) definitions inside the closure
588 is returned as an immutable value.
589
590 (defined? <symbol>) (defined? <symbol> <environment>)
591 Checks whether the given symbol is defined in the current (or given)
592 environment.
593
594 Symbols
595 (gensym)
596 Returns a new interned symbol each time. Will probably move to the
597 library when string->symbol is implemented.
598
599 Directives
600 (gc)
601 Performs garbage collection immediatelly.
602
603 (gcverbose) (gcverbose <bool>)
604 The argument (defaulting to #t) controls whether GC produces
605 visible outcome.
606
607 (quit) (quit <num>)
608 Stops the interpreter and sets the 'retcode' internal field (defaults
609 to 0). When standalone, 'retcode' is returned as exit code to the OS.
610
611 (tracing <num>)
612 1, turns on tracing. 0 turns it off. (Only when USE_TRACING is 1).
613
614 Mathematical functions
615 Since rationals and complexes are absent, the respective functions
616 are also missing.
617 Supported: exp, log, sin, cos, tan, asin, acos, atan, floor, ceiling,
618 trunc, round and also sqrt and expt when USE_MATH=1.
619 Number-theoretical quotient, remainder and modulo, gcd, lcm.
620 Library: exact?, inexact?, odd?, even?, zero?, positive?, negative?,
621 exact->inexact. inexact->exact is a core function.
622
623 Type predicates
624 boolean?,eof-object?,symbol?,number?,string?,integer?,real?,list?,null?,
625 char?,port?,input-port?,output-port?,procedure?,pair?,environment?',
626 vector?. Also closure?, macro?.
627
628 Types
629 Types supported:
630
631 Numbers (integers and reals)
632 Symbols
633 Pairs
634 Strings
635 Characters
636 Ports
637 Eof object
638 Environments
639 Vectors
640
641 Literals
642 String literals can contain escaped quotes \" as usual, but also
643 \n, \r, \t, \xDD (hex representations) and \DDD (octal representations).
644 Note also that it is possible to include literal newlines in string
645 literals, e.g.
646
647 (define s "String with newline here
648 and here
649 that can function like a HERE-string")
650
651 Character literals contain #\space and #\newline and are supplemented
652 with #\return and #\tab, with obvious meanings. Hex character
653 representations are allowed (e.g. #\x20 is #\space).
654 When USE_ASCII_NAMES is defined, various control characters can be
655 referred to by their ASCII name.
656 0 #\nul 17 #\dc1
657 1 #\soh 18 #\dc2
658 2 #\stx 19 #\dc3
659 3 #\etx 20 #\dc4
660 4 #\eot 21 #\nak
661 5 #\enq 22 #\syn
662 6 #\ack 23 #\etv
663 7 #\bel 24 #\can
664 8 #\bs 25 #\em
665 9 #\ht 26 #\sub
666 10 #\lf 27 #\esc
667 11 #\vt 28 #\fs
668 12 #\ff 29 #\gs
669 13 #\cr 30 #\rs
670 14 #\so 31 #\us
671 15 #\si
672 16 #\dle 127 #\del
673
674 Numeric literals support #x #o #b and #d. Flonums are currently read only
675 in decimal notation. Full grammar will be supported soon.
676
677 Quote, quasiquote etc.
678 As usual.
679
680 Immutable values
681 Immutable pairs cannot be modified by set-car! and set-cdr!.
682 Immutable strings cannot be modified via string-set!
683
684 I/O
685 As per R5RS, plus String Ports (see below).
686 current-input-port, current-output-port,
687 close-input-port, close-output-port, input-port?, output-port?,
688 open-input-file, open-output-file.
689 read, write, display, newline, write-char, read-char, peek-char.
690 char-ready? returns #t only for string ports, because there is no
691 portable way in stdio to determine if a character is available.
692 Also open-input-output-file, set-input-port, set-output-port (not R5RS)
693 Library: call-with-input-file, call-with-output-file,
694 with-input-from-file, with-output-from-file and
695 with-input-output-from-to-files, close-port and input-output-port?
696 (not R5RS).
697 String Ports: open-input-string, open-output-string, get-output-string,
698 open-input-output-string. Strings can be used with I/O routines.
699
700 Vectors
701 make-vector, vector, vector-length, vector-ref, vector-set!, list->vector,
702 vector-fill!, vector->list, vector-equal? (auxiliary function, not R5RS)
703
704 Strings
705 string, make-string, list->string, string-length, string-ref, string-set!,
706 substring, string->list, string-fill!, string-append, string-copy.
707 string=?, string<?, string>?, string>?, string<=?, string>=?.
708 (No string-ci*? yet). string->number, number->string. Also atom->string,
709 string->atom (not R5RS).
710
711 Symbols
712 symbol->string, string->symbol
713
714 Characters
715 integer->char, char->integer.
716 char=?, char<?, char>?, char<=?, char>=?.
717 (No char-ci*?)
718
719 Pairs & Lists
720 cons, car, cdr, list, length, map, for-each, foldr, list-tail,
721 list-ref, last-pair, reverse, append.
722 Also member, memq, memv, based on generic-member, assoc, assq, assv
723 based on generic-assoc.
724
725 Streams
726 head, tail, cons-stream
727
728 Control features
729 Apart from procedure?, also macro? and closure?
730 map, for-each, force, delay, call-with-current-continuation (or call/cc),
731 eval, apply. 'Forcing' a value that is not a promise produces the value.
732 There is no call-with-values, values, nor dynamic-wind. Dynamic-wind in
733 the presence of continuations would require support from the abstract
734 machine itself.
735
736 Property lists
737 TinyScheme inherited from MiniScheme property lists for symbols.
738 put, get.
739
740 Dynamically-loaded extensions
741 (load-extension <filename without extension>)
742 Loads a DLL declaring foreign procedures. On Unix/Linux, one can make use
743 of the ld.so.conf file or the LD_RUN_PATH system variable in order to place
744 the library in a directory other than the current one. Please refer to the
745 appropriate 'man' page.
746
747 Esoteric procedures
748 (oblist)
749 Returns the oblist, an immutable list of all the symbols.
750
751 (macro-expand <form>)
752 Returns the expanded form of the macro call denoted by the argument
753
754 (define-with-return (<procname> <args>...) <body>)
755 Like plain 'define', but makes the continuation available as 'return'
756 inside the procedure. Handy for imperative programs.
757
758 (new-segment <num>)
759 Allocates more memory segments.
760
761 defined?
762 See "Environments"
763
764 (get-closure-code <closure>)
765 Gets the code as scheme data.
766
767 (make-closure <code> <environment>)
768 Makes a new closure in the given environment.
769
770 Obsolete procedures
771 (print-width <object>)
772
773 Programmer's Reference
774 ----------------------
775
776 The interpreter state is initialized with "scheme_init".
777 Custom memory allocation routines can be installed with an alternate
778 initialization function: "scheme_init_custom_alloc".
779 Files can be loaded with "scheme_load_file". Strings containing Scheme
780 code can be loaded with "scheme_load_string". It is a good idea to
781 "scheme_load" init.scm before anything else.
782
783 External data for keeping external state (of use to foreign functions)
784 can be installed with "scheme_set_external_data".
785 Foreign functions are installed with "assign_foreign". Additional
786 definitions can be added to the interpreter state, with "scheme_define"
787 (this is the way HTTP header data and HTML form data are passed to the
788 Scheme script in the Altera SQL Server). If you wish to define the
789 foreign function in a specific environment (to enhance modularity),
790 use "assign_foreign_env".
791
792 The procedure "scheme_apply0" has been added with persistent scripts in
793 mind. Persistent scripts are loaded once, and every time they are needed
794 to produce HTTP output, appropriate data are passed through global
795 definitions and function "main" is called to do the job. One could
796 add easily "scheme_apply1" etc.
797
798 The interpreter state should be deinitialized with "scheme_deinit".
799
800 DLLs containing foreign functions should define a function named
801 init_<base-name>. E.g. foo.dll should define init_foo, and bar.so
802 should define init_bar. This function should assign_foreign any foreign
803 function contained in the DLL.
804
805 The first dynamically loaded extension available for TinyScheme is
806 a regular expression library. Although it's by no means an
807 established standard, this library is supposed to be installed in
808 a directory mirroring its name under the TinyScheme location.
809
810
811 Foreign Functions
812 -----------------
813
814 The user can add foreign functions in C. For example, a function
815 that squares its argument:
816
817 pointer square(scheme *sc, pointer args) {
818 if(args!=sc->NIL) {
819 if(sc->isnumber(sc->pair_car(args))) {
820 double v=sc->rvalue(sc->pair_car(args));
821 return sc->mk_real(sc,v*v);
822 }
823 }
824 return sc->NIL;
825 }
826
827 Foreign functions are now defined as closures:
828
829 sc->interface->scheme_define(
830 sc,
831 sc->global_env,
832 sc->interface->mk_symbol(sc,"square"),
833 sc->interface->mk_foreign_func(sc, square));
834
835
836 Foreign functions can use the external data in the "scheme" struct
837 to implement any kind of external state.
838
839 External data are set with the following function:
840 void scheme_set_external_data(scheme *sc, void *p);
841
842 As of v.1.17, the canonical way for a foreign function in a DLL to
843 manipulate Scheme data is using the function pointers in sc->interface.
844
845 Standalone
846 ----------
847
848 Usage: tinyscheme -?
849 or: tinyscheme [<file1> <file2> ...]
850 followed by
851 -1 <file> [<arg1> <arg2> ...]
852 -c <Scheme commands> [<arg1> <arg2> ...]
853 assuming that the executable is named tinyscheme.
854
855 Use - in the place of a filename to denote stdin.
856 The -1 flag is meant for #! usage in shell scripts. If you specify
857 #! /somewhere/tinyscheme -1
858 then tinyscheme will be called to process the file. For example, the
859 following script echoes the Scheme list of its arguments.
860
861 #! /somewhere/tinyscheme -1
862 (display *args*)
863
864 The -c flag permits execution of arbitrary Scheme code.
865
866
867 Error Handling
868 --------------
869
870 Errors are recovered from without damage. The user can install his
871 own handler for system errors, by defining *error-hook*. Defining
872 to '() gives the default behavior, which is equivalent to "error".
873 USE_ERROR_HOOK must be defined.
874
875 A simple exception handling mechanism can be found in "init.scm".
876 A new syntactic form is introduced:
877
878 (catch <expr returned exceptionally>
879 <expr1> <expr2> ... <exprN>)
880
881 "Catch" establishes a scope spanning multiple call-frames
882 until another "catch" is encountered.
883
884 Exceptions are thrown with:
885
886 (throw "message")
887
888 If used outside a (catch ...), reverts to (error "message").
889
890 Example of use:
891
892 (define (foo x) (write x) (newline) (/ x 0))
893
894 (catch (begin (display "Error!\n") 0)
895 (write "Before foo ... ")
896 (foo 5)
897 (write "After foo"))
898
899 The exception mechanism can be used even by system errors, by
900
901 (define *error-hook* throw)
902
903 which makes use of the error hook described above.
904
905 If necessary, the user can devise his own exception mechanism with
906 tagged exceptions etc.
907
908
909 Reader extensions
910 -----------------
911
912 When encountering an unknown character after '#', the user-specified
913 procedure *sharp-hook* (if any), is called to read the expression.
914 This can be used to extend the reader to handle user-defined constants
915 or whatever. It should be a procedure without arguments, reading from
916 the current input port (which will be the load-port).
917
918
919 Colon Qualifiers - Packages
920 ---------------------------
921
922 When USE_COLON_HOOK=1:
923 The lexer now recognizes the construction <qualifier>::<symbol> and
924 transforms it in the following manner (T is the transformation function):
925
926 T(<qualifier>::<symbol>) = (*colon-hook* 'T(<symbol>) <qualifier>)
927
928 where <qualifier> is a symbol not containing any double-colons.
929
930 As the definition is recursive, qualifiers can be nested.
931 The user can define his own *colon-hook*, to handle qualified names.
932 By default, "init.scm" defines *colon-hook* as EVAL. Consequently,
933 the qualifier must denote a Scheme environment, such as one returned
934 by (interaction-environment). "Init.scm" defines a new syntantic form,
935 PACKAGE, as a simple example. It is used like this:
936
937 (define toto
938 (package
939 (define foo 1)
940 (define bar +)))
941
942 foo ==> Error, "foo" undefined
943 (eval 'foo) ==> Error, "foo" undefined
944 (eval 'foo toto) ==> 1
945 toto::foo ==> 1
946 ((eval 'bar toto) 2 (eval 'foo toto)) ==> 3
947 (toto::bar 2 toto::foo) ==> 3
948 (eval (bar 2 foo) toto) ==> 3
949
950 If the user installs another package infrastructure, he must define
951 a new 'package' procedure or macro to retain compatibility with supplied
952 code.
953
954 Note: Older versions used ':' as a qualifier. Unfortunately, the use
955 of ':' as a pseudo-qualifier in existing code (i.e. SLIB) essentially
956 precludes its use as a real qualifier.
957
958
959
960
961
962
963
964
-(0 . 0)(1 . 88)
969 TinyScheme would not exist if it wasn't for MiniScheme. I had just
970 written the HTTP server for Ovrimos SQL Server, and I was lamenting the
971 lack of a scripting language. Server-side Javascript would have been the
972 preferred solution, had there been a Javascript interpreter I could
973 lay my hands on. But there weren't. Perl would have been another solution,
974 but it was probably ten times bigger that the program it was supposed to
975 be embedded in. There would also be thorny licencing issues.
976
977 So, the obvious thing to do was find a trully small interpreter. Forth
978 was a language I had once quasi-implemented, but the difficulty of
979 handling dynamic data and the weirdness of the language put me off. I then
980 looked around for a LISP interpreter, the next thing I knew was easy to
981 implement. Alas, the LeLisp I knew from my days in UPMC (Universite Pierre
982 et Marie Curie) had given way to Common Lisp, a megalith of a language!
983 Then my search lead me to Scheme, a language I knew was very orthogonal
984 and clean. When I found Mini-Scheme, a single C file of some 2400 loc, I
985 fell in love with it! What if it lacked floating-point numbers and
986 strings! The rest, as they say, is history.
987
988 Below are the original credits. Don't email Akira KIDA, the address has
989 changed.
990
991 ---------- Mini-Scheme Interpreter Version 0.85 ----------
992
993 coded by Atsushi Moriwaki (11/5/1989)
994
995 E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp
996
997 THIS SOFTWARE IS IN THE PUBLIC DOMAIN
998 ------------------------------------
999 This software is completely free to copy, modify and/or re-distribute.
1000 But I would appreciate it if you left my name on the code as the author.
1001
1002 This version has been modified by R.C. Secrist.
1003
1004 Mini-Scheme is now maintained by Akira KIDA.
1005
1006 This is a revised and modified version by Akira KIDA.
1007 current version is 0.85k4 (15 May 1994)
1008
1009 Please send suggestions, bug reports and/or requests to:
1010 <SDI00379@niftyserve.or.jp>
1011
1012
1013 Features compared to MiniSCHEME
1014 -------------------------------
1015
1016 All code is now reentrant. Interpreter state is held in a 'scheme'
1017 struct, and many interpreters can coexist in the same program, possibly
1018 in different threads. The user can specify user-defined memory allocation
1019 primitives. (see "Programmer's Reference")
1020
1021 The reader is more consistent.
1022
1023 Strings, characters and flonums are supported. (see "Types")
1024
1025 Files being loaded can be nested up to some depth.
1026
1027 R5RS I/O is there, plus String Ports. (see "Scheme Reference","I/O")
1028
1029 Vectors exist.
1030
1031 As a standalone application, it supports command-line arguments.
1032 (see "Standalone")
1033
1034 Running out of memory is now handled.
1035
1036 The user can add foreign functions in C. (see "Foreign Functions")
1037
1038 The code has been changed slightly, core functions have been moved
1039 to the library, behavior has been aligned with R5RS etc.
1040
1041 Support has been added for user-defined error recovery.
1042 (see "Error Handling")
1043
1044 Support has been added for modular programming.
1045 (see "Colon Qualifiers - Packages")
1046
1047 To enable this, EVAL has changed internally, and can
1048 now take two arguments, as per R5RS. Environments are supported.
1049 (see "Colon Qualifiers - Packages")
1050
1051 Promises are now evaluated once only.
1052
1053 (macro (foo form) ...) is now equivalent to (macro foo (lambda(form) ...))
1054
1055 The reader can be extended using new #-expressions
1056 (see "Reader extensions")
-(0 . 0)(1 . 146)
1061 /* dynload.c Dynamic Loader for TinyScheme */
1062 /* Original Copyright (c) 1999 Alexander Shendi */
1063 /* Modifications for NT and dl_* interface, scm_load_ext: D. Souflis */
1064 /* Refurbished by Stephen Gildea */
1065
1066 #define _SCHEME_SOURCE
1067 #include "dynload.h"
1068 #include <string.h>
1069 #include <stdio.h>
1070 #include <stdlib.h>
1071
1072 #ifndef MAXPATHLEN
1073 # define MAXPATHLEN 1024
1074 #endif
1075
1076 static void make_filename(const char *name, char *filename);
1077 static void make_init_fn(const char *name, char *init_fn);
1078
1079 #ifdef _WIN32
1080 # include <windows.h>
1081 #else
1082 typedef void *HMODULE;
1083 typedef void (*FARPROC)();
1084 #define SUN_DL
1085 #include <dlfcn.h>
1086 #endif
1087
1088 #ifdef _WIN32
1089
1090 #define PREFIX ""
1091 #define SUFFIX ".dll"
1092
1093 static void display_w32_error_msg(const char *additional_message)
1094 {
1095 LPVOID msg_buf;
1096
1097 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
1098 NULL, GetLastError(), 0,
1099 (LPTSTR)&msg_buf, 0, NULL);
1100 fprintf(stderr, "scheme load-extension: %s: %s", additional_message, msg_buf);
1101 LocalFree(msg_buf);
1102 }
1103
1104 static HMODULE dl_attach(const char *module) {
1105 HMODULE dll = LoadLibrary(module);
1106 if (!dll) display_w32_error_msg(module);
1107 return dll;
1108 }
1109
1110 static FARPROC dl_proc(HMODULE mo, const char *proc) {
1111 FARPROC procedure = GetProcAddress(mo,proc);
1112 if (!procedure) display_w32_error_msg(proc);
1113 return procedure;
1114 }
1115
1116 static void dl_detach(HMODULE mo) {
1117 (void)FreeLibrary(mo);
1118 }
1119
1120 #elif defined(SUN_DL)
1121
1122 #include <dlfcn.h>
1123
1124 #define PREFIX "lib"
1125 #define SUFFIX ".so"
1126
1127 static HMODULE dl_attach(const char *module) {
1128 HMODULE so=dlopen(module,RTLD_LAZY);
1129 if(!so) {
1130 fprintf(stderr, "Error loading scheme extension \"%s\": %s\n", module, dlerror());
1131 }
1132 return so;
1133 }
1134
1135 static FARPROC dl_proc(HMODULE mo, const char *proc) {
1136 const char *errmsg;
1137 FARPROC fp=(FARPROC)dlsym(mo,proc);
1138 if ((errmsg = dlerror()) == 0) {
1139 return fp;
1140 }
1141 fprintf(stderr, "Error initializing scheme module \"%s\": %s\n", proc, errmsg);
1142 return 0;
1143 }
1144
1145 static void dl_detach(HMODULE mo) {
1146 (void)dlclose(mo);
1147 }
1148 #endif
1149
1150 pointer scm_load_ext(scheme *sc, pointer args)
1151 {
1152 pointer first_arg;
1153 pointer retval;
1154 char filename[MAXPATHLEN], init_fn[MAXPATHLEN+6];
1155 char *name;
1156 HMODULE dll_handle;
1157 void (*module_init)(scheme *sc);
1158
1159 if ((args != sc->NIL) && is_string((first_arg = pair_car(args)))) {
1160 name = string_value(first_arg);
1161 make_filename(name,filename);
1162 make_init_fn(name,init_fn);
1163 dll_handle = dl_attach(filename);
1164 if (dll_handle == 0) {
1165 retval = sc -> F;
1166 }
1167 else {
1168 module_init = (void(*)(scheme *))dl_proc(dll_handle, init_fn);
1169 if (module_init != 0) {
1170 (*module_init)(sc);
1171 retval = sc -> T;
1172 }
1173 else {
1174 retval = sc->F;
1175 }
1176 }
1177 }
1178 else {
1179 retval = sc -> F;
1180 }
1181
1182 return(retval);
1183 }
1184
1185 static void make_filename(const char *name, char *filename) {
1186 strcpy(filename,name);
1187 strcat(filename,SUFFIX);
1188 }
1189
1190 static void make_init_fn(const char *name, char *init_fn) {
1191 const char *p=strrchr(name,'/');
1192 if(p==0) {
1193 p=name;
1194 } else {
1195 p++;
1196 }
1197 strcpy(init_fn,"init_");
1198 strcat(init_fn,p);
1199 }
1200
1201
1202 /*
1203 Local variables:
1204 c-file-style: "k&r"
1205 End:
1206 */
-(0 . 0)(1 . 12)
1211 /* dynload.h */
1212 /* Original Copyright (c) 1999 Alexander Shendi */
1213 /* Modifications for NT and dl_* interface: D. Souflis */
1214
1215 #ifndef DYNLOAD_H
1216 #define DYNLOAD_H
1217
1218 #include "scheme-private.h"
1219
1220 SCHEME_EXPORT pointer scm_load_ext(scheme *sc, pointer arglist);
1221
1222 #endif
-(0 . 0)(1 . 244)
1227
1228 How to hack TinyScheme
1229 ----------------------
1230
1231 TinyScheme is easy to learn and modify. It is structured like a
1232 meta-interpreter, only it is written in C. All data are Scheme
1233 objects, which facilitates both understanding/modifying the
1234 code and reifying the interpreter workings.
1235
1236 In place of a dry description, we will pace through the addition
1237 of a useful new datatype: garbage-collected memory blocks.
1238 The interface will be:
1239
1240 (make-block <n> [<fill>]) makes a new block of the specified size
1241 optionally filling it with a specified byte
1242 (block? <obj>)
1243 (block-length <block>)
1244 (block-ref <block> <index>) retrieves byte at location
1245 (block-set! <block> <index> <byte>) modifies byte at location
1246
1247 In the sequel, lines that begin with '>' denote lines to add to the
1248 code. Lines that begin with '|' are just citations of existing code.
1249 Lines that begin with X denote lines to be removed from the code.
1250
1251 First of all, we need to assign a typeid to our new type. Typeids
1252 in TinyScheme are small integers declared in the scheme_types enum
1253 located near the top of the scheme.c file; it begins with T_STRING.
1254 Add a new entry at the end, say T_MEMBLOCK. Remember to adjust the
1255 value of T_LAST_SYTEM_TYPE when adding new entries. There can be at
1256 most 31 types, but you don't have to worry about that limit yet.
1257
1258 | T_ENVIRONMENT=14,
1259 X T_LAST_SYSTEM_TYPE=14
1260 > T_MEMBLOCK=15,
1261 > T_LAST_SYSTEM_TYPE=15
1262 | };
1263
1264
1265 Then, some helper macros would be useful. Go to where is_string()
1266 and the rest are defined and add:
1267
1268 > INTERFACE INLINE int is_memblock(pointer p) { return (type(p)==T_MEMBLOCK); }
1269
1270 This actually is a function, because it is meant to be exported by
1271 scheme.h. If no foreign function will ever manipulate a memory block,
1272 you can instead define it as a macro:
1273
1274 > #define is_memblock(p) (type(p)==T_MEMBLOCK)
1275
1276 Then we make space for the new type in the main data structure:
1277 struct cell. As it happens, the _string part of the union _object
1278 (that is used to hold character strings) has two fields that suit us:
1279
1280 | struct {
1281 | char *_svalue;
1282 | int _keynum;
1283 | } _string;
1284
1285 We can use _svalue to hold the actual pointer and _keynum to hold its
1286 length. If we couln't reuse existing fields, we could always add other
1287 alternatives in union _object.
1288
1289 We then proceed to write the function that actually makes a new block.
1290 For conformance reasons, we name it mk_memblock
1291
1292 > static pointer mk_memblock(scheme *sc, int len, char fill) {
1293 > pointer x;
1294 > char *p=(char*)sc->malloc(len);
1295 >
1296 > if(p==0) {
1297 > return sc->NIL;
1298 > }
1299 > x = get_cell(sc, sc->NIL, sc->NIL);
1300 >
1301 > typeflag(x) = T_MEMBLOCK|T_ATOM;
1302 > strvalue(x)=p;
1303 > keynum(x)=len;
1304 > memset(p,fill,len);
1305 > return (x);
1306 > }
1307
1308 The memory used by the MEMBLOCK will have to be freed when the cell
1309 is reclaimed during garbage collection. There is a placeholder for
1310 that staff, function finalize_cell(), currently handling strings only.
1311
1312 | static void finalize_cell(scheme *sc, pointer a) {
1313 | if(is_string(a)) {
1314 | sc->free(strvalue(a));
1315 > } else if(is_memblock(a)) {
1316 > sc->free(strvalue(a));
1317 | } else if(is_port(a)) {
1318
1319 There are no MEMBLOCK literals, so we don't concern ourselves with
1320 the READER part (yet!). We must cater to the PRINTER, though. We
1321 add one case more in atom2str().
1322
1323 | } else if (iscontinuation(l)) {
1324 | p = "#<CONTINUATION>";
1325 > } else if (is_memblock(l)) {
1326 > p = "#<MEMORY BLOCK>";
1327 | } else {
1328
1329 Whenever a MEMBLOCK is displayed, it will look like that.
1330 Now, we must add the interface functions: constructor, predicate,
1331 accessor, modifier. We must in fact create new op-codes for the virtual
1332 machine underlying TinyScheme. Since version 1.30, TinyScheme uses
1333 macros and a single source text to keep the enums and the dispatch table
1334 in sync. The op-codes are defined in the opdefines.h file with one line
1335 for each op-code. The lines in the file have six columns between the
1336 starting _OPDEF( and ending ): A, B, C, D, E, and OP.
1337 Note that this file uses unusually long lines to accomodate all the
1338 information; adjust your editor to handle this.
1339
1340 The purpose of the columns is:
1341 - Column A is the name of the subroutine that handles the op-code.
1342 - Column B is the name of the op-code function.
1343 - Columns C and D are the minimum and maximum number of arguments
1344 that are accepted by the op-code.
1345 - Column E is a set of flags that tells the interpreter the type of
1346 each of the arguments expected by the op-code.
1347 - Column OP is used in the scheme_opcodes enum located in the
1348 scheme-private.h file.
1349
1350 Op-codes are really just tags for a huge C switch, only this switch
1351 is broken up in to a number of different opexe_X functions. The
1352 correspondence is made in table "dispatch_table". There, we assign
1353 the new op-codes to opexe_2, where the equivalent ones for vectors
1354 are situated. We also assign a name for them, and specify the minimum
1355 and maximum arity (number of expected arguments). INF_ARG as a maximum
1356 arity means "unlimited".
1357
1358 For reasons of consistency, we add the new op-codes right after those
1359 for vectors:
1360
1361 | _OP_DEF(opexe_2, "vector-set!", 3, 3, TST_VECTOR TST_NATURAL TST_ANY, OP_VECSET )
1362 > _OP_DEF(opexe_2, "make-block", 1, 2, TST_NATURAL TST_CHAR, OP_MKBLOCK )
1363 > _OP_DEF(opexe_2, "block-length", 1, 1, T_MEMBLOCK, OP_BLOCKLEN )
1364 > _OP_DEF(opexe_2, "block-ref", 2, 2, T_MEMBLOCK TST_NATURAL, OP_BLOCKREF )
1365 > _OP_DEF(opexe_2, "block-set!", 1, 1, T_MEMBLOCK TST_NATURAL TST_CHAR, OP_BLOCKSET )
1366 | _OP_DEF(opexe_3, "not", 1, 1, TST_NONE, OP_NOT )
1367
1368 We add the predicate along with the other predicates in opexe_3:
1369
1370 | _OP_DEF(opexe_3, "vector?", 1, 1, TST_ANY, OP_VECTORP )
1371 > _OP_DEF(opexe_3, "block?", 1, 1, TST_ANY, OP_BLOCKP )
1372 | _OP_DEF(opexe_3, "eq?", 2, 2, TST_ANY, OP_EQ )
1373
1374 All that remains is to write the actual code to do the processing and
1375 add it to the switch statement in opexe_2, after the OP_VECSET case.
1376
1377 > case OP_MKBLOCK: { /* make-block */
1378 > int fill=0;
1379 > int len;
1380 >
1381 > if(!isnumber(car(sc->args))) {
1382 > Error_1(sc,"make-block: not a number:",car(sc->args));
1383 > }
1384 > len=ivalue(car(sc->args));
1385 > if(len<=0) {
1386 > Error_1(sc,"make-block: not positive:",car(sc->args));
1387 > }
1388 >
1389 > if(cdr(sc->args)!=sc->NIL) {
1390 > if(!isnumber(cadr(sc->args)) || ivalue(cadr(sc->args))<0) {
1391 > Error_1(sc,"make-block: not a positive number:",cadr(sc->args));
1392 > }
1393 > fill=charvalue(cadr(sc->args))%255;
1394 > }
1395 > s_return(sc,mk_memblock(sc,len,(char)fill));
1396 > }
1397 >
1398 > case OP_BLOCKLEN: /* block-length */
1399 > if(!ismemblock(car(sc->args))) {
1400 > Error_1(sc,"block-length: not a memory block:",car(sc->args));
1401 > }
1402 > s_return(sc,mk_integer(sc,keynum(car(sc->args))));
1403 >
1404 > case OP_BLOCKREF: { /* block-ref */
1405 > char *str;
1406 > int index;
1407 >
1408 > if(!ismemblock(car(sc->args))) {
1409 > Error_1(sc,"block-ref: not a memory block:",car(sc->args));
1410 > }
1411 > str=strvalue(car(sc->args));
1412 >
1413 > if(cdr(sc->args)==sc->NIL) {
1414 > Error_0(sc,"block-ref: needs two arguments");
1415 > }
1416 > if(!isnumber(cadr(sc->args))) {
1417 > Error_1(sc,"block-ref: not a number:",cadr(sc->args));
1418 > }
1419 > index=ivalue(cadr(sc->args));
1420 >
1421 > if(index<0 || index>=keynum(car(sc->args))) {
1422 > Error_1(sc,"block-ref: out of bounds:",cadr(sc->args));
1423 > }
1424 >
1425 > s_return(sc,mk_integer(sc,str[index]));
1426 > }
1427 >
1428 > case OP_BLOCKSET: { /* block-set! */
1429 > char *str;
1430 > int index;
1431 > int c;
1432 >
1433 > if(!ismemblock(car(sc->args))) {
1434 > Error_1(sc,"block-set!: not a memory block:",car(sc->args));
1435 > }
1436 > if(isimmutable(car(sc->args))) {
1437 > Error_1(sc,"block-set!: unable to alter immutable memory block:",car(sc->args));
1438 > }
1439 > str=strvalue(car(sc->args));
1440 >
1441 > if(cdr(sc->args)==sc->NIL) {
1442 > Error_0(sc,"block-set!: needs three arguments");
1443 > }
1444 > if(!isnumber(cadr(sc->args))) {
1445 > Error_1(sc,"block-set!: not a number:",cadr(sc->args));
1446 > }
1447 > index=ivalue(cadr(sc->args));
1448 > if(index<0 || index>=keynum(car(sc->args))) {
1449 > Error_1(sc,"block-set!: out of bounds:",cadr(sc->args));
1450 > }
1451 >
1452 > if(cddr(sc->args)==sc->NIL) {
1453 > Error_0(sc,"block-set!: needs three arguments");
1454 > }
1455 > if(!isinteger(caddr(sc->args))) {
1456 > Error_1(sc,"block-set!: not an integer:",caddr(sc->args));
1457 > }
1458 > c=ivalue(caddr(sc->args))%255;
1459 >
1460 > str[index]=(char)c;
1461 > s_return(sc,car(sc->args));
1462 > }
1463
1464 Finally, do the same for the predicate in opexe_3.
1465
1466 | case OP_VECTORP: /* vector? */
1467 | s_retbool(is_vector(car(sc->args)));
1468 > case OP_BLOCKP: /* block? */
1469 > s_retbool(is_memblock(car(sc->args)));
1470 | case OP_EQ: /* eq? */
-(0 . 0)(1 . 716)
1475 ; Initialization file for TinySCHEME 1.41
1476
1477 ; Per R5RS, up to four deep compositions should be defined
1478 (define (caar x) (car (car x)))
1479 (define (cadr x) (car (cdr x)))
1480 (define (cdar x) (cdr (car x)))
1481 (define (cddr x) (cdr (cdr x)))
1482 (define (caaar x) (car (car (car x))))
1483 (define (caadr x) (car (car (cdr x))))
1484 (define (cadar x) (car (cdr (car x))))
1485 (define (caddr x) (car (cdr (cdr x))))
1486 (define (cdaar x) (cdr (car (car x))))
1487 (define (cdadr x) (cdr (car (cdr x))))
1488 (define (cddar x) (cdr (cdr (car x))))
1489 (define (cdddr x) (cdr (cdr (cdr x))))
1490 (define (caaaar x) (car (car (car (car x)))))
1491 (define (caaadr x) (car (car (car (cdr x)))))
1492 (define (caadar x) (car (car (cdr (car x)))))
1493 (define (caaddr x) (car (car (cdr (cdr x)))))
1494 (define (cadaar x) (car (cdr (car (car x)))))
1495 (define (cadadr x) (car (cdr (car (cdr x)))))
1496 (define (caddar x) (car (cdr (cdr (car x)))))
1497 (define (cadddr x) (car (cdr (cdr (cdr x)))))
1498 (define (cdaaar x) (cdr (car (car (car x)))))
1499 (define (cdaadr x) (cdr (car (car (cdr x)))))
1500 (define (cdadar x) (cdr (car (cdr (car x)))))
1501 (define (cdaddr x) (cdr (car (cdr (cdr x)))))
1502 (define (cddaar x) (cdr (cdr (car (car x)))))
1503 (define (cddadr x) (cdr (cdr (car (cdr x)))))
1504 (define (cdddar x) (cdr (cdr (cdr (car x)))))
1505 (define (cddddr x) (cdr (cdr (cdr (cdr x)))))
1506
1507 ;;;; Utility to ease macro creation
1508 (define (macro-expand form)
1509 ((eval (get-closure-code (eval (car form)))) form))
1510
1511 (define (macro-expand-all form)
1512 (if (macro? form)
1513 (macro-expand-all (macro-expand form))
1514 form))
1515
1516 (define *compile-hook* macro-expand-all)
1517
1518
1519 (macro (unless form)
1520 `(if (not ,(cadr form)) (begin ,@(cddr form))))
1521
1522 (macro (when form)
1523 `(if ,(cadr form) (begin ,@(cddr form))))
1524
1525 ; DEFINE-MACRO Contributed by Andy Gaynor
1526 (macro (define-macro dform)
1527 (if (symbol? (cadr dform))
1528 `(macro ,@(cdr dform))
1529 (let ((form (gensym)))
1530 `(macro (,(caadr dform) ,form)
1531 (apply (lambda ,(cdadr dform) ,@(cddr dform)) (cdr ,form))))))
1532
1533 ; Utilities for math. Notice that inexact->exact is primitive,
1534 ; but exact->inexact is not.
1535 (define exact? integer?)
1536 (define (inexact? x) (and (real? x) (not (integer? x))))
1537 (define (even? n) (= (remainder n 2) 0))
1538 (define (odd? n) (not (= (remainder n 2) 0)))
1539 (define (zero? n) (= n 0))
1540 (define (positive? n) (> n 0))
1541 (define (negative? n) (< n 0))
1542 (define complex? number?)
1543 (define rational? real?)
1544 (define (abs n) (if (>= n 0) n (- n)))
1545 (define (exact->inexact n) (* n 1.0))
1546 (define (<> n1 n2) (not (= n1 n2)))
1547
1548 ; min and max must return inexact if any arg is inexact; use (+ n 0.0)
1549 (define (max . lst)
1550 (foldr (lambda (a b)
1551 (if (> a b)
1552 (if (exact? b) a (+ a 0.0))
1553 (if (exact? a) b (+ b 0.0))))
1554 (car lst) (cdr lst)))
1555 (define (min . lst)
1556 (foldr (lambda (a b)
1557 (if (< a b)
1558 (if (exact? b) a (+ a 0.0))
1559 (if (exact? a) b (+ b 0.0))))
1560 (car lst) (cdr lst)))
1561
1562 (define (succ x) (+ x 1))
1563 (define (pred x) (- x 1))
1564 (define gcd
1565 (lambda a
1566 (if (null? a)
1567 0
1568 (let ((aa (abs (car a)))
1569 (bb (abs (cadr a))))
1570 (if (= bb 0)
1571 aa
1572 (gcd bb (remainder aa bb)))))))
1573 (define lcm
1574 (lambda a
1575 (if (null? a)
1576 1
1577 (let ((aa (abs (car a)))
1578 (bb (abs (cadr a))))
1579 (if (or (= aa 0) (= bb 0))
1580 0
1581 (abs (* (quotient aa (gcd aa bb)) bb)))))))
1582
1583
1584 (define (string . charlist)
1585 (list->string charlist))
1586
1587 (define (list->string charlist)
1588 (let* ((len (length charlist))
1589 (newstr (make-string len))
1590 (fill-string!
1591 (lambda (str i len charlist)
1592 (if (= i len)
1593 str
1594 (begin (string-set! str i (car charlist))
1595 (fill-string! str (+ i 1) len (cdr charlist)))))))
1596 (fill-string! newstr 0 len charlist)))
1597
1598 (define (string-fill! s e)
1599 (let ((n (string-length s)))
1600 (let loop ((i 0))
1601 (if (= i n)
1602 s
1603 (begin (string-set! s i e) (loop (succ i)))))))
1604
1605 (define (string->list s)
1606 (let loop ((n (pred (string-length s))) (l '()))
1607 (if (= n -1)
1608 l
1609 (loop (pred n) (cons (string-ref s n) l)))))
1610
1611 (define (string-copy str)
1612 (string-append str))
1613
1614 (define (string->anyatom str pred)
1615 (let* ((a (string->atom str)))
1616 (if (pred a) a
1617 (error "string->xxx: not a xxx" a))))
1618
1619 (define (string->number str . base)
1620 (let ((n (string->atom str (if (null? base) 10 (car base)))))
1621 (if (number? n) n #f)))
1622
1623 (define (anyatom->string n pred)
1624 (if (pred n)
1625 (atom->string n)
1626 (error "xxx->string: not a xxx" n)))
1627
1628 (define (number->string n . base)
1629 (atom->string n (if (null? base) 10 (car base))))
1630
1631
1632 (define (char-cmp? cmp a b)
1633 (cmp (char->integer a) (char->integer b)))
1634 (define (char-ci-cmp? cmp a b)
1635 (cmp (char->integer (char-downcase a)) (char->integer (char-downcase b))))
1636
1637 (define (char=? a b) (char-cmp? = a b))
1638 (define (char<? a b) (char-cmp? < a b))
1639 (define (char>? a b) (char-cmp? > a b))
1640 (define (char<=? a b) (char-cmp? <= a b))
1641 (define (char>=? a b) (char-cmp? >= a b))
1642
1643 (define (char-ci=? a b) (char-ci-cmp? = a b))
1644 (define (char-ci<? a b) (char-ci-cmp? < a b))
1645 (define (char-ci>? a b) (char-ci-cmp? > a b))
1646 (define (char-ci<=? a b) (char-ci-cmp? <= a b))
1647 (define (char-ci>=? a b) (char-ci-cmp? >= a b))
1648
1649 ; Note the trick of returning (cmp x y)
1650 (define (string-cmp? chcmp cmp a b)
1651 (let ((na (string-length a)) (nb (string-length b)))
1652 (let loop ((i 0))
1653 (cond
1654 ((= i na)
1655 (if (= i nb) (cmp 0 0) (cmp 0 1)))
1656 ((= i nb)
1657 (cmp 1 0))
1658 ((chcmp = (string-ref a i) (string-ref b i))
1659 (loop (succ i)))
1660 (else
1661 (chcmp cmp (string-ref a i) (string-ref b i)))))))
1662
1663
1664 (define (string=? a b) (string-cmp? char-cmp? = a b))
1665 (define (string<? a b) (string-cmp? char-cmp? < a b))
1666 (define (string>? a b) (string-cmp? char-cmp? > a b))
1667 (define (string<=? a b) (string-cmp? char-cmp? <= a b))
1668 (define (string>=? a b) (string-cmp? char-cmp? >= a b))
1669
1670 (define (string-ci=? a b) (string-cmp? char-ci-cmp? = a b))
1671 (define (string-ci<? a b) (string-cmp? char-ci-cmp? < a b))
1672 (define (string-ci>? a b) (string-cmp? char-ci-cmp? > a b))
1673 (define (string-ci<=? a b) (string-cmp? char-ci-cmp? <= a b))
1674 (define (string-ci>=? a b) (string-cmp? char-ci-cmp? >= a b))
1675
1676 (define (list . x) x)
1677
1678 (define (foldr f x lst)
1679 (if (null? lst)
1680 x
1681 (foldr f (f x (car lst)) (cdr lst))))
1682
1683 (define (unzip1-with-cdr . lists)
1684 (unzip1-with-cdr-iterative lists '() '()))
1685
1686 (define (unzip1-with-cdr-iterative lists cars cdrs)
1687 (if (null? lists)
1688 (cons cars cdrs)
1689 (let ((car1 (caar lists))
1690 (cdr1 (cdar lists)))
1691 (unzip1-with-cdr-iterative
1692 (cdr lists)
1693 (append cars (list car1))
1694 (append cdrs (list cdr1))))))
1695
1696 (define (map proc . lists)
1697 (if (null? lists)
1698 (apply proc)
1699 (if (null? (car lists))
1700 '()
1701 (let* ((unz (apply unzip1-with-cdr lists))
1702 (cars (car unz))
1703 (cdrs (cdr unz)))
1704 (cons (apply proc cars) (apply map (cons proc cdrs)))))))
1705
1706 (define (for-each proc . lists)
1707 (if (null? lists)
1708 (apply proc)
1709 (if (null? (car lists))
1710 #t
1711 (let* ((unz (apply unzip1-with-cdr lists))
1712 (cars (car unz))
1713 (cdrs (cdr unz)))
1714 (apply proc cars) (apply map (cons proc cdrs))))))
1715
1716 (define (list-tail x k)
1717 (if (zero? k)
1718 x
1719 (list-tail (cdr x) (- k 1))))
1720
1721 (define (list-ref x k)
1722 (car (list-tail x k)))
1723
1724 (define (last-pair x)
1725 (if (pair? (cdr x))
1726 (last-pair (cdr x))
1727 x))
1728
1729 (define (head stream) (car stream))
1730
1731 (define (tail stream) (force (cdr stream)))
1732
1733 (define (vector-equal? x y)
1734 (and (vector? x) (vector? y) (= (vector-length x) (vector-length y))
1735 (let ((n (vector-length x)))
1736 (let loop ((i 0))
1737 (if (= i n)
1738 #t
1739 (and (equal? (vector-ref x i) (vector-ref y i))
1740 (loop (succ i))))))))
1741
1742 (define (list->vector x)
1743 (apply vector x))
1744
1745 (define (vector-fill! v e)
1746 (let ((n (vector-length v)))
1747 (let loop ((i 0))
1748 (if (= i n)
1749 v
1750 (begin (vector-set! v i e) (loop (succ i)))))))
1751
1752 (define (vector->list v)
1753 (let loop ((n (pred (vector-length v))) (l '()))
1754 (if (= n -1)
1755 l
1756 (loop (pred n) (cons (vector-ref v n) l)))))
1757
1758 ;; The following quasiquote macro is due to Eric S. Tiedemann.
1759 ;; Copyright 1988 by Eric S. Tiedemann; all rights reserved.
1760 ;;
1761 ;; Subsequently modified to handle vectors: D. Souflis
1762
1763 (macro
1764 quasiquote
1765 (lambda (l)
1766 (define (mcons f l r)
1767 (if (and (pair? r)
1768 (eq? (car r) 'quote)
1769 (eq? (car (cdr r)) (cdr f))
1770 (pair? l)
1771 (eq? (car l) 'quote)
1772 (eq? (car (cdr l)) (car f)))
1773 (if (or (procedure? f) (number? f) (string? f))
1774 f
1775 (list 'quote f))
1776 (if (eqv? l vector)
1777 (apply l (eval r))
1778 (list 'cons l r)
1779 )))
1780 (define (mappend f l r)
1781 (if (or (null? (cdr f))
1782 (and (pair? r)
1783 (eq? (car r) 'quote)
1784 (eq? (car (cdr r)) '())))
1785 l
1786 (list 'append l r)))
1787 (define (foo level form)
1788 (cond ((not (pair? form))
1789 (if (or (procedure? form) (number? form) (string? form))
1790 form
1791 (list 'quote form))
1792 )
1793 ((eq? 'quasiquote (car form))
1794 (mcons form ''quasiquote (foo (+ level 1) (cdr form))))
1795 (#t (if (zero? level)
1796 (cond ((eq? (car form) 'unquote) (car (cdr form)))
1797 ((eq? (car form) 'unquote-splicing)
1798 (error "Unquote-splicing wasn't in a list:"
1799 form))
1800 ((and (pair? (car form))
1801 (eq? (car (car form)) 'unquote-splicing))
1802 (mappend form (car (cdr (car form)))
1803 (foo level (cdr form))))
1804 (#t (mcons form (foo level (car form))
1805 (foo level (cdr form)))))
1806 (cond ((eq? (car form) 'unquote)
1807 (mcons form ''unquote (foo (- level 1)
1808 (cdr form))))
1809 ((eq? (car form) 'unquote-splicing)
1810 (mcons form ''unquote-splicing
1811 (foo (- level 1) (cdr form))))
1812 (#t (mcons form (foo level (car form))
1813 (foo level (cdr form)))))))))
1814 (foo 0 (car (cdr l)))))
1815
1816 ;;;;;Helper for the dynamic-wind definition. By Tom Breton (Tehom)
1817 (define (shared-tail x y)
1818 (let ((len-x (length x))
1819 (len-y (length y)))
1820 (define (shared-tail-helper x y)
1821 (if
1822 (eq? x y)
1823 x
1824 (shared-tail-helper (cdr x) (cdr y))))
1825
1826 (cond
1827 ((> len-x len-y)
1828 (shared-tail-helper
1829 (list-tail x (- len-x len-y))
1830 y))
1831 ((< len-x len-y)
1832 (shared-tail-helper
1833 x
1834 (list-tail y (- len-y len-x))))
1835 (#t (shared-tail-helper x y)))))
1836
1837 ;;;;;Dynamic-wind by Tom Breton (Tehom)
1838
1839 ;;Guarded because we must only eval this once, because doing so
1840 ;;redefines call/cc in terms of old call/cc
1841 (unless (defined? 'dynamic-wind)
1842 (let
1843 ;;These functions are defined in the context of a private list of
1844 ;;pairs of before/after procs.
1845 ( (*active-windings* '())
1846 ;;We'll define some functions into the larger environment, so
1847 ;;we need to know it.
1848 (outer-env (current-environment)))
1849
1850 ;;Poor-man's structure operations
1851 (define before-func car)
1852 (define after-func cdr)
1853 (define make-winding cons)
1854
1855 ;;Manage active windings
1856 (define (activate-winding! new)
1857 ((before-func new))
1858 (set! *active-windings* (cons new *active-windings*)))
1859 (define (deactivate-top-winding!)
1860 (let ((old-top (car *active-windings*)))
1861 ;;Remove it from the list first so it's not active during its
1862 ;;own exit.
1863 (set! *active-windings* (cdr *active-windings*))
1864 ((after-func old-top))))
1865
1866 (define (set-active-windings! new-ws)
1867 (unless (eq? new-ws *active-windings*)
1868 (let ((shared (shared-tail new-ws *active-windings*)))
1869
1870 ;;Define the looping functions.
1871 ;;Exit the old list. Do deeper ones last. Don't do
1872 ;;any shared ones.
1873 (define (pop-many)
1874 (unless (eq? *active-windings* shared)
1875 (deactivate-top-winding!)
1876 (pop-many)))
1877 ;;Enter the new list. Do deeper ones first so that the
1878 ;;deeper windings will already be active. Don't do any
1879 ;;shared ones.
1880 (define (push-many new-ws)
1881 (unless (eq? new-ws shared)
1882 (push-many (cdr new-ws))
1883 (activate-winding! (car new-ws))))
1884
1885 ;;Do it.
1886 (pop-many)
1887 (push-many new-ws))))
1888
1889 ;;The definitions themselves.
1890 (eval
1891 `(define call-with-current-continuation
1892 ;;It internally uses the built-in call/cc, so capture it.
1893 ,(let ((old-c/cc call-with-current-continuation))
1894 (lambda (func)
1895 ;;Use old call/cc to get the continuation.
1896 (old-c/cc
1897 (lambda (continuation)
1898 ;;Call func with not the continuation itself
1899 ;;but a procedure that adjusts the active
1900 ;;windings to what they were when we made
1901 ;;this, and only then calls the
1902 ;;continuation.
1903 (func
1904 (let ((current-ws *active-windings*))
1905 (lambda (x)
1906 (set-active-windings! current-ws)
1907 (continuation x)))))))))
1908 outer-env)
1909 ;;We can't just say "define (dynamic-wind before thunk after)"
1910 ;;because the lambda it's defined to lives in this environment,
1911 ;;not in the global environment.
1912 (eval
1913 `(define dynamic-wind
1914 ,(lambda (before thunk after)
1915 ;;Make a new winding
1916 (activate-winding! (make-winding before after))
1917 (let ((result (thunk)))
1918 ;;Get rid of the new winding.
1919 (deactivate-top-winding!)
1920 ;;The return value is that of thunk.
1921 result)))
1922 outer-env)))
1923
1924 (define call/cc call-with-current-continuation)
1925
1926
1927 ;;;;; atom? and equal? written by a.k
1928
1929 ;;;; atom?
1930 (define (atom? x)
1931 (not (pair? x)))
1932
1933 ;;;; equal?
1934 (define (equal? x y)
1935 (cond
1936 ((pair? x)
1937 (and (pair? y)
1938 (equal? (car x) (car y))
1939 (equal? (cdr x) (cdr y))))
1940 ((vector? x)
1941 (and (vector? y) (vector-equal? x y)))
1942 ((string? x)
1943 (and (string? y) (string=? x y)))
1944 (else (eqv? x y))))
1945
1946 ;;;; (do ((var init inc) ...) (endtest result ...) body ...)
1947 ;;
1948 (macro do
1949 (lambda (do-macro)
1950 (apply (lambda (do vars endtest . body)
1951 (let ((do-loop (gensym)))
1952 `(letrec ((,do-loop
1953 (lambda ,(map (lambda (x)
1954 (if (pair? x) (car x) x))
1955 `,vars)
1956 (if ,(car endtest)
1957 (begin ,@(cdr endtest))
1958 (begin
1959 ,@body
1960 (,do-loop
1961 ,@(map (lambda (x)
1962 (cond
1963 ((not (pair? x)) x)
1964 ((< (length x) 3) (car x))
1965 (else (car (cdr (cdr x))))))
1966 `,vars)))))))
1967 (,do-loop
1968 ,@(map (lambda (x)
1969 (if (and (pair? x) (cdr x))
1970 (car (cdr x))
1971 '()))
1972 `,vars)))))
1973 do-macro)))
1974
1975 ;;;; generic-member
1976 (define (generic-member cmp obj lst)
1977 (cond
1978 ((null? lst) #f)
1979 ((cmp obj (car lst)) lst)
1980 (else (generic-member cmp obj (cdr lst)))))
1981
1982 (define (memq obj lst)
1983 (generic-member eq? obj lst))
1984 (define (memv obj lst)
1985 (generic-member eqv? obj lst))
1986 (define (member obj lst)
1987 (generic-member equal? obj lst))
1988
1989 ;;;; generic-assoc
1990 (define (generic-assoc cmp obj alst)
1991 (cond
1992 ((null? alst) #f)
1993 ((cmp obj (caar alst)) (car alst))
1994 (else (generic-assoc cmp obj (cdr alst)))))
1995
1996 (define (assq obj alst)
1997 (generic-assoc eq? obj alst))
1998 (define (assv obj alst)
1999 (generic-assoc eqv? obj alst))
2000 (define (assoc obj alst)
2001 (generic-assoc equal? obj alst))
2002
2003 (define (acons x y z) (cons (cons x y) z))
2004
2005 ;;;; Handy for imperative programs
2006 ;;;; Used as: (define-with-return (foo x y) .... (return z) ...)
2007 (macro (define-with-return form)
2008 `(define ,(cadr form)
2009 (call/cc (lambda (return) ,@(cddr form)))))
2010
2011 ;;;; Simple exception handling
2012 ;
2013 ; Exceptions are caught as follows:
2014 ;
2015 ; (catch (do-something to-recover and-return meaningful-value)
2016 ; (if-something goes-wrong)
2017 ; (with-these calls))
2018 ;
2019 ; "Catch" establishes a scope spanning multiple call-frames
2020 ; until another "catch" is encountered.
2021 ;
2022 ; Exceptions are thrown with:
2023 ;
2024 ; (throw "message")
2025 ;
2026 ; If used outside a (catch ...), reverts to (error "message)
2027
2028 (define *handlers* (list))
2029
2030 (define (push-handler proc)
2031 (set! *handlers* (cons proc *handlers*)))
2032
2033 (define (pop-handler)
2034 (let ((h (car *handlers*)))
2035 (set! *handlers* (cdr *handlers*))
2036 h))
2037
2038 (define (more-handlers?)
2039 (pair? *handlers*))
2040
2041 (define (throw . x)
2042 (if (more-handlers?)
2043 (apply (pop-handler))
2044 (apply error x)))
2045
2046 (macro (catch form)
2047 (let ((label (gensym)))
2048 `(call/cc (lambda (exit)
2049 (push-handler (lambda () (exit ,(cadr form))))
2050 (let ((,label (begin ,@(cddr form))))
2051 (pop-handler)
2052 ,label)))))
2053
2054 (define *error-hook* throw)
2055
2056
2057 ;;;;; Definition of MAKE-ENVIRONMENT, to be used with two-argument EVAL
2058
2059 (macro (make-environment form)
2060 `(apply (lambda ()
2061 ,@(cdr form)
2062 (current-environment))))
2063
2064 (define-macro (eval-polymorphic x . envl)
2065 (display envl)
2066 (let* ((env (if (null? envl) (current-environment) (eval (car envl))))
2067 (xval (eval x env)))
2068 (if (closure? xval)
2069 (make-closure (get-closure-code xval) env)
2070 xval)))
2071
2072 ; Redefine this if you install another package infrastructure
2073 ; Also redefine 'package'
2074 (define *colon-hook* eval)
2075
2076 ;;;;; I/O
2077
2078 (define (input-output-port? p)
2079 (and (input-port? p) (output-port? p)))
2080
2081 (define (close-port p)
2082 (cond
2083 ((input-output-port? p) (close-input-port (close-output-port p)))
2084 ((input-port? p) (close-input-port p))
2085 ((output-port? p) (close-output-port p))
2086 (else (throw "Not a port" p))))
2087
2088 (define (call-with-input-file s p)
2089 (let ((inport (open-input-file s)))
2090 (if (eq? inport #f)
2091 #f
2092 (let ((res (p inport)))
2093 (close-input-port inport)
2094 res))))
2095
2096 (define (call-with-output-file s p)
2097 (let ((outport (open-output-file s)))
2098 (if (eq? outport #f)
2099 #f
2100 (let ((res (p outport)))
2101 (close-output-port outport)
2102 res))))
2103
2104 (define (with-input-from-file s p)
2105 (let ((inport (open-input-file s)))
2106 (if (eq? inport #f)
2107 #f
2108 (let ((prev-inport (current-input-port)))
2109 (set-input-port inport)
2110 (let ((res (p)))
2111 (close-input-port inport)
2112 (set-input-port prev-inport)
2113 res)))))
2114
2115 (define (with-output-to-file s p)
2116 (let ((outport (open-output-file s)))
2117 (if (eq? outport #f)
2118 #f
2119 (let ((prev-outport (current-output-port)))
2120 (set-output-port outport)
2121 (let ((res (p)))
2122 (close-output-port outport)
2123 (set-output-port prev-outport)
2124 res)))))
2125
2126 (define (with-input-output-from-to-files si so p)
2127 (let ((inport (open-input-file si))
2128 (outport (open-input-file so)))
2129 (if (not (and inport outport))
2130 (begin
2131 (close-input-port inport)
2132 (close-output-port outport)
2133 #f)
2134 (let ((prev-inport (current-input-port))
2135 (prev-outport (current-output-port)))
2136 (set-input-port inport)
2137 (set-output-port outport)
2138 (let ((res (p)))
2139 (close-input-port inport)
2140 (close-output-port outport)
2141 (set-input-port prev-inport)
2142 (set-output-port prev-outport)
2143 res)))))
2144
2145 ; Random number generator (maximum cycle)
2146 (define *seed* 1)
2147 (define (random-next)
2148 (let* ((a 16807) (m 2147483647) (q (quotient m a)) (r (modulo m a)))
2149 (set! *seed*
2150 (- (* a (- *seed*
2151 (* (quotient *seed* q) q)))
2152 (* (quotient *seed* q) r)))
2153 (if (< *seed* 0) (set! *seed* (+ *seed* m)))
2154 *seed*))
2155 ;; SRFI-0
2156 ;; COND-EXPAND
2157 ;; Implemented as a macro
2158 (define *features* '(srfi-0))
2159
2160 (define-macro (cond-expand . cond-action-list)
2161 (cond-expand-runtime cond-action-list))
2162
2163 (define (cond-expand-runtime cond-action-list)
2164 (if (null? cond-action-list)
2165 #t
2166 (if (cond-eval (caar cond-action-list))
2167 `(begin ,@(cdar cond-action-list))
2168 (cond-expand-runtime (cdr cond-action-list)))))
2169
2170 (define (cond-eval-and cond-list)
2171 (foldr (lambda (x y) (and (cond-eval x) (cond-eval y))) #t cond-list))
2172
2173 (define (cond-eval-or cond-list)
2174 (foldr (lambda (x y) (or (cond-eval x) (cond-eval y))) #f cond-list))
2175
2176 (define (cond-eval condition)
2177 (cond
2178 ((symbol? condition)
2179 (if (member condition *features*) #t #f))
2180 ((eq? condition #t) #t)
2181 ((eq? condition #f) #f)
2182 (else (case (car condition)
2183 ((and) (cond-eval-and (cdr condition)))
2184 ((or) (cond-eval-or (cdr condition)))
2185 ((not) (if (not (null? (cddr condition)))
2186 (error "cond-expand : 'not' takes 1 argument")
2187 (not (cond-eval (cadr condition)))))
2188 (else (error "cond-expand : unknown operator" (car condition)))))))
2189
2190 (gc-verbose #f)
-(0 . 0)(1 . 98)
2195 # Makefile for TinyScheme
2196 # Time-stamp: <2002-06-24 14:13:27 gildea>
2197
2198 # Windows/2000
2199 #CC = cl -nologo
2200 #DEBUG= -W3 -Z7 -MD
2201 #DL_FLAGS=
2202 #SYS_LIBS=
2203 #Osuf=obj
2204 #SOsuf=dll
2205 #LIBsuf=.lib
2206 #EXE_EXT=.exe
2207 #LD = link -nologo
2208 #LDFLAGS = -debug -map -dll -incremental:no
2209 #LIBPREFIX =
2210 #OUT = -out:$@
2211 #RM= -del
2212 #AR= echo
2213
2214 # Unix, generally
2215 CC = gcc -fpic -pedantic
2216 DEBUG=-g -Wall -Wno-char-subscripts -O
2217 Osuf=o
2218 SOsuf=so
2219 LIBsuf=a
2220 EXE_EXT=
2221 LIBPREFIX=lib
2222 OUT = -o $@
2223 RM= -rm -f
2224 AR= ar crs
2225
2226 # Linux
2227 LD = gcc
2228 LDFLAGS = -shared
2229 DEBUG=-g -Wno-char-subscripts -O
2230 SYS_LIBS= -ldl -lm
2231 PLATFORM_FEATURES= -DSUN_DL=1
2232
2233 # Cygwin
2234 #PLATFORM_FEATURES = -DUSE_STRLWR=0
2235
2236 # MinGW/MSYS
2237 #SOsuf=dll
2238 #PLATFORM_FEATURES = -DUSE_STRLWR=0
2239
2240 # Mac OS X
2241 #LD = gcc
2242 #LDFLAGS = --dynamiclib
2243 #DEBUG=-g -Wno-char-subscripts -O
2244 #SYS_LIBS= -ldl
2245 #PLATFORM_FEATURES= -DUSE_STRLWR=1 -D__APPLE__=1 -DOSX=1
2246
2247
2248 # Solaris
2249 #SYS_LIBS= -ldl -lc
2250 #Osuf=o
2251 #SOsuf=so
2252 #EXE_EXT=
2253 #LD = ld
2254 #LDFLAGS = -G -Bsymbolic -z text
2255 #LIBPREFIX = lib
2256 #OUT = -o $@
2257
2258 FEATURES = $(PLATFORM_FEATURES) -DUSE_DL=1 -DUSE_MATH=1 -DUSE_ASCII_NAMES=0
2259
2260 OBJS = scheme.$(Osuf) dynload.$(Osuf)
2261
2262 LIBTARGET = $(LIBPREFIX)tinyscheme.$(SOsuf)
2263 STATICLIBTARGET = $(LIBPREFIX)tinyscheme.$(LIBsuf)
2264
2265 all: $(LIBTARGET) $(STATICLIBTARGET) scheme$(EXE_EXT)
2266
2267 %.$(Osuf): %.c
2268 $(CC) -I. -c $(DEBUG) $(FEATURES) $(DL_FLAGS) $<
2269
2270 $(LIBTARGET): $(OBJS)
2271 $(LD) $(LDFLAGS) $(OUT) $(OBJS) $(SYS_LIBS)
2272
2273 scheme$(EXE_EXT): $(OBJS)
2274 $(CC) -o $@ $(DEBUG) $(OBJS) $(SYS_LIBS)
2275
2276 $(STATICLIBTARGET): $(OBJS)
2277 $(AR) $@ $(OBJS)
2278
2279 $(OBJS): scheme.h scheme-private.h opdefines.h
2280 dynload.$(Osuf): dynload.h
2281
2282 clean:
2283 $(RM) $(OBJS) $(LIBTARGET) $(STATICLIBTARGET) scheme$(EXE_EXT)
2284 $(RM) tinyscheme.ilk tinyscheme.map tinyscheme.pdb tinyscheme.exp
2285 $(RM) scheme.ilk scheme.map scheme.pdb scheme.lib scheme.exp
2286 $(RM) *~
2287
2288 TAGS_SRCS = scheme.h scheme.c dynload.h dynload.c
2289
2290 tags: TAGS
2291 TAGS: $(TAGS_SRCS)
2292 etags $(TAGS_SRCS)
-(0 . 0)(1 . 195)
2297 _OP_DEF(opexe_0, "load", 1, 1, TST_STRING, OP_LOAD )
2298 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_T0LVL )
2299 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_T1LVL )
2300 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_READ_INTERNAL )
2301 _OP_DEF(opexe_0, "gensym", 0, 0, 0, OP_GENSYM )
2302 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_VALUEPRINT )
2303 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_EVAL )
2304 #if USE_TRACING
2305 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_REAL_EVAL )
2306 #endif
2307 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_E0ARGS )
2308 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_E1ARGS )
2309 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_APPLY )
2310 #if USE_TRACING
2311 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_REAL_APPLY )
2312 _OP_DEF(opexe_0, "tracing", 1, 1, TST_NATURAL, OP_TRACING )
2313 #endif
2314 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_DOMACRO )
2315 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LAMBDA )
2316 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LAMBDA1 )
2317 _OP_DEF(opexe_0, "make-closure", 1, 2, TST_PAIR TST_ENVIRONMENT, OP_MKCLOSURE )
2318 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_QUOTE )
2319 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_DEF0 )
2320 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_DEF1 )
2321 _OP_DEF(opexe_0, "defined?", 1, 2, TST_SYMBOL TST_ENVIRONMENT, OP_DEFP )
2322 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_BEGIN )
2323 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_IF0 )
2324 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_IF1 )
2325 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_SET0 )
2326 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_SET1 )
2327 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET0 )
2328 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET1 )
2329 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET2 )
2330 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET0AST )
2331 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET1AST )
2332 _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET2AST )
2333 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET0REC )
2334 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET1REC )
2335 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET2REC )
2336 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_COND0 )
2337 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_COND1 )
2338 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_DELAY )
2339 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_AND0 )
2340 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_AND1 )
2341 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_OR0 )
2342 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_OR1 )
2343 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_C0STREAM )
2344 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_C1STREAM )
2345 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_MACRO0 )
2346 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_MACRO1 )
2347 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE0 )
2348 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE1 )
2349 _OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE2 )
2350 _OP_DEF(opexe_1, "eval", 1, 2, TST_ANY TST_ENVIRONMENT, OP_PEVAL )
2351 _OP_DEF(opexe_1, "apply", 1, INF_ARG, TST_NONE, OP_PAPPLY )
2352 _OP_DEF(opexe_1, "call-with-current-continuation", 1, 1, TST_NONE, OP_CONTINUATION )
2353 #if USE_MATH
2354 _OP_DEF(opexe_2, "inexact->exact", 1, 1, TST_NUMBER, OP_INEX2EX )
2355 _OP_DEF(opexe_2, "exp", 1, 1, TST_NUMBER, OP_EXP )
2356 _OP_DEF(opexe_2, "log", 1, 1, TST_NUMBER, OP_LOG )
2357 _OP_DEF(opexe_2, "sin", 1, 1, TST_NUMBER, OP_SIN )
2358 _OP_DEF(opexe_2, "cos", 1, 1, TST_NUMBER, OP_COS )
2359 _OP_DEF(opexe_2, "tan", 1, 1, TST_NUMBER, OP_TAN )
2360 _OP_DEF(opexe_2, "asin", 1, 1, TST_NUMBER, OP_ASIN )
2361 _OP_DEF(opexe_2, "acos", 1, 1, TST_NUMBER, OP_ACOS )
2362 _OP_DEF(opexe_2, "atan", 1, 2, TST_NUMBER, OP_ATAN )
2363 _OP_DEF(opexe_2, "sqrt", 1, 1, TST_NUMBER, OP_SQRT )
2364 _OP_DEF(opexe_2, "expt", 2, 2, TST_NUMBER, OP_EXPT )
2365 _OP_DEF(opexe_2, "floor", 1, 1, TST_NUMBER, OP_FLOOR )
2366 _OP_DEF(opexe_2, "ceiling", 1, 1, TST_NUMBER, OP_CEILING )
2367 _OP_DEF(opexe_2, "truncate", 1, 1, TST_NUMBER, OP_TRUNCATE )
2368 _OP_DEF(opexe_2, "round", 1, 1, TST_NUMBER, OP_ROUND )
2369 #endif
2370 _OP_DEF(opexe_2, "+", 0, INF_ARG, TST_NUMBER, OP_ADD )
2371 _OP_DEF(opexe_2, "-", 1, INF_ARG, TST_NUMBER, OP_SUB )
2372 _OP_DEF(opexe_2, "*", 0, INF_ARG, TST_NUMBER, OP_MUL )
2373 _OP_DEF(opexe_2, "/", 1, INF_ARG, TST_NUMBER, OP_DIV )
2374 _OP_DEF(opexe_2, "quotient", 1, INF_ARG, TST_INTEGER, OP_INTDIV )
2375 _OP_DEF(opexe_2, "remainder", 2, 2, TST_INTEGER, OP_REM )
2376 _OP_DEF(opexe_2, "modulo", 2, 2, TST_INTEGER, OP_MOD )
2377 _OP_DEF(opexe_2, "car", 1, 1, TST_PAIR, OP_CAR )
2378 _OP_DEF(opexe_2, "cdr", 1, 1, TST_PAIR, OP_CDR )
2379 _OP_DEF(opexe_2, "cons", 2, 2, TST_NONE, OP_CONS )
2380 _OP_DEF(opexe_2, "set-car!", 2, 2, TST_PAIR TST_ANY, OP_SETCAR )
2381 _OP_DEF(opexe_2, "set-cdr!", 2, 2, TST_PAIR TST_ANY, OP_SETCDR )
2382 _OP_DEF(opexe_2, "char->integer", 1, 1, TST_CHAR, OP_CHAR2INT )
2383 _OP_DEF(opexe_2, "integer->char", 1, 1, TST_NATURAL, OP_INT2CHAR )
2384 _OP_DEF(opexe_2, "char-upcase", 1, 1, TST_CHAR, OP_CHARUPCASE )
2385 _OP_DEF(opexe_2, "char-downcase", 1, 1, TST_CHAR, OP_CHARDNCASE )
2386 _OP_DEF(opexe_2, "symbol->string", 1, 1, TST_SYMBOL, OP_SYM2STR )
2387 _OP_DEF(opexe_2, "atom->string", 1, 2, TST_ANY TST_NATURAL, OP_ATOM2STR )
2388 _OP_DEF(opexe_2, "string->symbol", 1, 1, TST_STRING, OP_STR2SYM )
2389 _OP_DEF(opexe_2, "string->atom", 1, 2, TST_STRING TST_NATURAL, OP_STR2ATOM )
2390 _OP_DEF(opexe_2, "make-string", 1, 2, TST_NATURAL TST_CHAR, OP_MKSTRING )
2391 _OP_DEF(opexe_2, "string-length", 1, 1, TST_STRING, OP_STRLEN )
2392 _OP_DEF(opexe_2, "string-ref", 2, 2, TST_STRING TST_NATURAL, OP_STRREF )
2393 _OP_DEF(opexe_2, "string-set!", 3, 3, TST_STRING TST_NATURAL TST_CHAR, OP_STRSET )
2394 _OP_DEF(opexe_2, "string-append", 0, INF_ARG, TST_STRING, OP_STRAPPEND )
2395 _OP_DEF(opexe_2, "substring", 2, 3, TST_STRING TST_NATURAL, OP_SUBSTR )
2396 _OP_DEF(opexe_2, "vector", 0, INF_ARG, TST_NONE, OP_VECTOR )
2397 _OP_DEF(opexe_2, "make-vector", 1, 2, TST_NATURAL TST_ANY, OP_MKVECTOR )
2398 _OP_DEF(opexe_2, "vector-length", 1, 1, TST_VECTOR, OP_VECLEN )
2399 _OP_DEF(opexe_2, "vector-ref", 2, 2, TST_VECTOR TST_NATURAL, OP_VECREF )
2400 _OP_DEF(opexe_2, "vector-set!", 3, 3, TST_VECTOR TST_NATURAL TST_ANY, OP_VECSET )
2401 _OP_DEF(opexe_3, "not", 1, 1, TST_NONE, OP_NOT )
2402 _OP_DEF(opexe_3, "boolean?", 1, 1, TST_NONE, OP_BOOLP )
2403 _OP_DEF(opexe_3, "eof-object?", 1, 1, TST_NONE, OP_EOFOBJP )
2404 _OP_DEF(opexe_3, "null?", 1, 1, TST_NONE, OP_NULLP )
2405 _OP_DEF(opexe_3, "=", 2, INF_ARG, TST_NUMBER, OP_NUMEQ )
2406 _OP_DEF(opexe_3, "<", 2, INF_ARG, TST_NUMBER, OP_LESS )
2407 _OP_DEF(opexe_3, ">", 2, INF_ARG, TST_NUMBER, OP_GRE )
2408 _OP_DEF(opexe_3, "<=", 2, INF_ARG, TST_NUMBER, OP_LEQ )
2409 _OP_DEF(opexe_3, ">=", 2, INF_ARG, TST_NUMBER, OP_GEQ )
2410 _OP_DEF(opexe_3, "symbol?", 1, 1, TST_ANY, OP_SYMBOLP )
2411 _OP_DEF(opexe_3, "number?", 1, 1, TST_ANY, OP_NUMBERP )
2412 _OP_DEF(opexe_3, "string?", 1, 1, TST_ANY, OP_STRINGP )
2413 _OP_DEF(opexe_3, "integer?", 1, 1, TST_ANY, OP_INTEGERP )
2414 _OP_DEF(opexe_3, "real?", 1, 1, TST_ANY, OP_REALP )
2415 _OP_DEF(opexe_3, "char?", 1, 1, TST_ANY, OP_CHARP )
2416 #if USE_CHAR_CLASSIFIERS
2417 _OP_DEF(opexe_3, "char-alphabetic?", 1, 1, TST_CHAR, OP_CHARAP )
2418 _OP_DEF(opexe_3, "char-numeric?", 1, 1, TST_CHAR, OP_CHARNP )
2419 _OP_DEF(opexe_3, "char-whitespace?", 1, 1, TST_CHAR, OP_CHARWP )
2420 _OP_DEF(opexe_3, "char-upper-case?", 1, 1, TST_CHAR, OP_CHARUP )
2421 _OP_DEF(opexe_3, "char-lower-case?", 1, 1, TST_CHAR, OP_CHARLP )
2422 #endif
2423 _OP_DEF(opexe_3, "port?", 1, 1, TST_ANY, OP_PORTP )
2424 _OP_DEF(opexe_3, "input-port?", 1, 1, TST_ANY, OP_INPORTP )
2425 _OP_DEF(opexe_3, "output-port?", 1, 1, TST_ANY, OP_OUTPORTP )
2426 _OP_DEF(opexe_3, "procedure?", 1, 1, TST_ANY, OP_PROCP )
2427 _OP_DEF(opexe_3, "pair?", 1, 1, TST_ANY, OP_PAIRP )
2428 _OP_DEF(opexe_3, "list?", 1, 1, TST_ANY, OP_LISTP )
2429 _OP_DEF(opexe_3, "environment?", 1, 1, TST_ANY, OP_ENVP )
2430 _OP_DEF(opexe_3, "vector?", 1, 1, TST_ANY, OP_VECTORP )
2431 _OP_DEF(opexe_3, "eq?", 2, 2, TST_ANY, OP_EQ )
2432 _OP_DEF(opexe_3, "eqv?", 2, 2, TST_ANY, OP_EQV )
2433 _OP_DEF(opexe_4, "force", 1, 1, TST_ANY, OP_FORCE )
2434 _OP_DEF(opexe_4, 0, 0, 0, 0, OP_SAVE_FORCED )
2435 _OP_DEF(opexe_4, "write", 1, 2, TST_ANY TST_OUTPORT, OP_WRITE )
2436 _OP_DEF(opexe_4, "write-char", 1, 2, TST_CHAR TST_OUTPORT, OP_WRITE_CHAR )
2437 _OP_DEF(opexe_4, "display", 1, 2, TST_ANY TST_OUTPORT, OP_DISPLAY )
2438 _OP_DEF(opexe_4, "newline", 0, 1, TST_OUTPORT, OP_NEWLINE )
2439 _OP_DEF(opexe_4, "error", 1, INF_ARG, TST_NONE, OP_ERR0 )
2440 _OP_DEF(opexe_4, 0, 0, 0, 0, OP_ERR1 )
2441 _OP_DEF(opexe_4, "reverse", 1, 1, TST_LIST, OP_REVERSE )
2442 _OP_DEF(opexe_4, "list*", 1, INF_ARG, TST_NONE, OP_LIST_STAR )
2443 _OP_DEF(opexe_4, "append", 0, INF_ARG, TST_NONE, OP_APPEND )
2444 #if USE_PLIST
2445 _OP_DEF(opexe_4, "put", 3, 3, TST_NONE, OP_PUT )
2446 _OP_DEF(opexe_4, "get", 2, 2, TST_NONE, OP_GET )
2447 #endif
2448 _OP_DEF(opexe_4, "quit", 0, 1, TST_NUMBER, OP_QUIT )
2449 _OP_DEF(opexe_4, "gc", 0, 0, 0, OP_GC )
2450 _OP_DEF(opexe_4, "gc-verbose", 0, 1, TST_NONE, OP_GCVERB )
2451 _OP_DEF(opexe_4, "new-segment", 0, 1, TST_NUMBER, OP_NEWSEGMENT )
2452 _OP_DEF(opexe_4, "oblist", 0, 0, 0, OP_OBLIST )
2453 _OP_DEF(opexe_4, "current-input-port", 0, 0, 0, OP_CURR_INPORT )
2454 _OP_DEF(opexe_4, "current-output-port", 0, 0, 0, OP_CURR_OUTPORT )
2455 _OP_DEF(opexe_4, "open-input-file", 1, 1, TST_STRING, OP_OPEN_INFILE )
2456 _OP_DEF(opexe_4, "open-output-file", 1, 1, TST_STRING, OP_OPEN_OUTFILE )
2457 _OP_DEF(opexe_4, "open-input-output-file", 1, 1, TST_STRING, OP_OPEN_INOUTFILE )
2458 #if USE_STRING_PORTS
2459 _OP_DEF(opexe_4, "open-input-string", 1, 1, TST_STRING, OP_OPEN_INSTRING )
2460 _OP_DEF(opexe_4, "open-input-output-string", 1, 1, TST_STRING, OP_OPEN_INOUTSTRING )
2461 _OP_DEF(opexe_4, "open-output-string", 0, 1, TST_STRING, OP_OPEN_OUTSTRING )
2462 _OP_DEF(opexe_4, "get-output-string", 1, 1, TST_OUTPORT, OP_GET_OUTSTRING )
2463 #endif
2464 _OP_DEF(opexe_4, "close-input-port", 1, 1, TST_INPORT, OP_CLOSE_INPORT )
2465 _OP_DEF(opexe_4, "close-output-port", 1, 1, TST_OUTPORT, OP_CLOSE_OUTPORT )
2466 _OP_DEF(opexe_4, "interaction-environment", 0, 0, 0, OP_INT_ENV )
2467 _OP_DEF(opexe_4, "current-environment", 0, 0, 0, OP_CURR_ENV )
2468 _OP_DEF(opexe_5, "read", 0, 1, TST_INPORT, OP_READ )
2469 _OP_DEF(opexe_5, "read-char", 0, 1, TST_INPORT, OP_READ_CHAR )
2470 _OP_DEF(opexe_5, "peek-char", 0, 1, TST_INPORT, OP_PEEK_CHAR )
2471 _OP_DEF(opexe_5, "char-ready?", 0, 1, TST_INPORT, OP_CHAR_READY )
2472 _OP_DEF(opexe_5, "set-input-port", 1, 1, TST_INPORT, OP_SET_INPORT )
2473 _OP_DEF(opexe_5, "set-output-port", 1, 1, TST_OUTPORT, OP_SET_OUTPORT )
2474 _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDSEXPR )
2475 _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDLIST )
2476 _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDDOT )
2477 _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQUOTE )
2478 _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQQUOTE )
2479 _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQQUOTEVEC )
2480 _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDUNQUOTE )
2481 _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDUQTSP )
2482 _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDVEC )
2483 _OP_DEF(opexe_5, 0, 0, 0, 0, OP_P0LIST )
2484 _OP_DEF(opexe_5, 0, 0, 0, 0, OP_P1LIST )
2485 _OP_DEF(opexe_5, 0, 0, 0, 0, OP_PVECFROM )
2486 _OP_DEF(opexe_6, "length", 1, 1, TST_LIST, OP_LIST_LENGTH )
2487 _OP_DEF(opexe_6, "assq", 2, 2, TST_NONE, OP_ASSQ )
2488 _OP_DEF(opexe_6, "get-closure-code", 1, 1, TST_NONE, OP_GET_CLOSURE )
2489 _OP_DEF(opexe_6, "closure?", 1, 1, TST_NONE, OP_CLOSUREP )
2490 _OP_DEF(opexe_6, "macro?", 1, 1, TST_NONE, OP_MACROP )
2491 #undef _OP_DEF
-(0 . 0)(1 . 210)
2496 /* scheme-private.h */
2497
2498 #ifndef _SCHEME_PRIVATE_H
2499 #define _SCHEME_PRIVATE_H
2500
2501 #include "scheme.h"
2502 /*------------------ Ugly internals -----------------------------------*/
2503 /*------------------ Of interest only to FFI users --------------------*/
2504
2505 #ifdef __cplusplus
2506 extern "C" {
2507 #endif
2508
2509 enum scheme_port_kind {
2510 port_free=0,
2511 port_file=1,
2512 port_string=2,
2513 port_srfi6=4,
2514 port_input=16,
2515 port_output=32,
2516 port_saw_EOF=64
2517 };
2518
2519 typedef struct port {
2520 unsigned char kind;
2521 union {
2522 struct {
2523 FILE *file;
2524 int closeit;
2525 #if SHOW_ERROR_LINE
2526 int curr_line;
2527 char *filename;
2528 #endif
2529 } stdio;
2530 struct {
2531 char *start;
2532 char *past_the_end;
2533 char *curr;
2534 } string;
2535 } rep;
2536 } port;
2537
2538 /* cell structure */
2539 struct cell {
2540 unsigned int _flag;
2541 union {
2542 struct {
2543 char *_svalue;
2544 int _length;
2545 } _string;
2546 num _number;
2547 port *_port;
2548 foreign_func _ff;
2549 struct {
2550 struct cell *_car;
2551 struct cell *_cdr;
2552 } _cons;
2553 } _object;
2554 };
2555
2556 struct scheme {
2557 /* arrays for segments */
2558 func_alloc malloc;
2559 func_dealloc free;
2560
2561 /* return code */
2562 int retcode;
2563 int tracing;
2564
2565
2566 #define CELL_SEGSIZE 5000 /* # of cells in one segment */
2567 #define CELL_NSEGMENT 10 /* # of segments for cells */
2568 char *alloc_seg[CELL_NSEGMENT];
2569 pointer cell_seg[CELL_NSEGMENT];
2570 int last_cell_seg;
2571
2572 /* We use 4 registers. */
2573 pointer args; /* register for arguments of function */
2574 pointer envir; /* stack register for current environment */
2575 pointer code; /* register for current code */
2576 pointer dump; /* stack register for next evaluation */
2577
2578 int interactive_repl; /* are we in an interactive REPL? */
2579
2580 struct cell _sink;
2581 pointer sink; /* when mem. alloc. fails */
2582 struct cell _NIL;
2583 pointer NIL; /* special cell representing empty cell */
2584 struct cell _HASHT;
2585 pointer T; /* special cell representing #t */
2586 struct cell _HASHF;
2587 pointer F; /* special cell representing #f */
2588 struct cell _EOF_OBJ;
2589 pointer EOF_OBJ; /* special cell representing end-of-file object */
2590 pointer oblist; /* pointer to symbol table */
2591 pointer global_env; /* pointer to global environment */
2592 pointer c_nest; /* stack for nested calls from C */
2593
2594 /* global pointers to special symbols */
2595 pointer LAMBDA; /* pointer to syntax lambda */
2596 pointer QUOTE; /* pointer to syntax quote */
2597
2598 pointer QQUOTE; /* pointer to symbol quasiquote */
2599 pointer UNQUOTE; /* pointer to symbol unquote */
2600 pointer UNQUOTESP; /* pointer to symbol unquote-splicing */
2601 pointer FEED_TO; /* => */
2602 pointer COLON_HOOK; /* *colon-hook* */
2603 pointer ERROR_HOOK; /* *error-hook* */
2604 pointer SHARP_HOOK; /* *sharp-hook* */
2605 pointer COMPILE_HOOK; /* *compile-hook* */
2606
2607 pointer free_cell; /* pointer to top of free cells */
2608 long fcells; /* # of free cells */
2609
2610 pointer inport;
2611 pointer outport;
2612 pointer save_inport;
2613 pointer loadport;
2614
2615 #define MAXFIL 64
2616 port load_stack[MAXFIL]; /* Stack of open files for port -1 (LOADing) */
2617 int nesting_stack[MAXFIL];
2618 int file_i;
2619 int nesting;
2620
2621 char gc_verbose; /* if gc_verbose is not zero, print gc status */
2622 char no_memory; /* Whether mem. alloc. has failed */
2623
2624 #define LINESIZE 1024
2625 char linebuff[LINESIZE];
2626 #define STRBUFFSIZE 256
2627 char strbuff[STRBUFFSIZE];
2628
2629 FILE *tmpfp;
2630 int tok;
2631 int print_flag;
2632 pointer value;
2633 int op;
2634
2635 void *ext_data; /* For the benefit of foreign functions */
2636 long gensym_cnt;
2637
2638 struct scheme_interface *vptr;
2639 void *dump_base; /* pointer to base of allocated dump stack */
2640 int dump_size; /* number of frames allocated for dump stack */
2641 };
2642
2643 /* operator code */
2644 enum scheme_opcodes {
2645 #define _OP_DEF(A,B,C,D,E,OP) OP,
2646 #include "opdefines.h"
2647 OP_MAXDEFINED
2648 };
2649
2650
2651 #define cons(sc,a,b) _cons(sc,a,b,0)
2652 #define immutable_cons(sc,a,b) _cons(sc,a,b,1)
2653
2654 int is_string(pointer p);
2655 char *string_value(pointer p);
2656 int is_number(pointer p);
2657 num nvalue(pointer p);
2658 long ivalue(pointer p);
2659 double rvalue(pointer p);
2660 int is_integer(pointer p);
2661 int is_real(pointer p);
2662 int is_character(pointer p);
2663 long charvalue(pointer p);
2664 int is_vector(pointer p);
2665
2666 int is_port(pointer p);
2667
2668 int is_pair(pointer p);
2669 pointer pair_car(pointer p);
2670 pointer pair_cdr(pointer p);
2671 pointer set_car(pointer p, pointer q);
2672 pointer set_cdr(pointer p, pointer q);
2673
2674 int is_symbol(pointer p);
2675 char *symname(pointer p);
2676 int hasprop(pointer p);
2677
2678 int is_syntax(pointer p);
2679 int is_proc(pointer p);
2680 int is_foreign(pointer p);
2681 char *syntaxname(pointer p);
2682 int is_closure(pointer p);
2683 #ifdef USE_MACRO
2684 int is_macro(pointer p);
2685 #endif
2686 pointer closure_code(pointer p);
2687 pointer closure_env(pointer p);
2688
2689 int is_continuation(pointer p);
2690 int is_promise(pointer p);
2691 int is_environment(pointer p);
2692 int is_immutable(pointer p);
2693 void setimmutable(pointer p);
2694
2695 #ifdef __cplusplus
2696 }
2697 #endif
2698
2699 #endif
2700
2701 /*
2702 Local variables:
2703 c-file-style: "k&r"
2704 End:
2705 */
-(0 . 0)(1 . 5051)
2710 /* T I N Y S C H E M E 1 . 4 1
2711 * Dimitrios Souflis (dsouflis@acm.org)
2712 * Based on MiniScheme (original credits follow)
2713 * (MINISCM) coded by Atsushi Moriwaki (11/5/1989)
2714 * (MINISCM) E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp
2715 * (MINISCM) This version has been modified by R.C. Secrist.
2716 * (MINISCM)
2717 * (MINISCM) Mini-Scheme is now maintained by Akira KIDA.
2718 * (MINISCM)
2719 * (MINISCM) This is a revised and modified version by Akira KIDA.
2720 * (MINISCM) current version is 0.85k4 (15 May 1994)
2721 *
2722 */
2723
2724 #define _SCHEME_SOURCE
2725 #include "scheme-private.h"
2726 #ifndef WIN32
2727 # include <unistd.h>
2728 #endif
2729 #ifdef WIN32
2730 #define snprintf _snprintf
2731 #endif
2732 #if USE_DL
2733 # include "dynload.h"
2734 #endif
2735 #if USE_MATH
2736 # include <math.h>
2737 #endif
2738
2739 #include <limits.h>
2740 #include <float.h>
2741 #include <ctype.h>
2742
2743 #if USE_STRCASECMP
2744 #include <strings.h>
2745 # ifndef __APPLE__
2746 # define stricmp strcasecmp
2747 # endif
2748 #endif
2749
2750 /* Used for documentation purposes, to signal functions in 'interface' */
2751 #define INTERFACE
2752
2753 #define TOK_EOF (-1)
2754 #define TOK_LPAREN 0
2755 #define TOK_RPAREN 1
2756 #define TOK_DOT 2
2757 #define TOK_ATOM 3
2758 #define TOK_QUOTE 4
2759 #define TOK_COMMENT 5
2760 #define TOK_DQUOTE 6
2761 #define TOK_BQUOTE 7
2762 #define TOK_COMMA 8
2763 #define TOK_ATMARK 9
2764 #define TOK_SHARP 10
2765 #define TOK_SHARP_CONST 11
2766 #define TOK_VEC 12
2767
2768 #define BACKQUOTE '`'
2769 #define DELIMITERS "()\";\f\t\v\n\r "
2770
2771 /*
2772 * Basic memory allocation units
2773 */
2774
2775 #define banner "TinyScheme 1.41"
2776
2777 #include <string.h>
2778 #include <stdlib.h>
2779
2780 #ifdef __APPLE__
2781 static int stricmp(const char *s1, const char *s2)
2782 {
2783 unsigned char c1, c2;
2784 do {
2785 c1 = tolower(*s1);
2786 c2 = tolower(*s2);
2787 if (c1 < c2)
2788 return -1;
2789 else if (c1 > c2)
2790 return 1;
2791 s1++, s2++;
2792 } while (c1 != 0);
2793 return 0;
2794 }
2795 #endif /* __APPLE__ */
2796
2797 #if USE_STRLWR
2798 static const char *strlwr(char *s) {
2799 const char *p=s;
2800 while(*s) {
2801 *s=tolower(*s);
2802 s++;
2803 }
2804 return p;
2805 }
2806 #endif
2807
2808 #ifndef prompt
2809 # define prompt "ts> "
2810 #endif
2811
2812 #ifndef InitFile
2813 # define InitFile "init.scm"
2814 #endif
2815
2816 #ifndef FIRST_CELLSEGS
2817 # define FIRST_CELLSEGS 3
2818 #endif
2819
2820 enum scheme_types {
2821 T_STRING=1,
2822 T_NUMBER=2,
2823 T_SYMBOL=3,
2824 T_PROC=4,
2825 T_PAIR=5,
2826 T_CLOSURE=6,
2827 T_CONTINUATION=7,
2828 T_FOREIGN=8,
2829 T_CHARACTER=9,
2830 T_PORT=10,
2831 T_VECTOR=11,
2832 T_MACRO=12,
2833 T_PROMISE=13,
2834 T_ENVIRONMENT=14,
2835 T_LAST_SYSTEM_TYPE=14
2836 };
2837
2838 /* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */
2839 #define ADJ 32
2840 #define TYPE_BITS 5
2841 #define T_MASKTYPE 31 /* 0000000000011111 */
2842 #define T_SYNTAX 4096 /* 0001000000000000 */
2843 #define T_IMMUTABLE 8192 /* 0010000000000000 */
2844 #define T_ATOM 16384 /* 0100000000000000 */ /* only for gc */
2845 #define CLRATOM 49151 /* 1011111111111111 */ /* only for gc */
2846 #define MARK 32768 /* 1000000000000000 */
2847 #define UNMARK 32767 /* 0111111111111111 */
2848
2849
2850 static num num_add(num a, num b);
2851 static num num_mul(num a, num b);
2852 static num num_div(num a, num b);
2853 static num num_intdiv(num a, num b);
2854 static num num_sub(num a, num b);
2855 static num num_rem(num a, num b);
2856 static num num_mod(num a, num b);
2857 static int num_eq(num a, num b);
2858 static int num_gt(num a, num b);
2859 static int num_ge(num a, num b);
2860 static int num_lt(num a, num b);
2861 static int num_le(num a, num b);
2862
2863 #if USE_MATH
2864 static double round_per_R5RS(double x);
2865 #endif
2866 static int is_zero_double(double x);
2867 static INLINE int num_is_integer(pointer p) {
2868 return ((p)->_object._number.is_fixnum);
2869 }
2870
2871 static num num_zero;
2872 static num num_one;
2873
2874 /* macros for cell operations */
2875 #define typeflag(p) ((p)->_flag)
2876 #define type(p) (typeflag(p)&T_MASKTYPE)
2877
2878 INTERFACE INLINE int is_string(pointer p) { return (type(p)==T_STRING); }
2879 #define strvalue(p) ((p)->_object._string._svalue)
2880 #define strlength(p) ((p)->_object._string._length)
2881
2882 INTERFACE static int is_list(scheme *sc, pointer p);
2883 INTERFACE INLINE int is_vector(pointer p) { return (type(p)==T_VECTOR); }
2884 INTERFACE static void fill_vector(pointer vec, pointer obj);
2885 INTERFACE static pointer vector_elem(pointer vec, int ielem);
2886 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a);
2887 INTERFACE INLINE int is_number(pointer p) { return (type(p)==T_NUMBER); }
2888 INTERFACE INLINE int is_integer(pointer p) {
2889 if (!is_number(p))
2890 return 0;
2891 if (num_is_integer(p) || (double)ivalue(p) == rvalue(p))
2892 return 1;
2893 return 0;
2894 }
2895
2896 INTERFACE INLINE int is_real(pointer p) {
2897 return is_number(p) && (!(p)->_object._number.is_fixnum);
2898 }
2899
2900 INTERFACE INLINE int is_character(pointer p) { return (type(p)==T_CHARACTER); }
2901 INTERFACE INLINE char *string_value(pointer p) { return strvalue(p); }
2902 INLINE num nvalue(pointer p) { return ((p)->_object._number); }
2903 INTERFACE long ivalue(pointer p) { return (num_is_integer(p)?(p)->_object._number.value.ivalue:(long)(p)->_object._number.value.rvalue); }
2904 INTERFACE double rvalue(pointer p) { return (!num_is_integer(p)?(p)->_object._number.value.rvalue:(double)(p)->_object._number.value.ivalue); }
2905 #define ivalue_unchecked(p) ((p)->_object._number.value.ivalue)
2906 #define rvalue_unchecked(p) ((p)->_object._number.value.rvalue)
2907 #define set_num_integer(p) (p)->_object._number.is_fixnum=1;
2908 #define set_num_real(p) (p)->_object._number.is_fixnum=0;
2909 INTERFACE long charvalue(pointer p) { return ivalue_unchecked(p); }
2910
2911 INTERFACE INLINE int is_port(pointer p) { return (type(p)==T_PORT); }
2912 INTERFACE INLINE int is_inport(pointer p) { return is_port(p) && p->_object._port->kind & port_input; }
2913 INTERFACE INLINE int is_outport(pointer p) { return is_port(p) && p->_object._port->kind & port_output; }
2914
2915 INTERFACE INLINE int is_pair(pointer p) { return (type(p)==T_PAIR); }
2916 #define car(p) ((p)->_object._cons._car)
2917 #define cdr(p) ((p)->_object._cons._cdr)
2918 INTERFACE pointer pair_car(pointer p) { return car(p); }
2919 INTERFACE pointer pair_cdr(pointer p) { return cdr(p); }
2920 INTERFACE pointer set_car(pointer p, pointer q) { return car(p)=q; }
2921 INTERFACE pointer set_cdr(pointer p, pointer q) { return cdr(p)=q; }
2922
2923 INTERFACE INLINE int is_symbol(pointer p) { return (type(p)==T_SYMBOL); }
2924 INTERFACE INLINE char *symname(pointer p) { return strvalue(car(p)); }
2925 #if USE_PLIST
2926 SCHEME_EXPORT INLINE int hasprop(pointer p) { return (typeflag(p)&T_SYMBOL); }
2927 #define symprop(p) cdr(p)
2928 #endif
2929
2930 INTERFACE INLINE int is_syntax(pointer p) { return (typeflag(p)&T_SYNTAX); }
2931 INTERFACE INLINE int is_proc(pointer p) { return (type(p)==T_PROC); }
2932 INTERFACE INLINE int is_foreign(pointer p) { return (type(p)==T_FOREIGN); }
2933 INTERFACE INLINE char *syntaxname(pointer p) { return strvalue(car(p)); }
2934 #define procnum(p) ivalue(p)
2935 static const char *procname(pointer x);
2936
2937 INTERFACE INLINE int is_closure(pointer p) { return (type(p)==T_CLOSURE); }
2938 INTERFACE INLINE int is_macro(pointer p) { return (type(p)==T_MACRO); }
2939 INTERFACE INLINE pointer closure_code(pointer p) { return car(p); }
2940 INTERFACE INLINE pointer closure_env(pointer p) { return cdr(p); }
2941
2942 INTERFACE INLINE int is_continuation(pointer p) { return (type(p)==T_CONTINUATION); }
2943 #define cont_dump(p) cdr(p)
2944
2945 /* To do: promise should be forced ONCE only */
2946 INTERFACE INLINE int is_promise(pointer p) { return (type(p)==T_PROMISE); }
2947
2948 INTERFACE INLINE int is_environment(pointer p) { return (type(p)==T_ENVIRONMENT); }
2949 #define setenvironment(p) typeflag(p) = T_ENVIRONMENT
2950
2951 #define is_atom(p) (typeflag(p)&T_ATOM)
2952 #define setatom(p) typeflag(p) |= T_ATOM
2953 #define clratom(p) typeflag(p) &= CLRATOM
2954
2955 #define is_mark(p) (typeflag(p)&MARK)
2956 #define setmark(p) typeflag(p) |= MARK
2957 #define clrmark(p) typeflag(p) &= UNMARK
2958
2959 INTERFACE INLINE int is_immutable(pointer p) { return (typeflag(p)&T_IMMUTABLE); }
2960 /*#define setimmutable(p) typeflag(p) |= T_IMMUTABLE*/
2961 INTERFACE INLINE void setimmutable(pointer p) { typeflag(p) |= T_IMMUTABLE; }
2962
2963 #define caar(p) car(car(p))
2964 #define cadr(p) car(cdr(p))
2965 #define cdar(p) cdr(car(p))
2966 #define cddr(p) cdr(cdr(p))
2967 #define cadar(p) car(cdr(car(p)))
2968 #define caddr(p) car(cdr(cdr(p)))
2969 #define cdaar(p) cdr(car(car(p)))
2970 #define cadaar(p) car(cdr(car(car(p))))
2971 #define cadddr(p) car(cdr(cdr(cdr(p))))
2972 #define cddddr(p) cdr(cdr(cdr(cdr(p))))
2973
2974 #if USE_CHAR_CLASSIFIERS
2975 static INLINE int Cisalpha(int c) { return isascii(c) && isalpha(c); }
2976 static INLINE int Cisdigit(int c) { return isascii(c) && isdigit(c); }
2977 static INLINE int Cisspace(int c) { return isascii(c) && isspace(c); }
2978 static INLINE int Cisupper(int c) { return isascii(c) && isupper(c); }
2979 static INLINE int Cislower(int c) { return isascii(c) && islower(c); }
2980 #endif
2981
2982 #if USE_ASCII_NAMES
2983 static const char *charnames[32]={
2984 "nul",
2985 "soh",
2986 "stx",
2987 "etx",
2988 "eot",
2989 "enq",
2990 "ack",
2991 "bel",
2992 "bs",
2993 "ht",
2994 "lf",
2995 "vt",
2996 "ff",
2997 "cr",
2998 "so",
2999 "si",
3000 "dle",
3001 "dc1",
3002 "dc2",
3003 "dc3",
3004 "dc4",
3005 "nak",
3006 "syn",
3007 "etb",
3008 "can",
3009 "em",
3010 "sub",
3011 "esc",
3012 "fs",
3013 "gs",
3014 "rs",
3015 "us"
3016 };
3017
3018 static int is_ascii_name(const char *name, int *pc) {
3019 int i;
3020 for(i=0; i<32; i++) {
3021 if(stricmp(name,charnames[i])==0) {
3022 *pc=i;
3023 return 1;
3024 }
3025 }
3026 if(stricmp(name,"del")==0) {
3027 *pc=127;
3028 return 1;
3029 }
3030 return 0;
3031 }
3032
3033 #endif
3034
3035 static int file_push(scheme *sc, const char *fname);
3036 static void file_pop(scheme *sc);
3037 static int file_interactive(scheme *sc);
3038 static INLINE int is_one_of(char *s, int c);
3039 static int alloc_cellseg(scheme *sc, int n);
3040 static long binary_decode(const char *s);
3041 static INLINE pointer get_cell(scheme *sc, pointer a, pointer b);
3042 static pointer _get_cell(scheme *sc, pointer a, pointer b);
3043 static pointer reserve_cells(scheme *sc, int n);
3044 static pointer get_consecutive_cells(scheme *sc, int n);
3045 static pointer find_consecutive_cells(scheme *sc, int n);
3046 static void finalize_cell(scheme *sc, pointer a);
3047 static int count_consecutive_cells(pointer x, int needed);
3048 static pointer find_slot_in_env(scheme *sc, pointer env, pointer sym, int all);
3049 static pointer mk_number(scheme *sc, num n);
3050 static char *store_string(scheme *sc, int len, const char *str, char fill);
3051 static pointer mk_vector(scheme *sc, int len);
3052 static pointer mk_atom(scheme *sc, char *q);
3053 static pointer mk_sharp_const(scheme *sc, char *name);
3054 static pointer mk_port(scheme *sc, port *p);
3055 static pointer port_from_filename(scheme *sc, const char *fn, int prop);
3056 static pointer port_from_file(scheme *sc, FILE *, int prop);
3057 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop);
3058 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop);
3059 static port *port_rep_from_file(scheme *sc, FILE *, int prop);
3060 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop);
3061 static void port_close(scheme *sc, pointer p, int flag);
3062 static void mark(pointer a);
3063 static void gc(scheme *sc, pointer a, pointer b);
3064 static int basic_inchar(port *pt);
3065 static int inchar(scheme *sc);
3066 static void backchar(scheme *sc, int c);
3067 static char *readstr_upto(scheme *sc, char *delim);
3068 static pointer readstrexp(scheme *sc);
3069 static INLINE int skipspace(scheme *sc);
3070 static int token(scheme *sc);
3071 static void printslashstring(scheme *sc, char *s, int len);
3072 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen);
3073 static void printatom(scheme *sc, pointer l, int f);
3074 static pointer mk_proc(scheme *sc, enum scheme_opcodes op);
3075 static pointer mk_closure(scheme *sc, pointer c, pointer e);
3076 static pointer mk_continuation(scheme *sc, pointer d);
3077 static pointer reverse(scheme *sc, pointer a);
3078 static pointer reverse_in_place(scheme *sc, pointer term, pointer list);
3079 static pointer revappend(scheme *sc, pointer a, pointer b);
3080 static void dump_stack_mark(scheme *);
3081 static pointer opexe_0(scheme *sc, enum scheme_opcodes op);
3082 static pointer opexe_1(scheme *sc, enum scheme_opcodes op);
3083 static pointer opexe_2(scheme *sc, enum scheme_opcodes op);
3084 static pointer opexe_3(scheme *sc, enum scheme_opcodes op);
3085 static pointer opexe_4(scheme *sc, enum scheme_opcodes op);
3086 static pointer opexe_5(scheme *sc, enum scheme_opcodes op);
3087 static pointer opexe_6(scheme *sc, enum scheme_opcodes op);
3088 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op);
3089 static void assign_syntax(scheme *sc, char *name);
3090 static int syntaxnum(pointer p);
3091 static void assign_proc(scheme *sc, enum scheme_opcodes, char *name);
3092
3093 #define num_ivalue(n) (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue)
3094 #define num_rvalue(n) (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue)
3095
3096 static num num_add(num a, num b) {
3097 num ret;
3098 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
3099 if(ret.is_fixnum) {
3100 ret.value.ivalue= a.value.ivalue+b.value.ivalue;
3101 } else {
3102 ret.value.rvalue=num_rvalue(a)+num_rvalue(b);
3103 }
3104 return ret;
3105 }
3106
3107 static num num_mul(num a, num b) {
3108 num ret;
3109 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
3110 if(ret.is_fixnum) {
3111 ret.value.ivalue= a.value.ivalue*b.value.ivalue;
3112 } else {
3113 ret.value.rvalue=num_rvalue(a)*num_rvalue(b);
3114 }
3115 return ret;
3116 }
3117
3118 static num num_div(num a, num b) {
3119 num ret;
3120 ret.is_fixnum=a.is_fixnum && b.is_fixnum && a.value.ivalue%b.value.ivalue==0;
3121 if(ret.is_fixnum) {
3122 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
3123 } else {
3124 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
3125 }
3126 return ret;
3127 }
3128
3129 static num num_intdiv(num a, num b) {
3130 num ret;
3131 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
3132 if(ret.is_fixnum) {
3133 ret.value.ivalue= a.value.ivalue/b.value.ivalue;
3134 } else {
3135 ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
3136 }
3137 return ret;
3138 }
3139
3140 static num num_sub(num a, num b) {
3141 num ret;
3142 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
3143 if(ret.is_fixnum) {
3144 ret.value.ivalue= a.value.ivalue-b.value.ivalue;
3145 } else {
3146 ret.value.rvalue=num_rvalue(a)-num_rvalue(b);
3147 }
3148 return ret;
3149 }
3150
3151 static num num_rem(num a, num b) {
3152 num ret;
3153 long e1, e2, res;
3154 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
3155 e1=num_ivalue(a);
3156 e2=num_ivalue(b);
3157 res=e1%e2;
3158 /* remainder should have same sign as second operand */
3159 if (res > 0) {
3160 if (e1 < 0) {
3161 res -= labs(e2);
3162 }
3163 } else if (res < 0) {
3164 if (e1 > 0) {
3165 res += labs(e2);
3166 }
3167 }
3168 ret.value.ivalue=res;
3169 return ret;
3170 }
3171
3172 static num num_mod(num a, num b) {
3173 num ret;
3174 long e1, e2, res;
3175 ret.is_fixnum=a.is_fixnum && b.is_fixnum;
3176 e1=num_ivalue(a);
3177 e2=num_ivalue(b);
3178 res=e1%e2;
3179 /* modulo should have same sign as second operand */
3180 if (res * e2 < 0) {
3181 res += e2;
3182 }
3183 ret.value.ivalue=res;
3184 return ret;
3185 }
3186
3187 static int num_eq(num a, num b) {
3188 int ret;
3189 int is_fixnum=a.is_fixnum && b.is_fixnum;
3190 if(is_fixnum) {
3191 ret= a.value.ivalue==b.value.ivalue;
3192 } else {
3193 ret=num_rvalue(a)==num_rvalue(b);
3194 }
3195 return ret;
3196 }
3197
3198
3199 static int num_gt(num a, num b) {
3200 int ret;
3201 int is_fixnum=a.is_fixnum && b.is_fixnum;
3202 if(is_fixnum) {
3203 ret= a.value.ivalue>b.value.ivalue;
3204 } else {
3205 ret=num_rvalue(a)>num_rvalue(b);
3206 }
3207 return ret;
3208 }
3209
3210 static int num_ge(num a, num b) {
3211 return !num_lt(a,b);
3212 }
3213
3214 static int num_lt(num a, num b) {
3215 int ret;
3216 int is_fixnum=a.is_fixnum && b.is_fixnum;
3217 if(is_fixnum) {
3218 ret= a.value.ivalue<b.value.ivalue;
3219 } else {
3220 ret=num_rvalue(a)<num_rvalue(b);
3221 }
3222 return ret;
3223 }
3224
3225 static int num_le(num a, num b) {
3226 return !num_gt(a,b);
3227 }
3228
3229 #if USE_MATH
3230 /* Round to nearest. Round to even if midway */
3231 static double round_per_R5RS(double x) {
3232 double fl=floor(x);
3233 double ce=ceil(x);
3234 double dfl=x-fl;
3235 double dce=ce-x;
3236 if(dfl>dce) {
3237 return ce;
3238 } else if(dfl<dce) {
3239 return fl;
3240 } else {
3241 if(fmod(fl,2.0)==0.0) { /* I imagine this holds */
3242 return fl;
3243 } else {
3244 return ce;
3245 }
3246 }
3247 }
3248 #endif
3249
3250 static int is_zero_double(double x) {
3251 return x<DBL_MIN && x>-DBL_MIN;
3252 }
3253
3254 static long binary_decode(const char *s) {
3255 long x=0;
3256
3257 while(*s!=0 && (*s=='1' || *s=='0')) {
3258 x<<=1;
3259 x+=*s-'0';
3260 s++;
3261 }
3262
3263 return x;
3264 }
3265
3266 /* allocate new cell segment */
3267 static int alloc_cellseg(scheme *sc, int n) {
3268 pointer newp;
3269 pointer last;
3270 pointer p;
3271 char *cp;
3272 long i;
3273 int k;
3274 int adj=ADJ;
3275
3276 if(adj<sizeof(struct cell)) {
3277 adj=sizeof(struct cell);
3278 }
3279
3280 for (k = 0; k < n; k++) {
3281 if (sc->last_cell_seg >= CELL_NSEGMENT - 1)
3282 return k;
3283 cp = (char*) sc->malloc(CELL_SEGSIZE * sizeof(struct cell)+adj);
3284 if (cp == 0)
3285 return k;
3286 i = ++sc->last_cell_seg ;
3287 sc->alloc_seg[i] = cp;
3288 /* adjust in TYPE_BITS-bit boundary */
3289 if(((unsigned long)cp)%adj!=0) {
3290 cp=(char*)(adj*((unsigned long)cp/adj+1));
3291 }
3292 /* insert new segment in address order */
3293 newp=(pointer)cp;
3294 sc->cell_seg[i] = newp;
3295 while (i > 0 && sc->cell_seg[i - 1] > sc->cell_seg[i]) {
3296 p = sc->cell_seg[i];
3297 sc->cell_seg[i] = sc->cell_seg[i - 1];
3298 sc->cell_seg[--i] = p;
3299 }
3300 sc->fcells += CELL_SEGSIZE;
3301 last = newp + CELL_SEGSIZE - 1;
3302 for (p = newp; p <= last; p++) {
3303 typeflag(p) = 0;
3304 cdr(p) = p + 1;
3305 car(p) = sc->NIL;
3306 }
3307 /* insert new cells in address order on free list */
3308 if (sc->free_cell == sc->NIL || p < sc->free_cell) {
3309 cdr(last) = sc->free_cell;
3310 sc->free_cell = newp;
3311 } else {
3312 p = sc->free_cell;
3313 while (cdr(p) != sc->NIL && newp > cdr(p))
3314 p = cdr(p);
3315 cdr(last) = cdr(p);
3316 cdr(p) = newp;
3317 }
3318 }
3319 return n;
3320 }
3321
3322 static INLINE pointer get_cell_x(scheme *sc, pointer a, pointer b) {
3323 if (sc->free_cell != sc->NIL) {
3324 pointer x = sc->free_cell;
3325 sc->free_cell = cdr(x);
3326 --sc->fcells;
3327 return (x);
3328 }
3329 return _get_cell (sc, a, b);
3330 }
3331
3332
3333 /* get new cell. parameter a, b is marked by gc. */
3334 static pointer _get_cell(scheme *sc, pointer a, pointer b) {
3335 pointer x;
3336
3337 if(sc->no_memory) {
3338 return sc->sink;
3339 }
3340
3341 if (sc->free_cell == sc->NIL) {
3342 const int min_to_be_recovered = sc->last_cell_seg*8;
3343 gc(sc,a, b);
3344 if (sc->fcells < min_to_be_recovered
3345 || sc->free_cell == sc->NIL) {
3346 /* if only a few recovered, get more to avoid fruitless gc's */
3347 if (!alloc_cellseg(sc,1) && sc->free_cell == sc->NIL) {
3348 sc->no_memory=1;
3349 return sc->sink;
3350 }
3351 }
3352 }
3353 x = sc->free_cell;
3354 sc->free_cell = cdr(x);
3355 --sc->fcells;
3356 return (x);
3357 }
3358
3359 /* make sure that there is a given number of cells free */
3360 static pointer reserve_cells(scheme *sc, int n) {
3361 if(sc->no_memory) {
3362 return sc->NIL;
3363 }
3364
3365 /* Are there enough cells available? */
3366 if (sc->fcells < n) {
3367 /* If not, try gc'ing some */
3368 gc(sc, sc->NIL, sc->NIL);
3369 if (sc->fcells < n) {
3370 /* If there still aren't, try getting more heap */
3371 if (!alloc_cellseg(sc,1)) {
3372 sc->no_memory=1;
3373 return sc->NIL;
3374 }
3375 }
3376 if (sc->fcells < n) {
3377 /* If all fail, report failure */
3378 sc->no_memory=1;
3379 return sc->NIL;
3380 }
3381 }
3382 return (sc->T);
3383 }
3384
3385 static pointer get_consecutive_cells(scheme *sc, int n) {
3386 pointer x;
3387
3388 if(sc->no_memory) { return sc->sink; }
3389
3390 /* Are there any cells available? */
3391 x=find_consecutive_cells(sc,n);
3392 if (x != sc->NIL) { return x; }
3393
3394 /* If not, try gc'ing some */
3395 gc(sc, sc->NIL, sc->NIL);
3396 x=find_consecutive_cells(sc,n);
3397 if (x != sc->NIL) { return x; }
3398
3399 /* If there still aren't, try getting more heap */
3400 if (!alloc_cellseg(sc,1))
3401 {
3402 sc->no_memory=1;
3403 return sc->sink;
3404 }
3405
3406 x=find_consecutive_cells(sc,n);
3407 if (x != sc->NIL) { return x; }
3408
3409 /* If all fail, report failure */
3410 sc->no_memory=1;
3411 return sc->sink;
3412 }
3413
3414 static int count_consecutive_cells(pointer x, int needed) {
3415 int n=1;
3416 while(cdr(x)==x+1) {
3417 x=cdr(x);
3418 n++;
3419 if(n>needed) return n;
3420 }
3421 return n;
3422 }
3423
3424 static pointer find_consecutive_cells(scheme *sc, int n) {
3425 pointer *pp;
3426 int cnt;
3427
3428 pp=&sc->free_cell;
3429 while(*pp!=sc->NIL) {
3430 cnt=count_consecutive_cells(*pp,n);
3431 if(cnt>=n) {
3432 pointer x=*pp;
3433 *pp=cdr(*pp+n-1);
3434 sc->fcells -= n;
3435 return x;
3436 }
3437 pp=&cdr(*pp+cnt-1);
3438 }
3439 return sc->NIL;
3440 }
3441
3442 /* To retain recent allocs before interpreter knows about them -
3443 Tehom */
3444
3445 static void push_recent_alloc(scheme *sc, pointer recent, pointer extra)
3446 {
3447 pointer holder = get_cell_x(sc, recent, extra);
3448 typeflag(holder) = T_PAIR | T_IMMUTABLE;
3449 car(holder) = recent;
3450 cdr(holder) = car(sc->sink);
3451 car(sc->sink) = holder;
3452 }
3453
3454
3455 static pointer get_cell(scheme *sc, pointer a, pointer b)
3456 {
3457 pointer cell = get_cell_x(sc, a, b);
3458 /* For right now, include "a" and "b" in "cell" so that gc doesn't
3459 think they are garbage. */
3460 /* Tentatively record it as a pair so gc understands it. */
3461 typeflag(cell) = T_PAIR;
3462 car(cell) = a;
3463 cdr(cell) = b;
3464 push_recent_alloc(sc, cell, sc->NIL);
3465 return cell;
3466 }
3467
3468 static pointer get_vector_object(scheme *sc, int len, pointer init)
3469 {
3470 pointer cells = get_consecutive_cells(sc,len/2+len%2+1);
3471 if(sc->no_memory) { return sc->sink; }
3472 /* Record it as a vector so that gc understands it. */
3473 typeflag(cells) = (T_VECTOR | T_ATOM);
3474 ivalue_unchecked(cells)=len;
3475 set_num_integer(cells);
3476 fill_vector(cells,init);
3477 push_recent_alloc(sc, cells, sc->NIL);
3478 return cells;
3479 }
3480
3481 static INLINE void ok_to_freely_gc(scheme *sc)
3482 {
3483 car(sc->sink) = sc->NIL;
3484 }
3485
3486
3487 #if defined TSGRIND
3488 static void check_cell_alloced(pointer p, int expect_alloced)
3489 {
3490 /* Can't use putstr(sc,str) because callers have no access to
3491 sc. */
3492 if(typeflag(p) & !expect_alloced)
3493 {
3494 fprintf(stderr,"Cell is already allocated!\n");
3495 }
3496 if(!(typeflag(p)) & expect_alloced)
3497 {
3498 fprintf(stderr,"Cell is not allocated!\n");
3499 }
3500
3501 }
3502 static void check_range_alloced(pointer p, int n, int expect_alloced)
3503 {
3504 int i;
3505 for(i = 0;i<n;i++)
3506 { (void)check_cell_alloced(p+i,expect_alloced); }
3507 }
3508
3509 #endif
3510
3511 /* Medium level cell allocation */
3512
3513 /* get new cons cell */
3514 pointer _cons(scheme *sc, pointer a, pointer b, int immutable) {
3515 pointer x = get_cell(sc,a, b);
3516
3517 typeflag(x) = T_PAIR;
3518 if(immutable) {
3519 setimmutable(x);
3520 }
3521 car(x) = a;
3522 cdr(x) = b;
3523 return (x);
3524 }
3525
3526 /* ========== oblist implementation ========== */
3527
3528 #ifndef USE_OBJECT_LIST
3529
3530 static int hash_fn(const char *key, int table_size);
3531
3532 static pointer oblist_initial_value(scheme *sc)
3533 {
3534 return mk_vector(sc, 461); /* probably should be bigger */
3535 }
3536
3537 /* returns the new symbol */
3538 static pointer oblist_add_by_name(scheme *sc, const char *name)
3539 {
3540 pointer x;
3541 int location;
3542
3543 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
3544 typeflag(x) = T_SYMBOL;
3545 setimmutable(car(x));
3546
3547 location = hash_fn(name, ivalue_unchecked(sc->oblist));
3548 set_vector_elem(sc->oblist, location,
3549 immutable_cons(sc, x, vector_elem(sc->oblist, location)));
3550 return x;
3551 }
3552
3553 static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
3554 {
3555 int location;
3556 pointer x;
3557 char *s;
3558
3559 location = hash_fn(name, ivalue_unchecked(sc->oblist));
3560 for (x = vector_elem(sc->oblist, location); x != sc->NIL; x = cdr(x)) {
3561 s = symname(car(x));
3562 /* case-insensitive, per R5RS section 2. */
3563 if(stricmp(name, s) == 0) {
3564 return car(x);
3565 }
3566 }
3567 return sc->NIL;
3568 }
3569
3570 static pointer oblist_all_symbols(scheme *sc)
3571 {
3572 int i;
3573 pointer x;
3574 pointer ob_list = sc->NIL;
3575
3576 for (i = 0; i < ivalue_unchecked(sc->oblist); i++) {
3577 for (x = vector_elem(sc->oblist, i); x != sc->NIL; x = cdr(x)) {
3578 ob_list = cons(sc, x, ob_list);
3579 }
3580 }
3581 return ob_list;
3582 }
3583
3584 #else
3585
3586 static pointer oblist_initial_value(scheme *sc)
3587 {
3588 return sc->NIL;
3589 }
3590
3591 static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
3592 {
3593 pointer x;
3594 char *s;
3595
3596 for (x = sc->oblist; x != sc->NIL; x = cdr(x)) {
3597 s = symname(car(x));
3598 /* case-insensitive, per R5RS section 2. */
3599 if(stricmp(name, s) == 0) {
3600 return car(x);
3601 }
3602 }
3603 return sc->NIL;
3604 }
3605
3606 /* returns the new symbol */
3607 static pointer oblist_add_by_name(scheme *sc, const char *name)
3608 {
3609 pointer x;
3610
3611 x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
3612 typeflag(x) = T_SYMBOL;
3613 setimmutable(car(x));
3614 sc->oblist = immutable_cons(sc, x, sc->oblist);
3615 return x;
3616 }
3617 static pointer oblist_all_symbols(scheme *sc)
3618 {
3619 return sc->oblist;
3620 }
3621
3622 #endif
3623
3624 static pointer mk_port(scheme *sc, port *p) {
3625 pointer x = get_cell(sc, sc->NIL, sc->NIL);
3626
3627 typeflag(x) = T_PORT|T_ATOM;
3628 x->_object._port=p;
3629 return (x);
3630 }
3631
3632 pointer mk_foreign_func(scheme *sc, foreign_func f) {
3633 pointer x = get_cell(sc, sc->NIL, sc->NIL);
3634
3635 typeflag(x) = (T_FOREIGN | T_ATOM);
3636 x->_object._ff=f;
3637 return (x);
3638 }
3639
3640 INTERFACE pointer mk_character(scheme *sc, int c) {
3641 pointer x = get_cell(sc,sc->NIL, sc->NIL);
3642
3643 typeflag(x) = (T_CHARACTER | T_ATOM);
3644 ivalue_unchecked(x)= c;
3645 set_num_integer(x);
3646 return (x);
3647 }
3648
3649 /* get number atom (integer) */
3650 INTERFACE pointer mk_integer(scheme *sc, long num) {
3651 pointer x = get_cell(sc,sc->NIL, sc->NIL);
3652
3653 typeflag(x) = (T_NUMBER | T_ATOM);
3654 ivalue_unchecked(x)= num;
3655 set_num_integer(x);
3656 return (x);
3657 }
3658
3659 INTERFACE pointer mk_real(scheme *sc, double n) {
3660 pointer x = get_cell(sc,sc->NIL, sc->NIL);
3661
3662 typeflag(x) = (T_NUMBER | T_ATOM);
3663 rvalue_unchecked(x)= n;
3664 set_num_real(x);
3665 return (x);
3666 }
3667
3668 static pointer mk_number(scheme *sc, num n) {
3669 if(n.is_fixnum) {
3670 return mk_integer(sc,n.value.ivalue);
3671 } else {
3672 return mk_real(sc,n.value.rvalue);
3673 }
3674 }
3675
3676 /* allocate name to string area */
3677 static char *store_string(scheme *sc, int len_str, const char *str, char fill) {
3678 char *q;
3679
3680 q=(char*)sc->malloc(len_str+1);
3681 if(q==0) {
3682 sc->no_memory=1;
3683 return sc->strbuff;
3684 }
3685 if(str!=0) {
3686 snprintf(q, len_str+1, "%s", str);
3687 } else {
3688 memset(q, fill, len_str);
3689 q[len_str]=0;
3690 }
3691 return (q);
3692 }
3693
3694 /* get new string */
3695 INTERFACE pointer mk_string(scheme *sc, const char *str) {
3696 return mk_counted_string(sc,str,strlen(str));
3697 }
3698
3699 INTERFACE pointer mk_counted_string(scheme *sc, const char *str, int len) {
3700 pointer x = get_cell(sc, sc->NIL, sc->NIL);
3701 typeflag(x) = (T_STRING | T_ATOM);
3702 strvalue(x) = store_string(sc,len,str,0);
3703 strlength(x) = len;
3704 return (x);
3705 }
3706
3707 INTERFACE pointer mk_empty_string(scheme *sc, int len, char fill) {
3708 pointer x = get_cell(sc, sc->NIL, sc->NIL);
3709 typeflag(x) = (T_STRING | T_ATOM);
3710 strvalue(x) = store_string(sc,len,0,fill);
3711 strlength(x) = len;
3712 return (x);
3713 }
3714
3715 INTERFACE static pointer mk_vector(scheme *sc, int len)
3716 { return get_vector_object(sc,len,sc->NIL); }
3717
3718 INTERFACE static void fill_vector(pointer vec, pointer obj) {
3719 int i;
3720 int num=ivalue(vec)/2+ivalue(vec)%2;
3721 for(i=0; i<num; i++) {
3722 typeflag(vec+1+i) = T_PAIR;
3723 setimmutable(vec+1+i);
3724 car(vec+1+i)=obj;
3725 cdr(vec+1+i)=obj;
3726 }
3727 }
3728
3729 INTERFACE static pointer vector_elem(pointer vec, int ielem) {
3730 int n=ielem/2;
3731 if(ielem%2==0) {
3732 return car(vec+1+n);
3733 } else {
3734 return cdr(vec+1+n);
3735 }
3736 }
3737
3738 INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a) {
3739 int n=ielem/2;
3740 if(ielem%2==0) {
3741 return car(vec+1+n)=a;
3742 } else {
3743 return cdr(vec+1+n)=a;
3744 }
3745 }
3746
3747 /* get new symbol */
3748 INTERFACE pointer mk_symbol(scheme *sc, const char *name) {
3749 pointer x;
3750
3751 /* first check oblist */
3752 x = oblist_find_by_name(sc, name);
3753 if (x != sc->NIL) {
3754 return (x);
3755 } else {
3756 x = oblist_add_by_name(sc, name);
3757 return (x);
3758 }
3759 }
3760
3761 INTERFACE pointer gensym(scheme *sc) {
3762 pointer x;
3763 char name[40];
3764
3765 for(; sc->gensym_cnt<LONG_MAX; sc->gensym_cnt++) {
3766 snprintf(name,40,"gensym-%ld",sc->gensym_cnt);
3767
3768 /* first check oblist */
3769 x = oblist_find_by_name(sc, name);
3770
3771 if (x != sc->NIL) {
3772 continue;
3773 } else {
3774 x = oblist_add_by_name(sc, name);
3775 return (x);
3776 }
3777 }
3778
3779 return sc->NIL;
3780 }
3781
3782 /* make symbol or number atom from string */
3783 static pointer mk_atom(scheme *sc, char *q) {
3784 char c, *p;
3785 int has_dec_point=0;
3786 int has_fp_exp = 0;
3787
3788 #if USE_COLON_HOOK
3789 if((p=strstr(q,"::"))!=0) {
3790 *p=0;
3791 return cons(sc, sc->COLON_HOOK,
3792 cons(sc,
3793 cons(sc,
3794 sc->QUOTE,
3795 cons(sc, mk_atom(sc,p+2), sc->NIL)),
3796 cons(sc, mk_symbol(sc,strlwr(q)), sc->NIL)));
3797 }
3798 #endif
3799
3800 p = q;
3801 c = *p++;
3802 if ((c == '+') || (c == '-')) {
3803 c = *p++;
3804 if (c == '.') {
3805 has_dec_point=1;
3806 c = *p++;
3807 }
3808 if (!isdigit(c)) {
3809 return (mk_symbol(sc, strlwr(q)));
3810 }
3811 } else if (c == '.') {
3812 has_dec_point=1;
3813 c = *p++;
3814 if (!isdigit(c)) {
3815 return (mk_symbol(sc, strlwr(q)));
3816 }
3817 } else if (!isdigit(c)) {
3818 return (mk_symbol(sc, strlwr(q)));
3819 }
3820
3821 for ( ; (c = *p) != 0; ++p) {
3822 if (!isdigit(c)) {
3823 if(c=='.') {
3824 if(!has_dec_point) {
3825 has_dec_point=1;
3826 continue;
3827 }
3828 }
3829 else if ((c == 'e') || (c == 'E')) {
3830 if(!has_fp_exp) {
3831 has_dec_point = 1; /* decimal point illegal
3832 from now on */
3833 p++;
3834 if ((*p == '-') || (*p == '+') || isdigit(*p)) {
3835 continue;
3836 }
3837 }
3838 }
3839 return (mk_symbol(sc, strlwr(q)));
3840 }
3841 }
3842 if(has_dec_point) {
3843 return mk_real(sc,atof(q));
3844 }
3845 return (mk_integer(sc, atol(q)));
3846 }
3847
3848 /* make constant */
3849 static pointer mk_sharp_const(scheme *sc, char *name) {
3850 long x;
3851 char tmp[STRBUFFSIZE];
3852
3853 if (!strcmp(name, "t"))
3854 return (sc->T);
3855 else if (!strcmp(name, "f"))
3856 return (sc->F);
3857 else if (*name == 'o') {/* #o (octal) */
3858 snprintf(tmp, STRBUFFSIZE, "0%s", name+1);
3859 sscanf(tmp, "%lo", (long unsigned *)&x);
3860 return (mk_integer(sc, x));
3861 } else if (*name == 'd') { /* #d (decimal) */
3862 sscanf(name+1, "%ld", (long int *)&x);
3863 return (mk_integer(sc, x));
3864 } else if (*name == 'x') { /* #x (hex) */
3865 snprintf(tmp, STRBUFFSIZE, "0x%s", name+1);
3866 sscanf(tmp, "%lx", (long unsigned *)&x);
3867 return (mk_integer(sc, x));
3868 } else if (*name == 'b') { /* #b (binary) */
3869 x = binary_decode(name+1);
3870 return (mk_integer(sc, x));
3871 } else if (*name == '\\') { /* #\w (character) */
3872 int c=0;
3873 if(stricmp(name+1,"space")==0) {
3874 c=' ';
3875 } else if(stricmp(name+1,"newline")==0) {
3876 c='\n';
3877 } else if(stricmp(name+1,"return")==0) {
3878 c='\r';
3879 } else if(stricmp(name+1,"tab")==0) {
3880 c='\t';
3881 } else if(name[1]=='x' && name[2]!=0) {
3882 int c1=0;
3883 if(sscanf(name+2,"%x",(unsigned int *)&c1)==1 && c1 < UCHAR_MAX) {
3884 c=c1;
3885 } else {
3886 return sc->NIL;
3887 }
3888 #if USE_ASCII_NAMES
3889 } else if(is_ascii_name(name+1,&c)) {
3890 /* nothing */
3891 #endif
3892 } else if(name[2]==0) {
3893 c=name[1];
3894 } else {
3895 return sc->NIL;
3896 }
3897 return mk_character(sc,c);
3898 } else
3899 return (sc->NIL);
3900 }
3901
3902 /* ========== garbage collector ========== */
3903
3904 /*--
3905 * We use algorithm E (Knuth, The Art of Computer Programming Vol.1,
3906 * sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm,
3907 * for marking.
3908 */
3909 static void mark(pointer a) {
3910 pointer t, q, p;
3911
3912 t = (pointer) 0;
3913 p = a;
3914 E2: setmark(p);
3915 if(is_vector(p)) {
3916 int i;
3917 int num=ivalue_unchecked(p)/2+ivalue_unchecked(p)%2;
3918 for(i=0; i<num; i++) {
3919 /* Vector cells will be treated like ordinary cells */
3920 mark(p+1+i);
3921 }
3922 }
3923 if (is_atom(p))
3924 goto E6;
3925 /* E4: down car */
3926 q = car(p);
3927 if (q && !is_mark(q)) {
3928 setatom(p); /* a note that we have moved car */
3929 car(p) = t;
3930 t = p;
3931 p = q;
3932 goto E2;
3933 }
3934 E5: q = cdr(p); /* down cdr */
3935 if (q && !is_mark(q)) {
3936 cdr(p) = t;
3937 t = p;
3938 p = q;
3939 goto E2;
3940 }
3941 E6: /* up. Undo the link switching from steps E4 and E5. */
3942 if (!t)
3943 return;
3944 q = t;
3945 if (is_atom(q)) {
3946 clratom(q);
3947 t = car(q);
3948 car(q) = p;
3949 p = q;
3950 goto E5;
3951 } else {
3952 t = cdr(q);
3953 cdr(q) = p;
3954 p = q;
3955 goto E6;
3956 }
3957 }
3958
3959 /* garbage collection. parameter a, b is marked. */
3960 static void gc(scheme *sc, pointer a, pointer b) {
3961 pointer p;
3962 int i;
3963
3964 if(sc->gc_verbose) {
3965 putstr(sc, "gc...");
3966 }
3967
3968 /* mark system globals */
3969 mark(sc->oblist);
3970 mark(sc->global_env);
3971
3972 /* mark current registers */
3973 mark(sc->args);
3974 mark(sc->envir);
3975 mark(sc->code);
3976 dump_stack_mark(sc);
3977 mark(sc->value);
3978 mark(sc->inport);
3979 mark(sc->save_inport);
3980 mark(sc->outport);
3981 mark(sc->loadport);
3982
3983 /* Mark recent objects the interpreter doesn't know about yet. */
3984 mark(car(sc->sink));
3985 /* Mark any older stuff above nested C calls */
3986 mark(sc->c_nest);
3987
3988 /* mark variables a, b */
3989 mark(a);
3990 mark(b);
3991
3992 /* garbage collect */
3993 clrmark(sc->NIL);
3994 sc->fcells = 0;
3995 sc->free_cell = sc->NIL;
3996 /* free-list is kept sorted by address so as to maintain consecutive
3997 ranges, if possible, for use with vectors. Here we scan the cells
3998 (which are also kept sorted by address) downwards to build the
3999 free-list in sorted order.
4000 */
4001 for (i = sc->last_cell_seg; i >= 0; i--) {
4002 p = sc->cell_seg[i] + CELL_SEGSIZE;
4003 while (--p >= sc->cell_seg[i]) {
4004 if (is_mark(p)) {
4005 clrmark(p);
4006 } else {
4007 /* reclaim cell */
4008 if (typeflag(p) != 0) {
4009 finalize_cell(sc, p);
4010 typeflag(p) = 0;
4011 car(p) = sc->NIL;
4012 }
4013 ++sc->fcells;
4014 cdr(p) = sc->free_cell;
4015 sc->free_cell = p;
4016 }
4017 }
4018 }
4019
4020 if (sc->gc_verbose) {
4021 char msg[80];
4022 snprintf(msg,80,"done: %ld cells were recovered.\n", sc->fcells);
4023 putstr(sc,msg);
4024 }
4025 }
4026
4027 static void finalize_cell(scheme *sc, pointer a) {
4028 if(is_string(a)) {
4029 sc->free(strvalue(a));
4030 } else if(is_port(a)) {
4031 if(a->_object._port->kind&port_file
4032 && a->_object._port->rep.stdio.closeit) {
4033 port_close(sc,a,port_input|port_output);
4034 }
4035 sc->free(a->_object._port);
4036 }
4037 }
4038
4039 /* ========== Routines for Reading ========== */
4040
4041 static int file_push(scheme *sc, const char *fname) {
4042 FILE *fin = NULL;
4043
4044 if (sc->file_i == MAXFIL-1)
4045 return 0;
4046 fin=fopen(fname,"r");
4047 if(fin!=0) {
4048 sc->file_i++;
4049 sc->load_stack[sc->file_i].kind=port_file|port_input;
4050 sc->load_stack[sc->file_i].rep.stdio.file=fin;
4051 sc->load_stack[sc->file_i].rep.stdio.closeit=1;
4052 sc->nesting_stack[sc->file_i]=0;
4053 sc->loadport->_object._port=sc->load_stack+sc->file_i;
4054
4055 #if SHOW_ERROR_LINE
4056 sc->load_stack[sc->file_i].rep.stdio.curr_line = 0;
4057 if(fname)
4058 sc->load_stack[sc->file_i].rep.stdio.filename = store_string(sc, strlen(fname), fname, 0);
4059 #endif
4060 }
4061 return fin!=0;
4062 }
4063
4064 static void file_pop(scheme *sc) {
4065 if(sc->file_i != 0) {
4066 sc->nesting=sc->nesting_stack[sc->file_i];
4067 port_close(sc,sc->loadport,port_input);
4068 sc->file_i--;
4069 sc->loadport->_object._port=sc->load_stack+sc->file_i;
4070 }
4071 }
4072
4073 static int file_interactive(scheme *sc) {
4074 return sc->file_i==0 && sc->load_stack[0].rep.stdio.file==stdin
4075 && sc->inport->_object._port->kind&port_file;
4076 }
4077
4078 static port *port_rep_from_filename(scheme *sc, const char *fn, int prop) {
4079 FILE *f;
4080 char *rw;
4081 port *pt;
4082 if(prop==(port_input|port_output)) {
4083 rw="a+";
4084 } else if(prop==port_output) {
4085 rw="w";
4086 } else {
4087 rw="r";
4088 }
4089 f=fopen(fn,rw);
4090 if(f==0) {
4091 return 0;
4092 }
4093 pt=port_rep_from_file(sc,f,prop);
4094 pt->rep.stdio.closeit=1;
4095
4096 #if SHOW_ERROR_LINE
4097 if(fn)
4098 pt->rep.stdio.filename = store_string(sc, strlen(fn), fn, 0);
4099
4100 pt->rep.stdio.curr_line = 0;
4101 #endif
4102 return pt;
4103 }
4104
4105 static pointer port_from_filename(scheme *sc, const char *fn, int prop) {
4106 port *pt;
4107 pt=port_rep_from_filename(sc,fn,prop);
4108 if(pt==0) {
4109 return sc->NIL;
4110 }
4111 return mk_port(sc,pt);
4112 }
4113
4114 static port *port_rep_from_file(scheme *sc, FILE *f, int prop)
4115 {
4116 port *pt;
4117
4118 pt = (port *)sc->malloc(sizeof *pt);
4119 if (pt == NULL) {
4120 return NULL;
4121 }
4122 pt->kind = port_file | prop;
4123 pt->rep.stdio.file = f;
4124 pt->rep.stdio.closeit = 0;
4125 return pt;
4126 }
4127
4128 static pointer port_from_file(scheme *sc, FILE *f, int prop) {
4129 port *pt;
4130 pt=port_rep_from_file(sc,f,prop);
4131 if(pt==0) {
4132 return sc->NIL;
4133 }
4134 return mk_port(sc,pt);
4135 }
4136
4137 static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
4138 port *pt;
4139 pt=(port*)sc->malloc(sizeof(port));
4140 if(pt==0) {
4141 return 0;
4142 }
4143 pt->kind=port_string|prop;
4144 pt->rep.string.start=start;
4145 pt->rep.string.curr=start;
4146 pt->rep.string.past_the_end=past_the_end;
4147 return pt;
4148 }
4149
4150 static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
4151 port *pt;
4152 pt=port_rep_from_string(sc,start,past_the_end,prop);
4153 if(pt==0) {
4154 return sc->NIL;
4155 }
4156 return mk_port(sc,pt);
4157 }
4158
4159 #define BLOCK_SIZE 256
4160
4161 static port *port_rep_from_scratch(scheme *sc) {
4162 port *pt;
4163 char *start;
4164 pt=(port*)sc->malloc(sizeof(port));
4165 if(pt==0) {
4166 return 0;
4167 }
4168 start=sc->malloc(BLOCK_SIZE);
4169 if(start==0) {
4170 return 0;
4171 }
4172 memset(start,' ',BLOCK_SIZE-1);
4173 start[BLOCK_SIZE-1]='\0';
4174 pt->kind=port_string|port_output|port_srfi6;
4175 pt->rep.string.start=start;
4176 pt->rep.string.curr=start;
4177 pt->rep.string.past_the_end=start+BLOCK_SIZE-1;
4178 return pt;
4179 }
4180
4181 static pointer port_from_scratch(scheme *sc) {
4182 port *pt;
4183 pt=port_rep_from_scratch(sc);
4184 if(pt==0) {
4185 return sc->NIL;
4186 }
4187 return mk_port(sc,pt);
4188 }
4189
4190 static void port_close(scheme *sc, pointer p, int flag) {
4191 port *pt=p->_object._port;
4192 pt->kind&=~flag;
4193 if((pt->kind & (port_input|port_output))==0) {
4194 if(pt->kind&port_file) {
4195
4196 #if SHOW_ERROR_LINE
4197 /* Cleanup is here so (close-*-port) functions could work too */
4198 pt->rep.stdio.curr_line = 0;
4199
4200 if(pt->rep.stdio.filename)
4201 sc->free(pt->rep.stdio.filename);
4202 #endif
4203
4204 fclose(pt->rep.stdio.file);
4205 }
4206 pt->kind=port_free;
4207 }
4208 }
4209
4210 /* get new character from input file */
4211 static int inchar(scheme *sc) {
4212 int c;
4213 port *pt;
4214
4215 pt = sc->inport->_object._port;
4216 if(pt->kind & port_saw_EOF)
4217 { return EOF; }
4218 c = basic_inchar(pt);
4219 if(c == EOF && sc->inport == sc->loadport) {
4220 /* Instead, set port_saw_EOF */
4221 pt->kind |= port_saw_EOF;
4222
4223 /* file_pop(sc); */
4224 return EOF;
4225 /* NOTREACHED */
4226 }
4227 return c;
4228 }
4229
4230 static int basic_inchar(port *pt) {
4231 if(pt->kind & port_file) {
4232 return fgetc(pt->rep.stdio.file);
4233 } else {
4234 if(*pt->rep.string.curr == 0 ||
4235 pt->rep.string.curr == pt->rep.string.past_the_end) {
4236 return EOF;
4237 } else {
4238 return *pt->rep.string.curr++;
4239 }
4240 }
4241 }
4242
4243 /* back character to input buffer */
4244 static void backchar(scheme *sc, int c) {
4245 port *pt;
4246 if(c==EOF) return;
4247 pt=sc->inport->_object._port;
4248 if(pt->kind&port_file) {
4249 ungetc(c,pt->rep.stdio.file);
4250 } else {
4251 if(pt->rep.string.curr!=pt->rep.string.start) {
4252 --pt->rep.string.curr;
4253 }
4254 }
4255 }
4256
4257 static int realloc_port_string(scheme *sc, port *p)
4258 {
4259 char *start=p->rep.string.start;
4260 size_t new_size=p->rep.string.past_the_end-start+1+BLOCK_SIZE;
4261 char *str=sc->malloc(new_size);
4262 if(str) {
4263 memset(str,' ',new_size-1);
4264 str[new_size-1]='\0';
4265 strcpy(str,start);
4266 p->rep.string.start=str;
4267 p->rep.string.past_the_end=str+new_size-1;
4268 p->rep.string.curr-=start-str;
4269 sc->free(start);
4270 return 1;
4271 } else {
4272 return 0;
4273 }
4274 }
4275
4276 INTERFACE void putstr(scheme *sc, const char *s) {
4277 port *pt=sc->outport->_object._port;
4278 if(pt->kind&port_file) {
4279 fputs(s,pt->rep.stdio.file);
4280 } else {
4281 for(;*s;s++) {
4282 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
4283 *pt->rep.string.curr++=*s;
4284 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
4285 *pt->rep.string.curr++=*s;
4286 }
4287 }
4288 }
4289 }
4290
4291 static void putchars(scheme *sc, const char *s, int len) {
4292 port *pt=sc->outport->_object._port;
4293 if(pt->kind&port_file) {
4294 fwrite(s,1,len,pt->rep.stdio.file);
4295 } else {
4296 for(;len;len--) {
4297 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
4298 *pt->rep.string.curr++=*s++;
4299 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
4300 *pt->rep.string.curr++=*s++;
4301 }
4302 }
4303 }
4304 }
4305
4306 INTERFACE void putcharacter(scheme *sc, int c) {
4307 port *pt=sc->outport->_object._port;
4308 if(pt->kind&port_file) {
4309 fputc(c,pt->rep.stdio.file);
4310 } else {
4311 if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
4312 *pt->rep.string.curr++=c;
4313 } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
4314 *pt->rep.string.curr++=c;
4315 }
4316 }
4317 }
4318
4319 /* read characters up to delimiter, but cater to character constants */
4320 static char *readstr_upto(scheme *sc, char *delim) {
4321 char *p = sc->strbuff;
4322
4323 while ((p - sc->strbuff < sizeof(sc->strbuff)) &&
4324 !is_one_of(delim, (*p++ = inchar(sc))));
4325
4326 if(p == sc->strbuff+2 && p[-2] == '\\') {
4327 *p=0;
4328 } else {
4329 backchar(sc,p[-1]);
4330 *--p = '\0';
4331 }
4332 return sc->strbuff;
4333 }
4334
4335 /* read string expression "xxx...xxx" */
4336 static pointer readstrexp(scheme *sc) {
4337 char *p = sc->strbuff;
4338 int c;
4339 int c1=0;
4340 enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state=st_ok;
4341
4342 for (;;) {
4343 c=inchar(sc);
4344 if(c == EOF || p-sc->strbuff > sizeof(sc->strbuff)-1) {
4345 return sc->F;
4346 }
4347 switch(state) {
4348 case st_ok:
4349 switch(c) {
4350 case '\\':
4351 state=st_bsl;
4352 break;
4353 case '"':
4354 *p=0;
4355 return mk_counted_string(sc,sc->strbuff,p-sc->strbuff);
4356 default:
4357 *p++=c;
4358 break;
4359 }
4360 break;
4361 case st_bsl:
4362 switch(c) {
4363 case '0':
4364 case '1':
4365 case '2':
4366 case '3':
4367 case '4':
4368 case '5':
4369 case '6':
4370 case '7':
4371 state=st_oct1;
4372 c1=c-'0';
4373 break;
4374 case 'x':
4375 case 'X':
4376 state=st_x1;
4377 c1=0;
4378 break;
4379 case 'n':
4380 *p++='\n';
4381 state=st_ok;
4382 break;
4383 case 't':
4384 *p++='\t';
4385 state=st_ok;
4386 break;
4387 case 'r':
4388 *p++='\r';
4389 state=st_ok;
4390 break;
4391 case '"':
4392 *p++='"';
4393 state=st_ok;
4394 break;
4395 default:
4396 *p++=c;
4397 state=st_ok;
4398 break;
4399 }
4400 break;
4401 case st_x1:
4402 case st_x2:
4403 c=toupper(c);
4404 if(c>='0' && c<='F') {
4405 if(c<='9') {
4406 c1=(c1<<4)+c-'0';
4407 } else {
4408 c1=(c1<<4)+c-'A'+10;
4409 }
4410 if(state==st_x1) {
4411 state=st_x2;
4412 } else {
4413 *p++=c1;
4414 state=st_ok;
4415 }
4416 } else {
4417 return sc->F;
4418 }
4419 break;
4420 case st_oct1:
4421 case st_oct2:
4422 if (c < '0' || c > '7')
4423 {
4424 *p++=c1;
4425 backchar(sc, c);
4426 state=st_ok;
4427 }
4428 else
4429 {
4430 if (state==st_oct2 && c1 >= 32)
4431 return sc->F;
4432
4433 c1=(c1<<3)+(c-'0');
4434
4435 if (state == st_oct1)
4436 state=st_oct2;
4437 else
4438 {
4439 *p++=c1;
4440 state=st_ok;
4441 }
4442 }
4443 break;
4444
4445 }
4446 }
4447 }
4448
4449 /* check c is in chars */
4450 static INLINE int is_one_of(char *s, int c) {
4451 if(c==EOF) return 1;
4452 while (*s)
4453 if (*s++ == c)
4454 return (1);
4455 return (0);
4456 }
4457
4458 /* skip white characters */
4459 static INLINE int skipspace(scheme *sc) {
4460 int c = 0, curr_line = 0;
4461
4462 do {
4463 c=inchar(sc);
4464 #if SHOW_ERROR_LINE
4465 if(c=='\n')
4466 curr_line++;
4467 #endif
4468 } while (isspace(c));
4469
4470 /* record it */
4471 #if SHOW_ERROR_LINE
4472 if (sc->load_stack[sc->file_i].kind & port_file)
4473 sc->load_stack[sc->file_i].rep.stdio.curr_line += curr_line;
4474 #endif
4475
4476 if(c!=EOF) {
4477 backchar(sc,c);
4478 return 1;
4479 }
4480 else
4481 { return EOF; }
4482 }
4483
4484 /* get token */
4485 static int token(scheme *sc) {
4486 int c;
4487 c = skipspace(sc);
4488 if(c == EOF) { return (TOK_EOF); }
4489 switch (c=inchar(sc)) {
4490 case EOF:
4491 return (TOK_EOF);
4492 case '(':
4493 return (TOK_LPAREN);
4494 case ')':
4495 return (TOK_RPAREN);
4496 case '.':
4497 c=inchar(sc);
4498 if(is_one_of(" \n\t",c)) {
4499 return (TOK_DOT);
4500 } else {
4501 backchar(sc,c);
4502 backchar(sc,'.');
4503 return TOK_ATOM;
4504 }
4505 case '\'':
4506 return (TOK_QUOTE);
4507 case ';':
4508 while ((c=inchar(sc)) != '\n' && c!=EOF)
4509 ;
4510
4511 #if SHOW_ERROR_LINE
4512 if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
4513 sc->load_stack[sc->file_i].rep.stdio.curr_line++;
4514 #endif
4515
4516 if(c == EOF)
4517 { return (TOK_EOF); }
4518 else
4519 { return (token(sc));}
4520 case '"':
4521 return (TOK_DQUOTE);
4522 case BACKQUOTE:
4523 return (TOK_BQUOTE);
4524 case ',':
4525 if ((c=inchar(sc)) == '@') {
4526 return (TOK_ATMARK);
4527 } else {
4528 backchar(sc,c);
4529 return (TOK_COMMA);
4530 }
4531 case '#':
4532 c=inchar(sc);
4533 if (c == '(') {
4534 return (TOK_VEC);
4535 } else if(c == '!') {
4536 while ((c=inchar(sc)) != '\n' && c!=EOF)
4537 ;
4538
4539 #if SHOW_ERROR_LINE
4540 if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
4541 sc->load_stack[sc->file_i].rep.stdio.curr_line++;
4542 #endif
4543
4544 if(c == EOF)
4545 { return (TOK_EOF); }
4546 else
4547 { return (token(sc));}
4548 } else {
4549 backchar(sc,c);
4550 if(is_one_of(" tfodxb\\",c)) {
4551 return TOK_SHARP_CONST;
4552 } else {
4553 return (TOK_SHARP);
4554 }
4555 }
4556 default:
4557 backchar(sc,c);
4558 return (TOK_ATOM);
4559 }
4560 }
4561
4562 /* ========== Routines for Printing ========== */
4563 #define ok_abbrev(x) (is_pair(x) && cdr(x) == sc->NIL)
4564
4565 static void printslashstring(scheme *sc, char *p, int len) {
4566 int i;
4567 unsigned char *s=(unsigned char*)p;
4568 putcharacter(sc,'"');
4569 for ( i=0; i<len; i++) {
4570 if(*s==0xff || *s=='"' || *s<' ' || *s=='\\') {
4571 putcharacter(sc,'\\');
4572 switch(*s) {
4573 case '"':
4574 putcharacter(sc,'"');
4575 break;
4576 case '\n':
4577 putcharacter(sc,'n');
4578 break;
4579 case '\t':
4580 putcharacter(sc,'t');
4581 break;
4582 case '\r':
4583 putcharacter(sc,'r');
4584 break;
4585 case '\\':
4586 putcharacter(sc,'\\');
4587 break;
4588 default: {
4589 int d=*s/16;
4590 putcharacter(sc,'x');
4591 if(d<10) {
4592 putcharacter(sc,d+'0');
4593 } else {
4594 putcharacter(sc,d-10+'A');
4595 }
4596 d=*s%16;
4597 if(d<10) {
4598 putcharacter(sc,d+'0');
4599 } else {
4600 putcharacter(sc,d-10+'A');
4601 }
4602 }
4603 }
4604 } else {
4605 putcharacter(sc,*s);
4606 }
4607 s++;
4608 }
4609 putcharacter(sc,'"');
4610 }
4611
4612
4613 /* print atoms */
4614 static void printatom(scheme *sc, pointer l, int f) {
4615 char *p;
4616 int len;
4617 atom2str(sc,l,f,&p,&len);
4618 putchars(sc,p,len);
4619 }
4620
4621
4622 /* Uses internal buffer unless string pointer is already available */
4623 static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen) {
4624 char *p;
4625
4626 if (l == sc->NIL) {
4627 p = "()";
4628 } else if (l == sc->T) {
4629 p = "#t";
4630 } else if (l == sc->F) {
4631 p = "#f";
4632 } else if (l == sc->EOF_OBJ) {
4633 p = "#<EOF>";
4634 } else if (is_port(l)) {
4635 p = sc->strbuff;
4636 snprintf(p, STRBUFFSIZE, "#<PORT>");
4637 } else if (is_number(l)) {
4638 p = sc->strbuff;
4639 if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */ {
4640 if(num_is_integer(l)) {
4641 snprintf(p, STRBUFFSIZE, "%ld", ivalue_unchecked(l));
4642 } else {
4643 snprintf(p, STRBUFFSIZE, "%.10g", rvalue_unchecked(l));
4644 /* r5rs says there must be a '.' (unless 'e'?) */
4645 f = strcspn(p, ".e");
4646 if (p[f] == 0) {
4647 p[f] = '.'; /* not found, so add '.0' at the end */
4648 p[f+1] = '0';
4649 p[f+2] = 0;
4650 }
4651 }
4652 } else {
4653 long v = ivalue(l);
4654 if (f == 16) {
4655 if (v >= 0)
4656 snprintf(p, STRBUFFSIZE, "%lx", v);
4657 else
4658 snprintf(p, STRBUFFSIZE, "-%lx", -v);
4659 } else if (f == 8) {
4660 if (v >= 0)
4661 snprintf(p, STRBUFFSIZE, "%lo", v);
4662 else
4663 snprintf(p, STRBUFFSIZE, "-%lo", -v);
4664 } else if (f == 2) {
4665 unsigned long b = (v < 0) ? -v : v;
4666 p = &p[STRBUFFSIZE-1];
4667 *p = 0;
4668 do { *--p = (b&1) ? '1' : '0'; b >>= 1; } while (b != 0);
4669 if (v < 0) *--p = '-';
4670 }
4671 }
4672 } else if (is_string(l)) {
4673 if (!f) {
4674 p = strvalue(l);
4675 } else { /* Hack, uses the fact that printing is needed */
4676 *pp=sc->strbuff;
4677 *plen=0;
4678 printslashstring(sc, strvalue(l), strlength(l));
4679 return;
4680 }
4681 } else if (is_character(l)) {
4682 int c=charvalue(l);
4683 p = sc->strbuff;
4684 if (!f) {
4685 p[0]=c;
4686 p[1]=0;
4687 } else {
4688 switch(c) {
4689 case ' ':
4690 snprintf(p,STRBUFFSIZE,"#\\space"); break;
4691 case '\n':
4692 snprintf(p,STRBUFFSIZE,"#\\newline"); break;
4693 case '\r':
4694 snprintf(p,STRBUFFSIZE,"#\\return"); break;
4695 case '\t':
4696 snprintf(p,STRBUFFSIZE,"#\\tab"); break;
4697 default:
4698 #if USE_ASCII_NAMES
4699 if(c==127) {
4700 snprintf(p,STRBUFFSIZE, "#\\del");
4701 break;
4702 } else if(c<32) {
4703 snprintf(p, STRBUFFSIZE, "#\\%s", charnames[c]);
4704 break;
4705 }
4706 #else
4707 if(c<32) {
4708 snprintf(p,STRBUFFSIZE,"#\\x%x",c); break;
4709 break;
4710 }
4711 #endif
4712 snprintf(p,STRBUFFSIZE,"#\\%c",c); break;
4713 break;
4714 }
4715 }
4716 } else if (is_symbol(l)) {
4717 p = symname(l);
4718 } else if (is_proc(l)) {
4719 p = sc->strbuff;
4720 snprintf(p,STRBUFFSIZE,"#<%s PROCEDURE %ld>", procname(l),procnum(l));
4721 } else if (is_macro(l)) {
4722 p = "#<MACRO>";
4723 } else if (is_closure(l)) {
4724 p = "#<CLOSURE>";
4725 } else if (is_promise(l)) {
4726 p = "#<PROMISE>";
4727 } else if (is_foreign(l)) {
4728 p = sc->strbuff;
4729 snprintf(p,STRBUFFSIZE,"#<FOREIGN PROCEDURE %ld>", procnum(l));
4730 } else if (is_continuation(l)) {
4731 p = "#<CONTINUATION>";
4732 } else {
4733 p = "#<ERROR>";
4734 }
4735 *pp=p;
4736 *plen=strlen(p);
4737 }
4738 /* ========== Routines for Evaluation Cycle ========== */
4739
4740 /* make closure. c is code. e is environment */
4741 static pointer mk_closure(scheme *sc, pointer c, pointer e) {
4742 pointer x = get_cell(sc, c, e);
4743
4744 typeflag(x) = T_CLOSURE;
4745 car(x) = c;
4746 cdr(x) = e;
4747 return (x);
4748 }
4749
4750 /* make continuation. */
4751 static pointer mk_continuation(scheme *sc, pointer d) {
4752 pointer x = get_cell(sc, sc->NIL, d);
4753
4754 typeflag(x) = T_CONTINUATION;
4755 cont_dump(x) = d;
4756 return (x);
4757 }
4758
4759 static pointer list_star(scheme *sc, pointer d) {
4760 pointer p, q;
4761 if(cdr(d)==sc->NIL) {
4762 return car(d);
4763 }
4764 p=cons(sc,car(d),cdr(d));
4765 q=p;
4766 while(cdr(cdr(p))!=sc->NIL) {
4767 d=cons(sc,car(p),cdr(p));
4768 if(cdr(cdr(p))!=sc->NIL) {
4769 p=cdr(d);
4770 }
4771 }
4772 cdr(p)=car(cdr(p));
4773 return q;
4774 }
4775
4776 /* reverse list -- produce new list */
4777 static pointer reverse(scheme *sc, pointer a) {
4778 /* a must be checked by gc */
4779 pointer p = sc->NIL;
4780
4781 for ( ; is_pair(a); a = cdr(a)) {
4782 p = cons(sc, car(a), p);
4783 }
4784 return (p);
4785 }
4786
4787 /* reverse list --- in-place */
4788 static pointer reverse_in_place(scheme *sc, pointer term, pointer list) {
4789 pointer p = list, result = term, q;
4790
4791 while (p != sc->NIL) {
4792 q = cdr(p);
4793 cdr(p) = result;
4794 result = p;
4795 p = q;
4796 }
4797 return (result);
4798 }
4799
4800 /* append list -- produce new list (in reverse order) */
4801 static pointer revappend(scheme *sc, pointer a, pointer b) {
4802 pointer result = a;
4803 pointer p = b;
4804
4805 while (is_pair(p)) {
4806 result = cons(sc, car(p), result);
4807 p = cdr(p);
4808 }
4809
4810 if (p == sc->NIL) {
4811 return result;
4812 }
4813
4814 return sc->F; /* signal an error */
4815 }
4816
4817 /* equivalence of atoms */
4818 int eqv(pointer a, pointer b) {
4819 if (is_string(a)) {
4820 if (is_string(b))
4821 return (strvalue(a) == strvalue(b));
4822 else
4823 return (0);
4824 } else if (is_number(a)) {
4825 if (is_number(b)) {
4826 if (num_is_integer(a) == num_is_integer(b))
4827 return num_eq(nvalue(a),nvalue(b));
4828 }
4829 return (0);
4830 } else if (is_character(a)) {
4831 if (is_character(b))
4832 return charvalue(a)==charvalue(b);
4833 else
4834 return (0);
4835 } else if (is_port(a)) {
4836 if (is_port(b))
4837 return a==b;
4838 else
4839 return (0);
4840 } else if (is_proc(a)) {
4841 if (is_proc(b))
4842 return procnum(a)==procnum(b);
4843 else
4844 return (0);
4845 } else {
4846 return (a == b);
4847 }
4848 }
4849
4850 /* true or false value macro */
4851 /* () is #t in R5RS */
4852 #define is_true(p) ((p) != sc->F)
4853 #define is_false(p) ((p) == sc->F)
4854
4855 /* ========== Environment implementation ========== */
4856
4857 #if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
4858
4859 static int hash_fn(const char *key, int table_size)
4860 {
4861 unsigned int hashed = 0;
4862 const char *c;
4863 int bits_per_int = sizeof(unsigned int)*8;
4864
4865 for (c = key; *c; c++) {
4866 /* letters have about 5 bits in them */
4867 hashed = (hashed<<5) | (hashed>>(bits_per_int-5));
4868 hashed ^= *c;
4869 }
4870 return hashed % table_size;
4871 }
4872 #endif
4873
4874 #ifndef USE_ALIST_ENV
4875
4876 /*
4877 * In this implementation, each frame of the environment may be
4878 * a hash table: a vector of alists hashed by variable name.
4879 * In practice, we use a vector only for the initial frame;
4880 * subsequent frames are too small and transient for the lookup
4881 * speed to out-weigh the cost of making a new vector.
4882 */
4883
4884 static void new_frame_in_env(scheme *sc, pointer old_env)
4885 {
4886 pointer new_frame;
4887
4888 /* The interaction-environment has about 300 variables in it. */
4889 if (old_env == sc->NIL) {
4890 new_frame = mk_vector(sc, 461);
4891 } else {
4892 new_frame = sc->NIL;
4893 }
4894
4895 sc->envir = immutable_cons(sc, new_frame, old_env);
4896 setenvironment(sc->envir);
4897 }
4898
4899 static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
4900 pointer variable, pointer value)
4901 {
4902 pointer slot = immutable_cons(sc, variable, value);
4903
4904 if (is_vector(car(env))) {
4905 int location = hash_fn(symname(variable), ivalue_unchecked(car(env)));
4906
4907 set_vector_elem(car(env), location,
4908 immutable_cons(sc, slot, vector_elem(car(env), location)));
4909 } else {
4910 car(env) = immutable_cons(sc, slot, car(env));
4911 }
4912 }
4913
4914 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
4915 {
4916 pointer x,y;
4917 int location;
4918
4919 for (x = env; x != sc->NIL; x = cdr(x)) {
4920 if (is_vector(car(x))) {
4921 location = hash_fn(symname(hdl), ivalue_unchecked(car(x)));
4922 y = vector_elem(car(x), location);
4923 } else {
4924 y = car(x);
4925 }
4926 for ( ; y != sc->NIL; y = cdr(y)) {
4927 if (caar(y) == hdl) {
4928 break;
4929 }
4930 }
4931 if (y != sc->NIL) {
4932 break;
4933 }
4934 if(!all) {
4935 return sc->NIL;
4936 }
4937 }
4938 if (x != sc->NIL) {
4939 return car(y);
4940 }
4941 return sc->NIL;
4942 }
4943
4944 #else /* USE_ALIST_ENV */
4945
4946 static INLINE void new_frame_in_env(scheme *sc, pointer old_env)
4947 {
4948 sc->envir = immutable_cons(sc, sc->NIL, old_env);
4949 setenvironment(sc->envir);
4950 }
4951
4952 static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
4953 pointer variable, pointer value)
4954 {
4955 car(env) = immutable_cons(sc, immutable_cons(sc, variable, value), car(env));
4956 }
4957
4958 static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
4959 {
4960 pointer x,y;
4961 for (x = env; x != sc->NIL; x = cdr(x)) {
4962 for (y = car(x); y != sc->NIL; y = cdr(y)) {
4963 if (caar(y) == hdl) {
4964 break;
4965 }
4966 }
4967 if (y != sc->NIL) {
4968 break;
4969 }
4970 if(!all) {
4971 return sc->NIL;
4972 }
4973 }
4974 if (x != sc->NIL) {
4975 return car(y);
4976 }
4977 return sc->NIL;
4978 }
4979
4980 #endif /* USE_ALIST_ENV else */
4981
4982 static INLINE void new_slot_in_env(scheme *sc, pointer variable, pointer value)
4983 {
4984 new_slot_spec_in_env(sc, sc->envir, variable, value);
4985 }
4986
4987 static INLINE void set_slot_in_env(scheme *sc, pointer slot, pointer value)
4988 {
4989 cdr(slot) = value;
4990 }
4991
4992 static INLINE pointer slot_value_in_env(pointer slot)
4993 {
4994 return cdr(slot);
4995 }
4996
4997 /* ========== Evaluation Cycle ========== */
4998
4999
5000 static pointer _Error_1(scheme *sc, const char *s, pointer a) {
5001 const char *str = s;
5002 #if USE_ERROR_HOOK
5003 pointer x;
5004 pointer hdl=sc->ERROR_HOOK;
5005 #endif
5006
5007 #if SHOW_ERROR_LINE
5008 char sbuf[STRBUFFSIZE];
5009
5010 /* make sure error is not in REPL */
5011 if (sc->load_stack[sc->file_i].kind & port_file &&
5012 sc->load_stack[sc->file_i].rep.stdio.file != stdin) {
5013 int ln = sc->load_stack[sc->file_i].rep.stdio.curr_line;
5014 const char *fname = sc->load_stack[sc->file_i].rep.stdio.filename;
5015
5016 /* should never happen */
5017 if(!fname) fname = "<unknown>";
5018
5019 /* we started from 0 */
5020 ln++;
5021 snprintf(sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s);
5022
5023 str = (const char*)sbuf;
5024 }
5025 #endif
5026
5027 #if USE_ERROR_HOOK
5028 x=find_slot_in_env(sc,sc->envir,hdl,1);
5029 if (x != sc->NIL) {
5030 if(a!=0) {
5031 sc->code = cons(sc, cons(sc, sc->QUOTE, cons(sc,(a), sc->NIL)), sc->NIL);
5032 } else {
5033 sc->code = sc->NIL;
5034 }
5035 sc->code = cons(sc, mk_string(sc, str), sc->code);
5036 setimmutable(car(sc->code));
5037 sc->code = cons(sc, slot_value_in_env(x), sc->code);
5038 sc->op = (int)OP_EVAL;
5039 return sc->T;
5040 }
5041 #endif
5042
5043 if(a!=0) {
5044 sc->args = cons(sc, (a), sc->NIL);
5045 } else {
5046 sc->args = sc->NIL;
5047 }
5048 sc->args = cons(sc, mk_string(sc, str), sc->args);
5049 setimmutable(car(sc->args));
5050 sc->op = (int)OP_ERR0;
5051 return sc->T;
5052 }
5053 #define Error_1(sc,s, a) return _Error_1(sc,s,a)
5054 #define Error_0(sc,s) return _Error_1(sc,s,0)
5055
5056 /* Too small to turn into function */
5057 # define BEGIN do {
5058 # define END } while (0)
5059 #define s_goto(sc,a) BEGIN \
5060 sc->op = (int)(a); \
5061 return sc->T; END
5062
5063 #define s_return(sc,a) return _s_return(sc,a)
5064
5065 #ifndef USE_SCHEME_STACK
5066
5067 /* this structure holds all the interpreter's registers */
5068 struct dump_stack_frame {
5069 enum scheme_opcodes op;
5070 pointer args;
5071 pointer envir;
5072 pointer code;
5073 };
5074
5075 #define STACK_GROWTH 3
5076
5077 static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code)
5078 {
5079 int nframes = (int)sc->dump;
5080 struct dump_stack_frame *next_frame;
5081
5082 /* enough room for the next frame? */
5083 if (nframes >= sc->dump_size) {
5084 sc->dump_size += STACK_GROWTH;
5085 /* alas there is no sc->realloc */
5086 sc->dump_base = realloc(sc->dump_base,
5087 sizeof(struct dump_stack_frame) * sc->dump_size);
5088 }
5089 next_frame = (struct dump_stack_frame *)sc->dump_base + nframes;
5090 next_frame->op = op;
5091 next_frame->args = args;
5092 next_frame->envir = sc->envir;
5093 next_frame->code = code;
5094 sc->dump = (pointer)(nframes+1);
5095 }
5096
5097 static pointer _s_return(scheme *sc, pointer a)
5098 {
5099 int nframes = (int)sc->dump;
5100 struct dump_stack_frame *frame;
5101
5102 sc->value = (a);
5103 if (nframes <= 0) {
5104 return sc->NIL;
5105 }
5106 nframes--;
5107 frame = (struct dump_stack_frame *)sc->dump_base + nframes;
5108 sc->op = frame->op;
5109 sc->args = frame->args;
5110 sc->envir = frame->envir;
5111 sc->code = frame->code;
5112 sc->dump = (pointer)nframes;
5113 return sc->T;
5114 }
5115
5116 static INLINE void dump_stack_reset(scheme *sc)
5117 {
5118 /* in this implementation, sc->dump is the number of frames on the stack */
5119 sc->dump = (pointer)0;
5120 }
5121
5122 static INLINE void dump_stack_initialize(scheme *sc)
5123 {
5124 sc->dump_size = 0;
5125 sc->dump_base = NULL;
5126 dump_stack_reset(sc);
5127 }
5128
5129 static void dump_stack_free(scheme *sc)
5130 {
5131 free(sc->dump_base);
5132 sc->dump_base = NULL;
5133 sc->dump = (pointer)0;
5134 sc->dump_size = 0;
5135 }
5136
5137 static INLINE void dump_stack_mark(scheme *sc)
5138 {
5139 int nframes = (int)sc->dump;
5140 int i;
5141 for(i=0; i<nframes; i++) {
5142 struct dump_stack_frame *frame;
5143 frame = (struct dump_stack_frame *)sc->dump_base + i;
5144 mark(frame->args);
5145 mark(frame->envir);
5146 mark(frame->code);
5147 }
5148 }
5149
5150 #else
5151
5152 static INLINE void dump_stack_reset(scheme *sc)
5153 {
5154 sc->dump = sc->NIL;
5155 }
5156
5157 static INLINE void dump_stack_initialize(scheme *sc)
5158 {
5159 dump_stack_reset(sc);
5160 }
5161
5162 static void dump_stack_free(scheme *sc)
5163 {
5164 sc->dump = sc->NIL;
5165 }
5166
5167 static pointer _s_return(scheme *sc, pointer a) {
5168 sc->value = (a);
5169 if(sc->dump==sc->NIL) return sc->NIL;
5170 sc->op = ivalue(car(sc->dump));
5171 sc->args = cadr(sc->dump);
5172 sc->envir = caddr(sc->dump);
5173 sc->code = cadddr(sc->dump);
5174 sc->dump = cddddr(sc->dump);
5175 return sc->T;
5176 }
5177
5178 static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) {
5179 sc->dump = cons(sc, sc->envir, cons(sc, (code), sc->dump));
5180 sc->dump = cons(sc, (args), sc->dump);
5181 sc->dump = cons(sc, mk_integer(sc, (long)(op)), sc->dump);
5182 }
5183
5184 static INLINE void dump_stack_mark(scheme *sc)
5185 {
5186 mark(sc->dump);
5187 }
5188 #endif
5189
5190 #define s_retbool(tf) s_return(sc,(tf) ? sc->T : sc->F)
5191
5192 static pointer opexe_0(scheme *sc, enum scheme_opcodes op) {
5193 pointer x, y;
5194
5195 switch (op) {
5196 case OP_LOAD: /* load */
5197 if(file_interactive(sc)) {
5198 fprintf(sc->outport->_object._port->rep.stdio.file,
5199 "Loading %s\n", strvalue(car(sc->args)));
5200 }
5201 if (!file_push(sc,strvalue(car(sc->args)))) {
5202 Error_1(sc,"unable to open", car(sc->args));
5203 }
5204 else
5205 {
5206 sc->args = mk_integer(sc,sc->file_i);
5207 s_goto(sc,OP_T0LVL);
5208 }
5209
5210 case OP_T0LVL: /* top level */
5211 /* If we reached the end of file, this loop is done. */
5212 if(sc->loadport->_object._port->kind & port_saw_EOF)
5213 {
5214 if(sc->file_i == 0)
5215 {
5216 sc->args=sc->NIL;
5217 s_goto(sc,OP_QUIT);
5218 }
5219 else
5220 {
5221 file_pop(sc);
5222 s_return(sc,sc->value);
5223 }
5224 /* NOTREACHED */
5225 }
5226
5227 /* If interactive, be nice to user. */
5228 if(file_interactive(sc))
5229 {
5230 sc->envir = sc->global_env;
5231 dump_stack_reset(sc);
5232 putstr(sc,"\n");
5233 putstr(sc,prompt);
5234 }
5235
5236 /* Set up another iteration of REPL */
5237 sc->nesting=0;
5238 sc->save_inport=sc->inport;
5239 sc->inport = sc->loadport;
5240 s_save(sc,OP_T0LVL, sc->NIL, sc->NIL);
5241 s_save(sc,OP_VALUEPRINT, sc->NIL, sc->NIL);
5242 s_save(sc,OP_T1LVL, sc->NIL, sc->NIL);
5243 s_goto(sc,OP_READ_INTERNAL);
5244
5245 case OP_T1LVL: /* top level */
5246 sc->code = sc->value;
5247 sc->inport=sc->save_inport;
5248 s_goto(sc,OP_EVAL);
5249
5250 case OP_READ_INTERNAL: /* internal read */
5251 sc->tok = token(sc);
5252 if(sc->tok==TOK_EOF)
5253 { s_return(sc,sc->EOF_OBJ); }
5254 s_goto(sc,OP_RDSEXPR);
5255
5256 case OP_GENSYM:
5257 s_return(sc, gensym(sc));
5258
5259 case OP_VALUEPRINT: /* print evaluation result */
5260 /* OP_VALUEPRINT is always pushed, because when changing from
5261 non-interactive to interactive mode, it needs to be
5262 already on the stack */
5263 if(sc->tracing) {
5264 putstr(sc,"\nGives: ");
5265 }
5266 if(file_interactive(sc)) {
5267 sc->print_flag = 1;
5268 sc->args = sc->value;
5269 s_goto(sc,OP_P0LIST);
5270 } else {
5271 s_return(sc,sc->value);
5272 }
5273
5274 case OP_EVAL: /* main part of evaluation */
5275 #if USE_TRACING
5276 if(sc->tracing) {
5277 /*s_save(sc,OP_VALUEPRINT,sc->NIL,sc->NIL);*/
5278 s_save(sc,OP_REAL_EVAL,sc->args,sc->code);
5279 sc->args=sc->code;
5280 putstr(sc,"\nEval: ");
5281 s_goto(sc,OP_P0LIST);
5282 }
5283 /* fall through */
5284 case OP_REAL_EVAL:
5285 #endif
5286 if (is_symbol(sc->code)) { /* symbol */
5287 x=find_slot_in_env(sc,sc->envir,sc->code,1);
5288 if (x != sc->NIL) {
5289 s_return(sc,slot_value_in_env(x));
5290 } else {
5291 Error_1(sc,"eval: unbound variable:", sc->code);
5292 }
5293 } else if (is_pair(sc->code)) {
5294 if (is_syntax(x = car(sc->code))) { /* SYNTAX */
5295 sc->code = cdr(sc->code);
5296 s_goto(sc,syntaxnum(x));
5297 } else {/* first, eval top element and eval arguments */
5298 s_save(sc,OP_E0ARGS, sc->NIL, sc->code);
5299 /* If no macros => s_save(sc,OP_E1ARGS, sc->NIL, cdr(sc->code));*/
5300 sc->code = car(sc->code);
5301 s_goto(sc,OP_EVAL);
5302 }
5303 } else {
5304 s_return(sc,sc->code);
5305 }
5306
5307 case OP_E0ARGS: /* eval arguments */
5308 if (is_macro(sc->value)) { /* macro expansion */
5309 s_save(sc,OP_DOMACRO, sc->NIL, sc->NIL);
5310 sc->args = cons(sc,sc->code, sc->NIL);
5311 sc->code = sc->value;
5312 s_goto(sc,OP_APPLY);
5313 } else {
5314 sc->code = cdr(sc->code);
5315 s_goto(sc,OP_E1ARGS);
5316 }
5317
5318 case OP_E1ARGS: /* eval arguments */
5319 sc->args = cons(sc, sc->value, sc->args);
5320 if (is_pair(sc->code)) { /* continue */
5321 s_save(sc,OP_E1ARGS, sc->args, cdr(sc->code));
5322 sc->code = car(sc->code);
5323 sc->args = sc->NIL;
5324 s_goto(sc,OP_EVAL);
5325 } else { /* end */
5326 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
5327 sc->code = car(sc->args);
5328 sc->args = cdr(sc->args);
5329 s_goto(sc,OP_APPLY);
5330 }
5331
5332 #if USE_TRACING
5333 case OP_TRACING: {
5334 int tr=sc->tracing;
5335 sc->tracing=ivalue(car(sc->args));
5336 s_return(sc,mk_integer(sc,tr));
5337 }
5338 #endif
5339
5340 case OP_APPLY: /* apply 'code' to 'args' */
5341 #if USE_TRACING
5342 if(sc->tracing) {
5343 s_save(sc,OP_REAL_APPLY,sc->args,sc->code);
5344 sc->print_flag = 1;
5345 /* sc->args=cons(sc,sc->code,sc->args);*/
5346 putstr(sc,"\nApply to: ");
5347 s_goto(sc,OP_P0LIST);
5348 }
5349 /* fall through */
5350 case OP_REAL_APPLY:
5351 #endif
5352 if (is_proc(sc->code)) {
5353 s_goto(sc,procnum(sc->code)); /* PROCEDURE */
5354 } else if (is_foreign(sc->code))
5355 {
5356 /* Keep nested calls from GC'ing the arglist */
5357 push_recent_alloc(sc,sc->args,sc->NIL);
5358 x=sc->code->_object._ff(sc,sc->args);
5359 s_return(sc,x);
5360 } else if (is_closure(sc->code) || is_macro(sc->code)
5361 || is_promise(sc->code)) { /* CLOSURE */
5362 /* Should not accept promise */
5363 /* make environment */
5364 new_frame_in_env(sc, closure_env(sc->code));
5365 for (x = car(closure_code(sc->code)), y = sc->args;
5366 is_pair(x); x = cdr(x), y = cdr(y)) {
5367 if (y == sc->NIL) {
5368 Error_0(sc,"not enough arguments");
5369 } else {
5370 new_slot_in_env(sc, car(x), car(y));
5371 }
5372 }
5373 if (x == sc->NIL) {
5374 /*--
5375 * if (y != sc->NIL) {
5376 * Error_0(sc,"too many arguments");
5377 * }
5378 */
5379 } else if (is_symbol(x))
5380 new_slot_in_env(sc, x, y);
5381 else {
5382 Error_1(sc,"syntax error in closure: not a symbol:", x);
5383 }
5384 sc->code = cdr(closure_code(sc->code));
5385 sc->args = sc->NIL;
5386 s_goto(sc,OP_BEGIN);
5387 } else if (is_continuation(sc->code)) { /* CONTINUATION */
5388 sc->dump = cont_dump(sc->code);
5389 s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL);
5390 } else {
5391 Error_0(sc,"illegal function");
5392 }
5393
5394 case OP_DOMACRO: /* do macro */
5395 sc->code = sc->value;
5396 s_goto(sc,OP_EVAL);
5397
5398 #if 1
5399 case OP_LAMBDA: /* lambda */
5400 /* If the hook is defined, apply it to sc->code, otherwise
5401 set sc->value fall thru */
5402 {
5403 pointer f=find_slot_in_env(sc,sc->envir,sc->COMPILE_HOOK,1);
5404 if(f==sc->NIL) {
5405 sc->value = sc->code;
5406 /* Fallthru */
5407 } else {
5408 s_save(sc,OP_LAMBDA1,sc->args,sc->code);
5409 sc->args=cons(sc,sc->code,sc->NIL);
5410 sc->code=slot_value_in_env(f);
5411 s_goto(sc,OP_APPLY);
5412 }
5413 }
5414
5415 case OP_LAMBDA1:
5416 s_return(sc,mk_closure(sc, sc->value, sc->envir));
5417
5418 #else
5419 case OP_LAMBDA: /* lambda */
5420 s_return(sc,mk_closure(sc, sc->code, sc->envir));
5421
5422 #endif
5423
5424 case OP_MKCLOSURE: /* make-closure */
5425 x=car(sc->args);
5426 if(car(x)==sc->LAMBDA) {
5427 x=cdr(x);
5428 }
5429 if(cdr(sc->args)==sc->NIL) {
5430 y=sc->envir;
5431 } else {
5432 y=cadr(sc->args);
5433 }
5434 s_return(sc,mk_closure(sc, x, y));
5435
5436 case OP_QUOTE: /* quote */
5437 s_return(sc,car(sc->code));
5438
5439 case OP_DEF0: /* define */
5440 if(is_immutable(car(sc->code)))
5441 Error_1(sc,"define: unable to alter immutable", car(sc->code));
5442
5443 if (is_pair(car(sc->code))) {
5444 x = caar(sc->code);
5445 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
5446 } else {
5447 x = car(sc->code);
5448 sc->code = cadr(sc->code);
5449 }
5450 if (!is_symbol(x)) {
5451 Error_0(sc,"variable is not a symbol");
5452 }
5453 s_save(sc,OP_DEF1, sc->NIL, x);
5454 s_goto(sc,OP_EVAL);
5455
5456 case OP_DEF1: /* define */
5457 x=find_slot_in_env(sc,sc->envir,sc->code,0);
5458 if (x != sc->NIL) {
5459 set_slot_in_env(sc, x, sc->value);
5460 } else {
5461 new_slot_in_env(sc, sc->code, sc->value);
5462 }
5463 s_return(sc,sc->code);
5464
5465
5466 case OP_DEFP: /* defined? */
5467 x=sc->envir;
5468 if(cdr(sc->args)!=sc->NIL) {
5469 x=cadr(sc->args);
5470 }
5471 s_retbool(find_slot_in_env(sc,x,car(sc->args),1)!=sc->NIL);
5472
5473 case OP_SET0: /* set! */
5474 if(is_immutable(car(sc->code)))
5475 Error_1(sc,"set!: unable to alter immutable variable",car(sc->code));
5476 s_save(sc,OP_SET1, sc->NIL, car(sc->code));
5477 sc->code = cadr(sc->code);
5478 s_goto(sc,OP_EVAL);
5479
5480 case OP_SET1: /* set! */
5481 y=find_slot_in_env(sc,sc->envir,sc->code,1);
5482 if (y != sc->NIL) {
5483 set_slot_in_env(sc, y, sc->value);
5484 s_return(sc,sc->value);
5485 } else {
5486 Error_1(sc,"set!: unbound variable:", sc->code);
5487 }
5488
5489
5490 case OP_BEGIN: /* begin */
5491 if (!is_pair(sc->code)) {
5492 s_return(sc,sc->code);
5493 }
5494 if (cdr(sc->code) != sc->NIL) {
5495 s_save(sc,OP_BEGIN, sc->NIL, cdr(sc->code));
5496 }
5497 sc->code = car(sc->code);
5498 s_goto(sc,OP_EVAL);
5499
5500 case OP_IF0: /* if */
5501 s_save(sc,OP_IF1, sc->NIL, cdr(sc->code));
5502 sc->code = car(sc->code);
5503 s_goto(sc,OP_EVAL);
5504
5505 case OP_IF1: /* if */
5506 if (is_true(sc->value))
5507 sc->code = car(sc->code);
5508 else
5509 sc->code = cadr(sc->code); /* (if #f 1) ==> () because
5510 * car(sc->NIL) = sc->NIL */
5511 s_goto(sc,OP_EVAL);
5512
5513 case OP_LET0: /* let */
5514 sc->args = sc->NIL;
5515 sc->value = sc->code;
5516 sc->code = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code);
5517 s_goto(sc,OP_LET1);
5518
5519 case OP_LET1: /* let (calculate parameters) */
5520 sc->args = cons(sc, sc->value, sc->args);
5521 if (is_pair(sc->code)) { /* continue */
5522 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
5523 Error_1(sc, "Bad syntax of binding spec in let :",
5524 car(sc->code));
5525 }
5526 s_save(sc,OP_LET1, sc->args, cdr(sc->code));
5527 sc->code = cadar(sc->code);
5528 sc->args = sc->NIL;
5529 s_goto(sc,OP_EVAL);
5530 } else { /* end */
5531 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
5532 sc->code = car(sc->args);
5533 sc->args = cdr(sc->args);
5534 s_goto(sc,OP_LET2);
5535 }
5536
5537 case OP_LET2: /* let */
5538 new_frame_in_env(sc, sc->envir);
5539 for (x = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code), y = sc->args;
5540 y != sc->NIL; x = cdr(x), y = cdr(y)) {
5541 new_slot_in_env(sc, caar(x), car(y));
5542 }
5543 if (is_symbol(car(sc->code))) { /* named let */
5544 for (x = cadr(sc->code), sc->args = sc->NIL; x != sc->NIL; x = cdr(x)) {
5545 if (!is_pair(x))
5546 Error_1(sc, "Bad syntax of binding in let :", x);
5547 if (!is_list(sc, car(x)))
5548 Error_1(sc, "Bad syntax of binding in let :", car(x));
5549 sc->args = cons(sc, caar(x), sc->args);
5550 }
5551 x = mk_closure(sc, cons(sc, reverse_in_place(sc, sc->NIL, sc->args), cddr(sc->code)), sc->envir);
5552 new_slot_in_env(sc, car(sc->code), x);
5553 sc->code = cddr(sc->code);
5554 sc->args = sc->NIL;
5555 } else {
5556 sc->code = cdr(sc->code);
5557 sc->args = sc->NIL;
5558 }
5559 s_goto(sc,OP_BEGIN);
5560
5561 case OP_LET0AST: /* let* */
5562 if (car(sc->code) == sc->NIL) {
5563 new_frame_in_env(sc, sc->envir);
5564 sc->code = cdr(sc->code);
5565 s_goto(sc,OP_BEGIN);
5566 }
5567 if(!is_pair(car(sc->code)) || !is_pair(caar(sc->code)) || !is_pair(cdaar(sc->code))) {
5568 Error_1(sc,"Bad syntax of binding spec in let* :",car(sc->code));
5569 }
5570 s_save(sc,OP_LET1AST, cdr(sc->code), car(sc->code));
5571 sc->code = cadaar(sc->code);
5572 s_goto(sc,OP_EVAL);
5573
5574 case OP_LET1AST: /* let* (make new frame) */
5575 new_frame_in_env(sc, sc->envir);
5576 s_goto(sc,OP_LET2AST);
5577
5578 case OP_LET2AST: /* let* (calculate parameters) */
5579 new_slot_in_env(sc, caar(sc->code), sc->value);
5580 sc->code = cdr(sc->code);
5581 if (is_pair(sc->code)) { /* continue */
5582 s_save(sc,OP_LET2AST, sc->args, sc->code);
5583 sc->code = cadar(sc->code);
5584 sc->args = sc->NIL;
5585 s_goto(sc,OP_EVAL);
5586 } else { /* end */
5587 sc->code = sc->args;
5588 sc->args = sc->NIL;
5589 s_goto(sc,OP_BEGIN);
5590 }
5591 default:
5592 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
5593 Error_0(sc,sc->strbuff);
5594 }
5595 return sc->T;
5596 }
5597
5598 static pointer opexe_1(scheme *sc, enum scheme_opcodes op) {
5599 pointer x, y;
5600
5601 switch (op) {
5602 case OP_LET0REC: /* letrec */
5603 new_frame_in_env(sc, sc->envir);
5604 sc->args = sc->NIL;
5605 sc->value = sc->code;
5606 sc->code = car(sc->code);
5607 s_goto(sc,OP_LET1REC);
5608
5609 case OP_LET1REC: /* letrec (calculate parameters) */
5610 sc->args = cons(sc, sc->value, sc->args);
5611 if (is_pair(sc->code)) { /* continue */
5612 if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
5613 Error_1(sc, "Bad syntax of binding spec in letrec :",
5614 car(sc->code));
5615 }
5616 s_save(sc,OP_LET1REC, sc->args, cdr(sc->code));
5617 sc->code = cadar(sc->code);
5618 sc->args = sc->NIL;
5619 s_goto(sc,OP_EVAL);
5620 } else { /* end */
5621 sc->args = reverse_in_place(sc, sc->NIL, sc->args);
5622 sc->code = car(sc->args);
5623 sc->args = cdr(sc->args);
5624 s_goto(sc,OP_LET2REC);
5625 }
5626
5627 case OP_LET2REC: /* letrec */
5628 for (x = car(sc->code), y = sc->args; y != sc->NIL; x = cdr(x), y = cdr(y)) {
5629 new_slot_in_env(sc, caar(x), car(y));
5630 }
5631 sc->code = cdr(sc->code);
5632 sc->args = sc->NIL;
5633 s_goto(sc,OP_BEGIN);
5634
5635 case OP_COND0: /* cond */
5636 if (!is_pair(sc->code)) {
5637 Error_0(sc,"syntax error in cond");
5638 }
5639 s_save(sc,OP_COND1, sc->NIL, sc->code);
5640 sc->code = caar(sc->code);
5641 s_goto(sc,OP_EVAL);
5642
5643 case OP_COND1: /* cond */
5644 if (is_true(sc->value)) {
5645 if ((sc->code = cdar(sc->code)) == sc->NIL) {
5646 s_return(sc,sc->value);
5647 }
5648 if(car(sc->code)==sc->FEED_TO) {
5649 if(!is_pair(cdr(sc->code))) {
5650 Error_0(sc,"syntax error in cond");
5651 }
5652 x=cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL));
5653 sc->code=cons(sc,cadr(sc->code),cons(sc,x,sc->NIL));
5654 s_goto(sc,OP_EVAL);
5655 }
5656 s_goto(sc,OP_BEGIN);
5657 } else {
5658 if ((sc->code = cdr(sc->code)) == sc->NIL) {
5659 s_return(sc,sc->NIL);
5660 } else {
5661 s_save(sc,OP_COND1, sc->NIL, sc->code);
5662 sc->code = caar(sc->code);
5663 s_goto(sc,OP_EVAL);
5664 }
5665 }
5666
5667 case OP_DELAY: /* delay */
5668 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
5669 typeflag(x)=T_PROMISE;
5670 s_return(sc,x);
5671
5672 case OP_AND0: /* and */
5673 if (sc->code == sc->NIL) {
5674 s_return(sc,sc->T);
5675 }
5676 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
5677 sc->code = car(sc->code);
5678 s_goto(sc,OP_EVAL);
5679
5680 case OP_AND1: /* and */
5681 if (is_false(sc->value)) {
5682 s_return(sc,sc->value);
5683 } else if (sc->code == sc->NIL) {
5684 s_return(sc,sc->value);
5685 } else {
5686 s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
5687 sc->code = car(sc->code);
5688 s_goto(sc,OP_EVAL);
5689 }
5690
5691 case OP_OR0: /* or */
5692 if (sc->code == sc->NIL) {
5693 s_return(sc,sc->F);
5694 }
5695 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
5696 sc->code = car(sc->code);
5697 s_goto(sc,OP_EVAL);
5698
5699 case OP_OR1: /* or */
5700 if (is_true(sc->value)) {
5701 s_return(sc,sc->value);
5702 } else if (sc->code == sc->NIL) {
5703 s_return(sc,sc->value);
5704 } else {
5705 s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
5706 sc->code = car(sc->code);
5707 s_goto(sc,OP_EVAL);
5708 }
5709
5710 case OP_C0STREAM: /* cons-stream */
5711 s_save(sc,OP_C1STREAM, sc->NIL, cdr(sc->code));
5712 sc->code = car(sc->code);
5713 s_goto(sc,OP_EVAL);
5714
5715 case OP_C1STREAM: /* cons-stream */
5716 sc->args = sc->value; /* save sc->value to register sc->args for gc */
5717 x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
5718 typeflag(x)=T_PROMISE;
5719 s_return(sc,cons(sc, sc->args, x));
5720
5721 case OP_MACRO0: /* macro */
5722 if (is_pair(car(sc->code))) {
5723 x = caar(sc->code);
5724 sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
5725 } else {
5726 x = car(sc->code);
5727 sc->code = cadr(sc->code);
5728 }
5729 if (!is_symbol(x)) {
5730 Error_0(sc,"variable is not a symbol");
5731 }
5732 s_save(sc,OP_MACRO1, sc->NIL, x);
5733 s_goto(sc,OP_EVAL);
5734
5735 case OP_MACRO1: /* macro */
5736 typeflag(sc->value) = T_MACRO;
5737 x = find_slot_in_env(sc, sc->envir, sc->code, 0);
5738 if (x != sc->NIL) {
5739 set_slot_in_env(sc, x, sc->value);
5740 } else {
5741 new_slot_in_env(sc, sc->code, sc->value);
5742 }
5743 s_return(sc,sc->code);
5744
5745 case OP_CASE0: /* case */
5746 s_save(sc,OP_CASE1, sc->NIL, cdr(sc->code));
5747 sc->code = car(sc->code);
5748 s_goto(sc,OP_EVAL);
5749
5750 case OP_CASE1: /* case */
5751 for (x = sc->code; x != sc->NIL; x = cdr(x)) {
5752 if (!is_pair(y = caar(x))) {
5753 break;
5754 }
5755 for ( ; y != sc->NIL; y = cdr(y)) {
5756 if (eqv(car(y), sc->value)) {
5757 break;
5758 }
5759 }
5760 if (y != sc->NIL) {
5761 break;
5762 }
5763 }
5764 if (x != sc->NIL) {
5765 if (is_pair(caar(x))) {
5766 sc->code = cdar(x);
5767 s_goto(sc,OP_BEGIN);
5768 } else {/* else */
5769 s_save(sc,OP_CASE2, sc->NIL, cdar(x));
5770 sc->code = caar(x);
5771 s_goto(sc,OP_EVAL);
5772 }
5773 } else {
5774 s_return(sc,sc->NIL);
5775 }
5776
5777 case OP_CASE2: /* case */
5778 if (is_true(sc->value)) {
5779 s_goto(sc,OP_BEGIN);
5780 } else {
5781 s_return(sc,sc->NIL);
5782 }
5783
5784 case OP_PAPPLY: /* apply */
5785 sc->code = car(sc->args);
5786 sc->args = list_star(sc,cdr(sc->args));
5787 /*sc->args = cadr(sc->args);*/
5788 s_goto(sc,OP_APPLY);
5789
5790 case OP_PEVAL: /* eval */
5791 if(cdr(sc->args)!=sc->NIL) {
5792 sc->envir=cadr(sc->args);
5793 }
5794 sc->code = car(sc->args);
5795 s_goto(sc,OP_EVAL);
5796
5797 case OP_CONTINUATION: /* call-with-current-continuation */
5798 sc->code = car(sc->args);
5799 sc->args = cons(sc, mk_continuation(sc, sc->dump), sc->NIL);
5800 s_goto(sc,OP_APPLY);
5801
5802 default:
5803 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
5804 Error_0(sc,sc->strbuff);
5805 }
5806 return sc->T;
5807 }
5808
5809 static pointer opexe_2(scheme *sc, enum scheme_opcodes op) {
5810 pointer x;
5811 num v;
5812 #if USE_MATH
5813 double dd;
5814 #endif
5815
5816 switch (op) {
5817 #if USE_MATH
5818 case OP_INEX2EX: /* inexact->exact */
5819 x=car(sc->args);
5820 if(num_is_integer(x)) {
5821 s_return(sc,x);
5822 } else if(modf(rvalue_unchecked(x),&dd)==0.0) {
5823 s_return(sc,mk_integer(sc,ivalue(x)));
5824 } else {
5825 Error_1(sc,"inexact->exact: not integral:",x);
5826 }
5827
5828 case OP_EXP:
5829 x=car(sc->args);
5830 s_return(sc, mk_real(sc, exp(rvalue(x))));
5831
5832 case OP_LOG:
5833 x=car(sc->args);
5834 s_return(sc, mk_real(sc, log(rvalue(x))));
5835
5836 case OP_SIN:
5837 x=car(sc->args);
5838 s_return(sc, mk_real(sc, sin(rvalue(x))));
5839
5840 case OP_COS:
5841 x=car(sc->args);
5842 s_return(sc, mk_real(sc, cos(rvalue(x))));
5843
5844 case OP_TAN:
5845 x=car(sc->args);
5846 s_return(sc, mk_real(sc, tan(rvalue(x))));
5847
5848 case OP_ASIN:
5849 x=car(sc->args);
5850 s_return(sc, mk_real(sc, asin(rvalue(x))));
5851
5852 case OP_ACOS:
5853 x=car(sc->args);
5854 s_return(sc, mk_real(sc, acos(rvalue(x))));
5855
5856 case OP_ATAN:
5857 x=car(sc->args);
5858 if(cdr(sc->args)==sc->NIL) {
5859 s_return(sc, mk_real(sc, atan(rvalue(x))));
5860 } else {
5861 pointer y=cadr(sc->args);
5862 s_return(sc, mk_real(sc, atan2(rvalue(x),rvalue(y))));
5863 }
5864
5865 case OP_SQRT:
5866 x=car(sc->args);
5867 s_return(sc, mk_real(sc, sqrt(rvalue(x))));
5868
5869 case OP_EXPT: {
5870 double result;
5871 int real_result=1;
5872 pointer y=cadr(sc->args);
5873 x=car(sc->args);
5874 if (num_is_integer(x) && num_is_integer(y))
5875 real_result=0;
5876 /* This 'if' is an R5RS compatibility fix. */
5877 /* NOTE: Remove this 'if' fix for R6RS. */
5878 if (rvalue(x) == 0 && rvalue(y) < 0) {
5879 result = 0.0;
5880 } else {
5881 result = pow(rvalue(x),rvalue(y));
5882 }
5883 /* Before returning integer result make sure we can. */
5884 /* If the test fails, result is too big for integer. */
5885 if (!real_result)
5886 {
5887 long result_as_long = (long)result;
5888 if (result != (double)result_as_long)
5889 real_result = 1;
5890 }
5891 if (real_result) {
5892 s_return(sc, mk_real(sc, result));
5893 } else {
5894 s_return(sc, mk_integer(sc, result));
5895 }
5896 }
5897
5898 case OP_FLOOR:
5899 x=car(sc->args);
5900 s_return(sc, mk_real(sc, floor(rvalue(x))));
5901
5902 case OP_CEILING:
5903 x=car(sc->args);
5904 s_return(sc, mk_real(sc, ceil(rvalue(x))));
5905
5906 case OP_TRUNCATE : {
5907 double rvalue_of_x ;
5908 x=car(sc->args);
5909 rvalue_of_x = rvalue(x) ;
5910 if (rvalue_of_x > 0) {
5911 s_return(sc, mk_real(sc, floor(rvalue_of_x)));
5912 } else {
5913 s_return(sc, mk_real(sc, ceil(rvalue_of_x)));
5914 }
5915 }
5916
5917 case OP_ROUND:
5918 x=car(sc->args);
5919 if (num_is_integer(x))
5920 s_return(sc, x);
5921 s_return(sc, mk_real(sc, round_per_R5RS(rvalue(x))));
5922 #endif
5923
5924 case OP_ADD: /* + */
5925 v=num_zero;
5926 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
5927 v=num_add(v,nvalue(car(x)));
5928 }
5929 s_return(sc,mk_number(sc, v));
5930
5931 case OP_MUL: /* * */
5932 v=num_one;
5933 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
5934 v=num_mul(v,nvalue(car(x)));
5935 }
5936 s_return(sc,mk_number(sc, v));
5937
5938 case OP_SUB: /* - */
5939 if(cdr(sc->args)==sc->NIL) {
5940 x=sc->args;
5941 v=num_zero;
5942 } else {
5943 x = cdr(sc->args);
5944 v = nvalue(car(sc->args));
5945 }
5946 for (; x != sc->NIL; x = cdr(x)) {
5947 v=num_sub(v,nvalue(car(x)));
5948 }
5949 s_return(sc,mk_number(sc, v));
5950
5951 case OP_DIV: /* / */
5952 if(cdr(sc->args)==sc->NIL) {
5953 x=sc->args;
5954 v=num_one;
5955 } else {
5956 x = cdr(sc->args);
5957 v = nvalue(car(sc->args));
5958 }
5959 for (; x != sc->NIL; x = cdr(x)) {
5960 if (!is_zero_double(rvalue(car(x))))
5961 v=num_div(v,nvalue(car(x)));
5962 else {
5963 Error_0(sc,"/: division by zero");
5964 }
5965 }
5966 s_return(sc,mk_number(sc, v));
5967
5968 case OP_INTDIV: /* quotient */
5969 if(cdr(sc->args)==sc->NIL) {
5970 x=sc->args;
5971 v=num_one;
5972 } else {
5973 x = cdr(sc->args);
5974 v = nvalue(car(sc->args));
5975 }
5976 for (; x != sc->NIL; x = cdr(x)) {
5977 if (ivalue(car(x)) != 0)
5978 v=num_intdiv(v,nvalue(car(x)));
5979 else {
5980 Error_0(sc,"quotient: division by zero");
5981 }
5982 }
5983 s_return(sc,mk_number(sc, v));
5984
5985 case OP_REM: /* remainder */
5986 v = nvalue(car(sc->args));
5987 if (ivalue(cadr(sc->args)) != 0)
5988 v=num_rem(v,nvalue(cadr(sc->args)));
5989 else {
5990 Error_0(sc,"remainder: division by zero");
5991 }
5992 s_return(sc,mk_number(sc, v));
5993
5994 case OP_MOD: /* modulo */
5995 v = nvalue(car(sc->args));
5996 if (ivalue(cadr(sc->args)) != 0)
5997 v=num_mod(v,nvalue(cadr(sc->args)));
5998 else {
5999 Error_0(sc,"modulo: division by zero");
6000 }
6001 s_return(sc,mk_number(sc, v));
6002
6003 case OP_CAR: /* car */
6004 s_return(sc,caar(sc->args));
6005
6006 case OP_CDR: /* cdr */
6007 s_return(sc,cdar(sc->args));
6008
6009 case OP_CONS: /* cons */
6010 cdr(sc->args) = cadr(sc->args);
6011 s_return(sc,sc->args);
6012
6013 case OP_SETCAR: /* set-car! */
6014 if(!is_immutable(car(sc->args))) {
6015 caar(sc->args) = cadr(sc->args);
6016 s_return(sc,car(sc->args));
6017 } else {
6018 Error_0(sc,"set-car!: unable to alter immutable pair");
6019 }
6020
6021 case OP_SETCDR: /* set-cdr! */
6022 if(!is_immutable(car(sc->args))) {
6023 cdar(sc->args) = cadr(sc->args);
6024 s_return(sc,car(sc->args));
6025 } else {
6026 Error_0(sc,"set-cdr!: unable to alter immutable pair");
6027 }
6028
6029 case OP_CHAR2INT: { /* char->integer */
6030 char c;
6031 c=(char)ivalue(car(sc->args));
6032 s_return(sc,mk_integer(sc,(unsigned char)c));
6033 }
6034
6035 case OP_INT2CHAR: { /* integer->char */
6036 unsigned char c;
6037 c=(unsigned char)ivalue(car(sc->args));
6038 s_return(sc,mk_character(sc,(char)c));
6039 }
6040
6041 case OP_CHARUPCASE: {
6042 unsigned char c;
6043 c=(unsigned char)ivalue(car(sc->args));
6044 c=toupper(c);
6045 s_return(sc,mk_character(sc,(char)c));
6046 }
6047
6048 case OP_CHARDNCASE: {
6049 unsigned char c;
6050 c=(unsigned char)ivalue(car(sc->args));
6051 c=tolower(c);
6052 s_return(sc,mk_character(sc,(char)c));
6053 }
6054
6055 case OP_STR2SYM: /* string->symbol */
6056 s_return(sc,mk_symbol(sc,strvalue(car(sc->args))));
6057
6058 case OP_STR2ATOM: /* string->atom */ {
6059 char *s=strvalue(car(sc->args));
6060 long pf = 0;
6061 if(cdr(sc->args)!=sc->NIL) {
6062 /* we know cadr(sc->args) is a natural number */
6063 /* see if it is 2, 8, 10, or 16, or error */
6064 pf = ivalue_unchecked(cadr(sc->args));
6065 if(pf == 16 || pf == 10 || pf == 8 || pf == 2) {
6066 /* base is OK */
6067 }
6068 else {
6069 pf = -1;
6070 }
6071 }
6072 if (pf < 0) {
6073 Error_1(sc, "string->atom: bad base:", cadr(sc->args));
6074 } else if(*s=='#') /* no use of base! */ {
6075 s_return(sc, mk_sharp_const(sc, s+1));
6076 } else {
6077 if (pf == 0 || pf == 10) {
6078 s_return(sc, mk_atom(sc, s));
6079 }
6080 else {
6081 char *ep;
6082 long iv = strtol(s,&ep,(int )pf);
6083 if (*ep == 0) {
6084 s_return(sc, mk_integer(sc, iv));
6085 }
6086 else {
6087 s_return(sc, sc->F);
6088 }
6089 }
6090 }
6091 }
6092
6093 case OP_SYM2STR: /* symbol->string */
6094 x=mk_string(sc,symname(car(sc->args)));
6095 setimmutable(x);
6096 s_return(sc,x);
6097
6098 case OP_ATOM2STR: /* atom->string */ {
6099 long pf = 0;
6100 x=car(sc->args);
6101 if(cdr(sc->args)!=sc->NIL) {
6102 /* we know cadr(sc->args) is a natural number */
6103 /* see if it is 2, 8, 10, or 16, or error */
6104 pf = ivalue_unchecked(cadr(sc->args));
6105 if(is_number(x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2)) {
6106 /* base is OK */
6107 }
6108 else {
6109 pf = -1;
6110 }
6111 }
6112 if (pf < 0) {
6113 Error_1(sc, "atom->string: bad base:", cadr(sc->args));
6114 } else if(is_number(x) || is_character(x) || is_string(x) || is_symbol(x)) {
6115 char *p;
6116 int len;
6117 atom2str(sc,x,(int )pf,&p,&len);
6118 s_return(sc,mk_counted_string(sc,p,len));
6119 } else {
6120 Error_1(sc, "atom->string: not an atom:", x);
6121 }
6122 }
6123
6124 case OP_MKSTRING: { /* make-string */
6125 int fill=' ';
6126 int len;
6127
6128 len=ivalue(car(sc->args));
6129
6130 if(cdr(sc->args)!=sc->NIL) {
6131 fill=charvalue(cadr(sc->args));
6132 }
6133 s_return(sc,mk_empty_string(sc,len,(char)fill));
6134 }
6135
6136 case OP_STRLEN: /* string-length */
6137 s_return(sc,mk_integer(sc,strlength(car(sc->args))));
6138
6139 case OP_STRREF: { /* string-ref */
6140 char *str;
6141 int index;
6142
6143 str=strvalue(car(sc->args));
6144
6145 index=ivalue(cadr(sc->args));
6146
6147 if(index>=strlength(car(sc->args))) {
6148 Error_1(sc,"string-ref: out of bounds:",cadr(sc->args));
6149 }
6150
6151 s_return(sc,mk_character(sc,((unsigned char*)str)[index]));
6152 }
6153
6154 case OP_STRSET: { /* string-set! */
6155 char *str;
6156 int index;
6157 int c;
6158
6159 if(is_immutable(car(sc->args))) {
6160 Error_1(sc,"string-set!: unable to alter immutable string:",car(sc->args));
6161 }
6162 str=strvalue(car(sc->args));
6163
6164 index=ivalue(cadr(sc->args));
6165 if(index>=strlength(car(sc->args))) {
6166 Error_1(sc,"string-set!: out of bounds:",cadr(sc->args));
6167 }
6168
6169 c=charvalue(caddr(sc->args));
6170
6171 str[index]=(char)c;
6172 s_return(sc,car(sc->args));
6173 }
6174
6175 case OP_STRAPPEND: { /* string-append */
6176 /* in 1.29 string-append was in Scheme in init.scm but was too slow */
6177 int len = 0;
6178 pointer newstr;
6179 char *pos;
6180
6181 /* compute needed length for new string */
6182 for (x = sc->args; x != sc->NIL; x = cdr(x)) {
6183 len += strlength(car(x));
6184 }
6185 newstr = mk_empty_string(sc, len, ' ');
6186 /* store the contents of the argument strings into the new string */
6187 for (pos = strvalue(newstr), x = sc->args; x != sc->NIL;
6188 pos += strlength(car(x)), x = cdr(x)) {
6189 memcpy(pos, strvalue(car(x)), strlength(car(x)));
6190 }
6191 s_return(sc, newstr);
6192 }
6193
6194 case OP_SUBSTR: { /* substring */
6195 char *str;
6196 int index0;
6197 int index1;
6198 int len;
6199
6200 str=strvalue(car(sc->args));
6201
6202 index0=ivalue(cadr(sc->args));
6203
6204 if(index0>strlength(car(sc->args))) {
6205 Error_1(sc,"substring: start out of bounds:",cadr(sc->args));
6206 }
6207
6208 if(cddr(sc->args)!=sc->NIL) {
6209 index1=ivalue(caddr(sc->args));
6210 if(index1>strlength(car(sc->args)) || index1<index0) {
6211 Error_1(sc,"substring: end out of bounds:",caddr(sc->args));
6212 }
6213 } else {
6214 index1=strlength(car(sc->args));
6215 }
6216
6217 len=index1-index0;
6218 x=mk_empty_string(sc,len,' ');
6219 memcpy(strvalue(x),str+index0,len);
6220 strvalue(x)[len]=0;
6221
6222 s_return(sc,x);
6223 }
6224
6225 case OP_VECTOR: { /* vector */
6226 int i;
6227 pointer vec;
6228 int len=list_length(sc,sc->args);
6229 if(len<0) {
6230 Error_1(sc,"vector: not a proper list:",sc->args);
6231 }
6232 vec=mk_vector(sc,len);
6233 if(sc->no_memory) { s_return(sc, sc->sink); }
6234 for (x = sc->args, i = 0; is_pair(x); x = cdr(x), i++) {
6235 set_vector_elem(vec,i,car(x));
6236 }
6237 s_return(sc,vec);
6238 }
6239
6240 case OP_MKVECTOR: { /* make-vector */
6241 pointer fill=sc->NIL;
6242 int len;
6243 pointer vec;
6244
6245 len=ivalue(car(sc->args));
6246
6247 if(cdr(sc->args)!=sc->NIL) {
6248 fill=cadr(sc->args);
6249 }
6250 vec=mk_vector(sc,len);
6251 if(sc->no_memory) { s_return(sc, sc->sink); }
6252 if(fill!=sc->NIL) {
6253 fill_vector(vec,fill);
6254 }
6255 s_return(sc,vec);
6256 }
6257
6258 case OP_VECLEN: /* vector-length */
6259 s_return(sc,mk_integer(sc,ivalue(car(sc->args))));
6260
6261 case OP_VECREF: { /* vector-ref */
6262 int index;
6263
6264 index=ivalue(cadr(sc->args));
6265
6266 if(index>=ivalue(car(sc->args))) {
6267 Error_1(sc,"vector-ref: out of bounds:",cadr(sc->args));
6268 }
6269
6270 s_return(sc,vector_elem(car(sc->args),index));
6271 }
6272
6273 case OP_VECSET: { /* vector-set! */
6274 int index;
6275
6276 if(is_immutable(car(sc->args))) {
6277 Error_1(sc,"vector-set!: unable to alter immutable vector:",car(sc->args));
6278 }
6279
6280 index=ivalue(cadr(sc->args));
6281 if(index>=ivalue(car(sc->args))) {
6282 Error_1(sc,"vector-set!: out of bounds:",cadr(sc->args));
6283 }
6284
6285 set_vector_elem(car(sc->args),index,caddr(sc->args));
6286 s_return(sc,car(sc->args));
6287 }
6288
6289 default:
6290 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
6291 Error_0(sc,sc->strbuff);
6292 }
6293 return sc->T;
6294 }
6295
6296 static int is_list(scheme *sc, pointer a)
6297 { return list_length(sc,a) >= 0; }
6298
6299 /* Result is:
6300 proper list: length
6301 circular list: -1
6302 not even a pair: -2
6303 dotted list: -2 minus length before dot
6304 */
6305 int list_length(scheme *sc, pointer a) {
6306 int i=0;
6307 pointer slow, fast;
6308
6309 slow = fast = a;
6310 while (1)
6311 {
6312 if (fast == sc->NIL)
6313 return i;
6314 if (!is_pair(fast))
6315 return -2 - i;
6316 fast = cdr(fast);
6317 ++i;
6318 if (fast == sc->NIL)
6319 return i;
6320 if (!is_pair(fast))
6321 return -2 - i;
6322 ++i;
6323 fast = cdr(fast);
6324
6325 /* Safe because we would have already returned if `fast'
6326 encountered a non-pair. */
6327 slow = cdr(slow);
6328 if (fast == slow)
6329 {
6330 /* the fast pointer has looped back around and caught up
6331 with the slow pointer, hence the structure is circular,
6332 not of finite length, and therefore not a list */
6333 return -1;
6334 }
6335 }
6336 }
6337
6338 static pointer opexe_3(scheme *sc, enum scheme_opcodes op) {
6339 pointer x;
6340 num v;
6341 int (*comp_func)(num,num)=0;
6342
6343 switch (op) {
6344 case OP_NOT: /* not */
6345 s_retbool(is_false(car(sc->args)));
6346 case OP_BOOLP: /* boolean? */
6347 s_retbool(car(sc->args) == sc->F || car(sc->args) == sc->T);
6348 case OP_EOFOBJP: /* boolean? */
6349 s_retbool(car(sc->args) == sc->EOF_OBJ);
6350 case OP_NULLP: /* null? */
6351 s_retbool(car(sc->args) == sc->NIL);
6352 case OP_NUMEQ: /* = */
6353 case OP_LESS: /* < */
6354 case OP_GRE: /* > */
6355 case OP_LEQ: /* <= */
6356 case OP_GEQ: /* >= */
6357 switch(op) {
6358 case OP_NUMEQ: comp_func=num_eq; break;
6359 case OP_LESS: comp_func=num_lt; break;
6360 case OP_GRE: comp_func=num_gt; break;
6361 case OP_LEQ: comp_func=num_le; break;
6362 case OP_GEQ: comp_func=num_ge; break;
6363 }
6364 x=sc->args;
6365 v=nvalue(car(x));
6366 x=cdr(x);
6367
6368 for (; x != sc->NIL; x = cdr(x)) {
6369 if(!comp_func(v,nvalue(car(x)))) {
6370 s_retbool(0);
6371 }
6372 v=nvalue(car(x));
6373 }
6374 s_retbool(1);
6375 case OP_SYMBOLP: /* symbol? */
6376 s_retbool(is_symbol(car(sc->args)));
6377 case OP_NUMBERP: /* number? */
6378 s_retbool(is_number(car(sc->args)));
6379 case OP_STRINGP: /* string? */
6380 s_retbool(is_string(car(sc->args)));
6381 case OP_INTEGERP: /* integer? */
6382 s_retbool(is_integer(car(sc->args)));
6383 case OP_REALP: /* real? */
6384 s_retbool(is_number(car(sc->args))); /* All numbers are real */
6385 case OP_CHARP: /* char? */
6386 s_retbool(is_character(car(sc->args)));
6387 #if USE_CHAR_CLASSIFIERS
6388 case OP_CHARAP: /* char-alphabetic? */
6389 s_retbool(Cisalpha(ivalue(car(sc->args))));
6390 case OP_CHARNP: /* char-numeric? */
6391 s_retbool(Cisdigit(ivalue(car(sc->args))));
6392 case OP_CHARWP: /* char-whitespace? */
6393 s_retbool(Cisspace(ivalue(car(sc->args))));
6394 case OP_CHARUP: /* char-upper-case? */
6395 s_retbool(Cisupper(ivalue(car(sc->args))));
6396 case OP_CHARLP: /* char-lower-case? */
6397 s_retbool(Cislower(ivalue(car(sc->args))));
6398 #endif
6399 case OP_PORTP: /* port? */
6400 s_retbool(is_port(car(sc->args)));
6401 case OP_INPORTP: /* input-port? */
6402 s_retbool(is_inport(car(sc->args)));
6403 case OP_OUTPORTP: /* output-port? */
6404 s_retbool(is_outport(car(sc->args)));
6405 case OP_PROCP: /* procedure? */
6406 /*--
6407 * continuation should be procedure by the example
6408 * (call-with-current-continuation procedure?) ==> #t
6409 * in R^3 report sec. 6.9
6410 */
6411 s_retbool(is_proc(car(sc->args)) || is_closure(car(sc->args))
6412 || is_continuation(car(sc->args)) || is_foreign(car(sc->args)));
6413 case OP_PAIRP: /* pair? */
6414 s_retbool(is_pair(car(sc->args)));
6415 case OP_LISTP: /* list? */
6416 s_retbool(list_length(sc,car(sc->args)) >= 0);
6417
6418 case OP_ENVP: /* environment? */
6419 s_retbool(is_environment(car(sc->args)));
6420 case OP_VECTORP: /* vector? */
6421 s_retbool(is_vector(car(sc->args)));
6422 case OP_EQ: /* eq? */
6423 s_retbool(car(sc->args) == cadr(sc->args));
6424 case OP_EQV: /* eqv? */
6425 s_retbool(eqv(car(sc->args), cadr(sc->args)));
6426 default:
6427 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
6428 Error_0(sc,sc->strbuff);
6429 }
6430 return sc->T;
6431 }
6432
6433 static pointer opexe_4(scheme *sc, enum scheme_opcodes op) {
6434 pointer x, y;
6435
6436 switch (op) {
6437 case OP_FORCE: /* force */
6438 sc->code = car(sc->args);
6439 if (is_promise(sc->code)) {
6440 /* Should change type to closure here */
6441 s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code);
6442 sc->args = sc->NIL;
6443 s_goto(sc,OP_APPLY);
6444 } else {
6445 s_return(sc,sc->code);
6446 }
6447
6448 case OP_SAVE_FORCED: /* Save forced value replacing promise */
6449 memcpy(sc->code,sc->value,sizeof(struct cell));
6450 s_return(sc,sc->value);
6451
6452 case OP_WRITE: /* write */
6453 case OP_DISPLAY: /* display */
6454 case OP_WRITE_CHAR: /* write-char */
6455 if(is_pair(cdr(sc->args))) {
6456 if(cadr(sc->args)!=sc->outport) {
6457 x=cons(sc,sc->outport,sc->NIL);
6458 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
6459 sc->outport=cadr(sc->args);
6460 }
6461 }
6462 sc->args = car(sc->args);
6463 if(op==OP_WRITE) {
6464 sc->print_flag = 1;
6465 } else {
6466 sc->print_flag = 0;
6467 }
6468 s_goto(sc,OP_P0LIST);
6469
6470 case OP_NEWLINE: /* newline */
6471 if(is_pair(sc->args)) {
6472 if(car(sc->args)!=sc->outport) {
6473 x=cons(sc,sc->outport,sc->NIL);
6474 s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
6475 sc->outport=car(sc->args);
6476 }
6477 }
6478 putstr(sc, "\n");
6479 s_return(sc,sc->T);
6480
6481 case OP_ERR0: /* error */
6482 sc->retcode=-1;
6483 if (!is_string(car(sc->args))) {
6484 sc->args=cons(sc,mk_string(sc," -- "),sc->args);
6485 setimmutable(car(sc->args));
6486 }
6487 putstr(sc, "Error: ");
6488 putstr(sc, strvalue(car(sc->args)));
6489 sc->args = cdr(sc->args);
6490 s_goto(sc,OP_ERR1);
6491
6492 case OP_ERR1: /* error */
6493 putstr(sc, " ");
6494 if (sc->args != sc->NIL) {
6495 s_save(sc,OP_ERR1, cdr(sc->args), sc->NIL);
6496 sc->args = car(sc->args);
6497 sc->print_flag = 1;
6498 s_goto(sc,OP_P0LIST);
6499 } else {
6500 putstr(sc, "\n");
6501 if(sc->interactive_repl) {
6502 s_goto(sc,OP_T0LVL);
6503 } else {
6504 return sc->NIL;
6505 }
6506 }
6507
6508 case OP_REVERSE: /* reverse */
6509 s_return(sc,reverse(sc, car(sc->args)));
6510
6511 case OP_LIST_STAR: /* list* */
6512 s_return(sc,list_star(sc,sc->args));
6513
6514 case OP_APPEND: /* append */
6515 x = sc->NIL;
6516 y = sc->args;
6517 if (y == x) {
6518 s_return(sc, x);
6519 }
6520
6521 /* cdr() in the while condition is not a typo. If car() */
6522 /* is used (append '() 'a) will return the wrong result.*/
6523 while (cdr(y) != sc->NIL) {
6524 x = revappend(sc, x, car(y));
6525 y = cdr(y);
6526 if (x == sc->F) {
6527 Error_0(sc, "non-list argument to append");
6528 }
6529 }
6530
6531 s_return(sc, reverse_in_place(sc, car(y), x));
6532
6533 #if USE_PLIST
6534 case OP_PUT: /* put */
6535 if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) {
6536 Error_0(sc,"illegal use of put");
6537 }
6538 for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) {
6539 if (caar(x) == y) {
6540 break;
6541 }
6542 }
6543 if (x != sc->NIL)
6544 cdar(x) = caddr(sc->args);
6545 else
6546 symprop(car(sc->args)) = cons(sc, cons(sc, y, caddr(sc->args)),
6547 symprop(car(sc->args)));
6548 s_return(sc,sc->T);
6549
6550 case OP_GET: /* get */
6551 if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) {
6552 Error_0(sc,"illegal use of get");
6553 }
6554 for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) {
6555 if (caar(x) == y) {
6556 break;
6557 }
6558 }
6559 if (x != sc->NIL) {
6560 s_return(sc,cdar(x));
6561 } else {
6562 s_return(sc,sc->NIL);
6563 }
6564 #endif /* USE_PLIST */
6565 case OP_QUIT: /* quit */
6566 if(is_pair(sc->args)) {
6567 sc->retcode=ivalue(car(sc->args));
6568 }
6569 return (sc->NIL);
6570
6571 case OP_GC: /* gc */
6572 gc(sc, sc->NIL, sc->NIL);
6573 s_return(sc,sc->T);
6574
6575 case OP_GCVERB: /* gc-verbose */
6576 { int was = sc->gc_verbose;
6577
6578 sc->gc_verbose = (car(sc->args) != sc->F);
6579 s_retbool(was);
6580 }
6581
6582 case OP_NEWSEGMENT: /* new-segment */
6583 if (!is_pair(sc->args) || !is_number(car(sc->args))) {
6584 Error_0(sc,"new-segment: argument must be a number");
6585 }
6586 alloc_cellseg(sc, (int) ivalue(car(sc->args)));
6587 s_return(sc,sc->T);
6588
6589 case OP_OBLIST: /* oblist */
6590 s_return(sc, oblist_all_symbols(sc));
6591
6592 case OP_CURR_INPORT: /* current-input-port */
6593 s_return(sc,sc->inport);
6594
6595 case OP_CURR_OUTPORT: /* current-output-port */
6596 s_return(sc,sc->outport);
6597
6598 case OP_OPEN_INFILE: /* open-input-file */
6599 case OP_OPEN_OUTFILE: /* open-output-file */
6600 case OP_OPEN_INOUTFILE: /* open-input-output-file */ {
6601 int prop=0;
6602 pointer p;
6603 switch(op) {
6604 case OP_OPEN_INFILE: prop=port_input; break;
6605 case OP_OPEN_OUTFILE: prop=port_output; break;
6606 case OP_OPEN_INOUTFILE: prop=port_input|port_output; break;
6607 }
6608 p=port_from_filename(sc,strvalue(car(sc->args)),prop);
6609 if(p==sc->NIL) {
6610 s_return(sc,sc->F);
6611 }
6612 s_return(sc,p);
6613 }
6614
6615 #if USE_STRING_PORTS
6616 case OP_OPEN_INSTRING: /* open-input-string */
6617 case OP_OPEN_INOUTSTRING: /* open-input-output-string */ {
6618 int prop=0;
6619 pointer p;
6620 switch(op) {
6621 case OP_OPEN_INSTRING: prop=port_input; break;
6622 case OP_OPEN_INOUTSTRING: prop=port_input|port_output; break;
6623 }
6624 p=port_from_string(sc, strvalue(car(sc->args)),
6625 strvalue(car(sc->args))+strlength(car(sc->args)), prop);
6626 if(p==sc->NIL) {
6627 s_return(sc,sc->F);
6628 }
6629 s_return(sc,p);
6630 }
6631 case OP_OPEN_OUTSTRING: /* open-output-string */ {
6632 pointer p;
6633 if(car(sc->args)==sc->NIL) {
6634 p=port_from_scratch(sc);
6635 if(p==sc->NIL) {
6636 s_return(sc,sc->F);
6637 }
6638 } else {
6639 p=port_from_string(sc, strvalue(car(sc->args)),
6640 strvalue(car(sc->args))+strlength(car(sc->args)),
6641 port_output);
6642 if(p==sc->NIL) {
6643 s_return(sc,sc->F);
6644 }
6645 }
6646 s_return(sc,p);
6647 }
6648 case OP_GET_OUTSTRING: /* get-output-string */ {
6649 port *p;
6650
6651 if ((p=car(sc->args)->_object._port)->kind&port_string) {
6652 off_t size;
6653 char *str;
6654
6655 size=p->rep.string.curr-p->rep.string.start+1;
6656 str=sc->malloc(size);
6657 if(str != NULL) {
6658 pointer s;
6659
6660 memcpy(str,p->rep.string.start,size-1);
6661 str[size-1]='\0';
6662 s=mk_string(sc,str);
6663 sc->free(str);
6664 s_return(sc,s);
6665 }
6666 }
6667 s_return(sc,sc->F);
6668 }
6669 #endif
6670
6671 case OP_CLOSE_INPORT: /* close-input-port */
6672 port_close(sc,car(sc->args),port_input);
6673 s_return(sc,sc->T);
6674
6675 case OP_CLOSE_OUTPORT: /* close-output-port */
6676 port_close(sc,car(sc->args),port_output);
6677 s_return(sc,sc->T);
6678
6679 case OP_INT_ENV: /* interaction-environment */
6680 s_return(sc,sc->global_env);
6681
6682 case OP_CURR_ENV: /* current-environment */
6683 s_return(sc,sc->envir);
6684
6685 }
6686 return sc->T;
6687 }
6688
6689 static pointer opexe_5(scheme *sc, enum scheme_opcodes op) {
6690 pointer x;
6691
6692 if(sc->nesting!=0) {
6693 int n=sc->nesting;
6694 sc->nesting=0;
6695 sc->retcode=-1;
6696 Error_1(sc,"unmatched parentheses:",mk_integer(sc,n));
6697 }
6698
6699 switch (op) {
6700 /* ========== reading part ========== */
6701 case OP_READ:
6702 if(!is_pair(sc->args)) {
6703 s_goto(sc,OP_READ_INTERNAL);
6704 }
6705 if(!is_inport(car(sc->args))) {
6706 Error_1(sc,"read: not an input port:",car(sc->args));
6707 }
6708 if(car(sc->args)==sc->inport) {
6709 s_goto(sc,OP_READ_INTERNAL);
6710 }
6711 x=sc->inport;
6712 sc->inport=car(sc->args);
6713 x=cons(sc,x,sc->NIL);
6714 s_save(sc,OP_SET_INPORT, x, sc->NIL);
6715 s_goto(sc,OP_READ_INTERNAL);
6716
6717 case OP_READ_CHAR: /* read-char */
6718 case OP_PEEK_CHAR: /* peek-char */ {
6719 int c;
6720 if(is_pair(sc->args)) {
6721 if(car(sc->args)!=sc->inport) {
6722 x=sc->inport;
6723 x=cons(sc,x,sc->NIL);
6724 s_save(sc,OP_SET_INPORT, x, sc->NIL);
6725 sc->inport=car(sc->args);
6726 }
6727 }
6728 c=inchar(sc);
6729 if(c==EOF) {
6730 s_return(sc,sc->EOF_OBJ);
6731 }
6732 if(sc->op==OP_PEEK_CHAR) {
6733 backchar(sc,c);
6734 }
6735 s_return(sc,mk_character(sc,c));
6736 }
6737
6738 case OP_CHAR_READY: /* char-ready? */ {
6739 pointer p=sc->inport;
6740 int res;
6741 if(is_pair(sc->args)) {
6742 p=car(sc->args);
6743 }
6744 res=p->_object._port->kind&port_string;
6745 s_retbool(res);
6746 }
6747
6748 case OP_SET_INPORT: /* set-input-port */
6749 sc->inport=car(sc->args);
6750 s_return(sc,sc->value);
6751
6752 case OP_SET_OUTPORT: /* set-output-port */
6753 sc->outport=car(sc->args);
6754 s_return(sc,sc->value);
6755
6756 case OP_RDSEXPR:
6757 switch (sc->tok) {
6758 case TOK_EOF:
6759 s_return(sc,sc->EOF_OBJ);
6760 /* NOTREACHED */
6761 /*
6762 * Commented out because we now skip comments in the scanner
6763 *
6764 case TOK_COMMENT: {
6765 int c;
6766 while ((c=inchar(sc)) != '\n' && c!=EOF)
6767 ;
6768 sc->tok = token(sc);
6769 s_goto(sc,OP_RDSEXPR);
6770 }
6771 */
6772 case TOK_VEC:
6773 s_save(sc,OP_RDVEC,sc->NIL,sc->NIL);
6774 /* fall through */
6775 case TOK_LPAREN:
6776 sc->tok = token(sc);
6777 if (sc->tok == TOK_RPAREN) {
6778 s_return(sc,sc->NIL);
6779 } else if (sc->tok == TOK_DOT) {
6780 Error_0(sc,"syntax error: illegal dot expression");
6781 } else {
6782 sc->nesting_stack[sc->file_i]++;
6783 s_save(sc,OP_RDLIST, sc->NIL, sc->NIL);
6784 s_goto(sc,OP_RDSEXPR);
6785 }
6786 case TOK_QUOTE:
6787 s_save(sc,OP_RDQUOTE, sc->NIL, sc->NIL);
6788 sc->tok = token(sc);
6789 s_goto(sc,OP_RDSEXPR);
6790 case TOK_BQUOTE:
6791 sc->tok = token(sc);
6792 if(sc->tok==TOK_VEC) {
6793 s_save(sc,OP_RDQQUOTEVEC, sc->NIL, sc->NIL);
6794 sc->tok=TOK_LPAREN;
6795 s_goto(sc,OP_RDSEXPR);
6796 } else {
6797 s_save(sc,OP_RDQQUOTE, sc->NIL, sc->NIL);
6798 }
6799 s_goto(sc,OP_RDSEXPR);
6800 case TOK_COMMA:
6801 s_save(sc,OP_RDUNQUOTE, sc->NIL, sc->NIL);
6802 sc->tok = token(sc);
6803 s_goto(sc,OP_RDSEXPR);
6804 case TOK_ATMARK:
6805 s_save(sc,OP_RDUQTSP, sc->NIL, sc->NIL);
6806 sc->tok = token(sc);
6807 s_goto(sc,OP_RDSEXPR);
6808 case TOK_ATOM:
6809 s_return(sc,mk_atom(sc, readstr_upto(sc, DELIMITERS)));
6810 case TOK_DQUOTE:
6811 x=readstrexp(sc);
6812 if(x==sc->F) {
6813 Error_0(sc,"Error reading string");
6814 }
6815 setimmutable(x);
6816 s_return(sc,x);
6817 case TOK_SHARP: {
6818 pointer f=find_slot_in_env(sc,sc->envir,sc->SHARP_HOOK,1);
6819 if(f==sc->NIL) {
6820 Error_0(sc,"undefined sharp expression");
6821 } else {
6822 sc->code=cons(sc,slot_value_in_env(f),sc->NIL);
6823 s_goto(sc,OP_EVAL);
6824 }
6825 }
6826 case TOK_SHARP_CONST:
6827 if ((x = mk_sharp_const(sc, readstr_upto(sc, DELIMITERS))) == sc->NIL) {
6828 Error_0(sc,"undefined sharp expression");
6829 } else {
6830 s_return(sc,x);
6831 }
6832 default:
6833 Error_0(sc,"syntax error: illegal token");
6834 }
6835 break;
6836
6837 case OP_RDLIST: {
6838 sc->args = cons(sc, sc->value, sc->args);
6839 sc->tok = token(sc);
6840 /* We now skip comments in the scanner
6841 while (sc->tok == TOK_COMMENT) {
6842 int c;
6843 while ((c=inchar(sc)) != '\n' && c!=EOF)
6844 ;
6845 sc->tok = token(sc);
6846 }
6847 */
6848 if (sc->tok == TOK_EOF)
6849 { s_return(sc,sc->EOF_OBJ); }
6850 else if (sc->tok == TOK_RPAREN) {
6851 int c = inchar(sc);
6852 if (c != '\n')
6853 backchar(sc,c);
6854 #if SHOW_ERROR_LINE
6855 else if (sc->load_stack[sc->file_i].kind & port_file)
6856 sc->load_stack[sc->file_i].rep.stdio.curr_line++;
6857 #endif
6858 sc->nesting_stack[sc->file_i]--;
6859 s_return(sc,reverse_in_place(sc, sc->NIL, sc->args));
6860 } else if (sc->tok == TOK_DOT) {
6861 s_save(sc,OP_RDDOT, sc->args, sc->NIL);
6862 sc->tok = token(sc);
6863 s_goto(sc,OP_RDSEXPR);
6864 } else {
6865 s_save(sc,OP_RDLIST, sc->args, sc->NIL);;
6866 s_goto(sc,OP_RDSEXPR);
6867 }
6868 }
6869
6870 case OP_RDDOT:
6871 if (token(sc) != TOK_RPAREN) {
6872 Error_0(sc,"syntax error: illegal dot expression");
6873 } else {
6874 sc->nesting_stack[sc->file_i]--;
6875 s_return(sc,reverse_in_place(sc, sc->value, sc->args));
6876 }
6877
6878 case OP_RDQUOTE:
6879 s_return(sc,cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL)));
6880
6881 case OP_RDQQUOTE:
6882 s_return(sc,cons(sc, sc->QQUOTE, cons(sc, sc->value, sc->NIL)));
6883
6884 case OP_RDQQUOTEVEC:
6885 s_return(sc,cons(sc, mk_symbol(sc,"apply"),
6886 cons(sc, mk_symbol(sc,"vector"),
6887 cons(sc,cons(sc, sc->QQUOTE,
6888 cons(sc,sc->value,sc->NIL)),
6889 sc->NIL))));
6890
6891 case OP_RDUNQUOTE:
6892 s_return(sc,cons(sc, sc->UNQUOTE, cons(sc, sc->value, sc->NIL)));
6893
6894 case OP_RDUQTSP:
6895 s_return(sc,cons(sc, sc->UNQUOTESP, cons(sc, sc->value, sc->NIL)));
6896
6897 case OP_RDVEC:
6898 /*sc->code=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
6899 s_goto(sc,OP_EVAL); Cannot be quoted*/
6900 /*x=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
6901 s_return(sc,x); Cannot be part of pairs*/
6902 /*sc->code=mk_proc(sc,OP_VECTOR);
6903 sc->args=sc->value;
6904 s_goto(sc,OP_APPLY);*/
6905 sc->args=sc->value;
6906 s_goto(sc,OP_VECTOR);
6907
6908 /* ========== printing part ========== */
6909 case OP_P0LIST:
6910 if(is_vector(sc->args)) {
6911 putstr(sc,"#(");
6912 sc->args=cons(sc,sc->args,mk_integer(sc,0));
6913 s_goto(sc,OP_PVECFROM);
6914 } else if(is_environment(sc->args)) {
6915 putstr(sc,"#<ENVIRONMENT>");
6916 s_return(sc,sc->T);
6917 } else if (!is_pair(sc->args)) {
6918 printatom(sc, sc->args, sc->print_flag);
6919 s_return(sc,sc->T);
6920 } else if (car(sc->args) == sc->QUOTE && ok_abbrev(cdr(sc->args))) {
6921 putstr(sc, "'");
6922 sc->args = cadr(sc->args);
6923 s_goto(sc,OP_P0LIST);
6924 } else if (car(sc->args) == sc->QQUOTE && ok_abbrev(cdr(sc->args))) {
6925 putstr(sc, "`");
6926 sc->args = cadr(sc->args);
6927 s_goto(sc,OP_P0LIST);
6928 } else if (car(sc->args) == sc->UNQUOTE && ok_abbrev(cdr(sc->args))) {
6929 putstr(sc, ",");
6930 sc->args = cadr(sc->args);
6931 s_goto(sc,OP_P0LIST);
6932 } else if (car(sc->args) == sc->UNQUOTESP && ok_abbrev(cdr(sc->args))) {
6933 putstr(sc, ",@");
6934 sc->args = cadr(sc->args);
6935 s_goto(sc,OP_P0LIST);
6936 } else {
6937 putstr(sc, "(");
6938 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
6939 sc->args = car(sc->args);
6940 s_goto(sc,OP_P0LIST);
6941 }
6942
6943 case OP_P1LIST:
6944 if (is_pair(sc->args)) {
6945 s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
6946 putstr(sc, " ");
6947 sc->args = car(sc->args);
6948 s_goto(sc,OP_P0LIST);
6949 } else if(is_vector(sc->args)) {
6950 s_save(sc,OP_P1LIST,sc->NIL,sc->NIL);
6951 putstr(sc, " . ");
6952 s_goto(sc,OP_P0LIST);
6953 } else {
6954 if (sc->args != sc->NIL) {
6955 putstr(sc, " . ");
6956 printatom(sc, sc->args, sc->print_flag);
6957 }
6958 putstr(sc, ")");
6959 s_return(sc,sc->T);
6960 }
6961 case OP_PVECFROM: {
6962 int i=ivalue_unchecked(cdr(sc->args));
6963 pointer vec=car(sc->args);
6964 int len=ivalue_unchecked(vec);
6965 if(i==len) {
6966 putstr(sc,")");
6967 s_return(sc,sc->T);
6968 } else {
6969 pointer elem=vector_elem(vec,i);
6970 ivalue_unchecked(cdr(sc->args))=i+1;
6971 s_save(sc,OP_PVECFROM, sc->args, sc->NIL);
6972 sc->args=elem;
6973 if (i > 0)
6974 putstr(sc," ");
6975 s_goto(sc,OP_P0LIST);
6976 }
6977 }
6978
6979 default:
6980 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
6981 Error_0(sc,sc->strbuff);
6982
6983 }
6984 return sc->T;
6985 }
6986
6987 static pointer opexe_6(scheme *sc, enum scheme_opcodes op) {
6988 pointer x, y;
6989 long v;
6990
6991 switch (op) {
6992 case OP_LIST_LENGTH: /* length */ /* a.k */
6993 v=list_length(sc,car(sc->args));
6994 if(v<0) {
6995 Error_1(sc,"length: not a list:",car(sc->args));
6996 }
6997 s_return(sc,mk_integer(sc, v));
6998
6999 case OP_ASSQ: /* assq */ /* a.k */
7000 x = car(sc->args);
7001 for (y = cadr(sc->args); is_pair(y); y = cdr(y)) {
7002 if (!is_pair(car(y))) {
7003 Error_0(sc,"unable to handle non pair element");
7004 }
7005 if (x == caar(y))
7006 break;
7007 }
7008 if (is_pair(y)) {
7009 s_return(sc,car(y));
7010 } else {
7011 s_return(sc,sc->F);
7012 }
7013
7014
7015 case OP_GET_CLOSURE: /* get-closure-code */ /* a.k */
7016 sc->args = car(sc->args);
7017 if (sc->args == sc->NIL) {
7018 s_return(sc,sc->F);
7019 } else if (is_closure(sc->args)) {
7020 s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value)));
7021 } else if (is_macro(sc->args)) {
7022 s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value)));
7023 } else {
7024 s_return(sc,sc->F);
7025 }
7026 case OP_CLOSUREP: /* closure? */
7027 /*
7028 * Note, macro object is also a closure.
7029 * Therefore, (closure? <#MACRO>) ==> #t
7030 */
7031 s_retbool(is_closure(car(sc->args)));
7032 case OP_MACROP: /* macro? */
7033 s_retbool(is_macro(car(sc->args)));
7034 default:
7035 snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
7036 Error_0(sc,sc->strbuff);
7037 }
7038 return sc->T; /* NOTREACHED */
7039 }
7040
7041 typedef pointer (*dispatch_func)(scheme *, enum scheme_opcodes);
7042
7043 typedef int (*test_predicate)(pointer);
7044 static int is_any(pointer p) { return 1;}
7045
7046 static int is_nonneg(pointer p) {
7047 return ivalue(p)>=0 && is_integer(p);
7048 }
7049
7050 /* Correspond carefully with following defines! */
7051 static struct {
7052 test_predicate fct;
7053 const char *kind;
7054 } tests[]={
7055 {0,0}, /* unused */
7056 {is_any, 0},
7057 {is_string, "string"},
7058 {is_symbol, "symbol"},
7059 {is_port, "port"},
7060 {is_inport,"input port"},
7061 {is_outport,"output port"},
7062 {is_environment, "environment"},
7063 {is_pair, "pair"},
7064 {0, "pair or '()"},
7065 {is_character, "character"},
7066 {is_vector, "vector"},
7067 {is_number, "number"},
7068 {is_integer, "integer"},
7069 {is_nonneg, "non-negative integer"}
7070 };
7071
7072 #define TST_NONE 0
7073 #define TST_ANY "\001"
7074 #define TST_STRING "\002"
7075 #define TST_SYMBOL "\003"
7076 #define TST_PORT "\004"
7077 #define TST_INPORT "\005"
7078 #define TST_OUTPORT "\006"
7079 #define TST_ENVIRONMENT "\007"
7080 #define TST_PAIR "\010"
7081 #define TST_LIST "\011"
7082 #define TST_CHAR "\012"
7083 #define TST_VECTOR "\013"
7084 #define TST_NUMBER "\014"
7085 #define TST_INTEGER "\015"
7086 #define TST_NATURAL "\016"
7087
7088 typedef struct {
7089 dispatch_func func;
7090 char *name;
7091 int min_arity;
7092 int max_arity;
7093 char *arg_tests_encoding;
7094 } op_code_info;
7095
7096 #define INF_ARG 0xffff
7097
7098 static op_code_info dispatch_table[]= {
7099 #define _OP_DEF(A,B,C,D,E,OP) {A,B,C,D,E},
7100 #include "opdefines.h"
7101 { 0 }
7102 };
7103
7104 static const char *procname(pointer x) {
7105 int n=procnum(x);
7106 const char *name=dispatch_table[n].name;
7107 if(name==0) {
7108 name="ILLEGAL!";
7109 }
7110 return name;
7111 }
7112
7113 /* kernel of this interpreter */
7114 static void Eval_Cycle(scheme *sc, enum scheme_opcodes op) {
7115 sc->op = op;
7116 for (;;) {
7117 op_code_info *pcd=dispatch_table+sc->op;
7118 if (pcd->name!=0) { /* if built-in function, check arguments */
7119 char msg[STRBUFFSIZE];
7120 int ok=1;
7121 int n=list_length(sc,sc->args);
7122
7123 /* Check number of arguments */
7124 if(n<pcd->min_arity) {
7125 ok=0;
7126 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
7127 pcd->name,
7128 pcd->min_arity==pcd->max_arity?"":" at least",
7129 pcd->min_arity);
7130 }
7131 if(ok && n>pcd->max_arity) {
7132 ok=0;
7133 snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
7134 pcd->name,
7135 pcd->min_arity==pcd->max_arity?"":" at most",
7136 pcd->max_arity);
7137 }
7138 if(ok) {
7139 if(pcd->arg_tests_encoding!=0) {
7140 int i=0;
7141 int j;
7142 const char *t=pcd->arg_tests_encoding;
7143 pointer arglist=sc->args;
7144 do {
7145 pointer arg=car(arglist);
7146 j=(int)t[0];
7147 if(j==TST_LIST[0]) {
7148 if(arg!=sc->NIL && !is_pair(arg)) break;
7149 } else {
7150 if(!tests[j].fct(arg)) break;
7151 }
7152
7153 if(t[1]!=0) {/* last test is replicated as necessary */
7154 t++;
7155 }
7156 arglist=cdr(arglist);
7157 i++;
7158 } while(i<n);
7159 if(i<n) {
7160 ok=0;
7161 snprintf(msg, STRBUFFSIZE, "%s: argument %d must be: %s",
7162 pcd->name,
7163 i+1,
7164 tests[j].kind);
7165 }
7166 }
7167 }
7168 if(!ok) {
7169 if(_Error_1(sc,msg,0)==sc->NIL) {
7170 return;
7171 }
7172 pcd=dispatch_table+sc->op;
7173 }
7174 }
7175 ok_to_freely_gc(sc);
7176 if (pcd->func(sc, (enum scheme_opcodes)sc->op) == sc->NIL) {
7177 return;
7178 }
7179 if(sc->no_memory) {
7180 fprintf(stderr,"No memory!\n");
7181 return;
7182 }
7183 }
7184 }
7185
7186 /* ========== Initialization of internal keywords ========== */
7187
7188 static void assign_syntax(scheme *sc, char *name) {
7189 pointer x;
7190
7191 x = oblist_add_by_name(sc, name);
7192 typeflag(x) |= T_SYNTAX;
7193 }
7194
7195 static void assign_proc(scheme *sc, enum scheme_opcodes op, char *name) {
7196 pointer x, y;
7197
7198 x = mk_symbol(sc, name);
7199 y = mk_proc(sc,op);
7200 new_slot_in_env(sc, x, y);
7201 }
7202
7203 static pointer mk_proc(scheme *sc, enum scheme_opcodes op) {
7204 pointer y;
7205
7206 y = get_cell(sc, sc->NIL, sc->NIL);
7207 typeflag(y) = (T_PROC | T_ATOM);
7208 ivalue_unchecked(y) = (long) op;
7209 set_num_integer(y);
7210 return y;
7211 }
7212
7213 /* Hard-coded for the given keywords. Remember to rewrite if more are added! */
7214 static int syntaxnum(pointer p) {
7215 const char *s=strvalue(car(p));
7216 switch(strlength(car(p))) {
7217 case 2:
7218 if(s[0]=='i') return OP_IF0; /* if */
7219 else return OP_OR0; /* or */
7220 case 3:
7221 if(s[0]=='a') return OP_AND0; /* and */
7222 else return OP_LET0; /* let */
7223 case 4:
7224 switch(s[3]) {
7225 case 'e': return OP_CASE0; /* case */
7226 case 'd': return OP_COND0; /* cond */
7227 case '*': return OP_LET0AST; /* let* */
7228 default: return OP_SET0; /* set! */
7229 }
7230 case 5:
7231 switch(s[2]) {
7232 case 'g': return OP_BEGIN; /* begin */
7233 case 'l': return OP_DELAY; /* delay */
7234 case 'c': return OP_MACRO0; /* macro */
7235 default: return OP_QUOTE; /* quote */
7236 }
7237 case 6:
7238 switch(s[2]) {
7239 case 'm': return OP_LAMBDA; /* lambda */
7240 case 'f': return OP_DEF0; /* define */
7241 default: return OP_LET0REC; /* letrec */
7242 }
7243 default:
7244 return OP_C0STREAM; /* cons-stream */
7245 }
7246 }
7247
7248 /* initialization of TinyScheme */
7249 #if USE_INTERFACE
7250 INTERFACE static pointer s_cons(scheme *sc, pointer a, pointer b) {
7251 return cons(sc,a,b);
7252 }
7253 INTERFACE static pointer s_immutable_cons(scheme *sc, pointer a, pointer b) {
7254 return immutable_cons(sc,a,b);
7255 }
7256
7257 static struct scheme_interface vtbl ={
7258 scheme_define,
7259 s_cons,
7260 s_immutable_cons,
7261 reserve_cells,
7262 mk_integer,
7263 mk_real,
7264 mk_symbol,
7265 gensym,
7266 mk_string,
7267 mk_counted_string,
7268 mk_character,
7269 mk_vector,
7270 mk_foreign_func,
7271 putstr,
7272 putcharacter,
7273
7274 is_string,
7275 string_value,
7276 is_number,
7277 nvalue,
7278 ivalue,
7279 rvalue,
7280 is_integer,
7281 is_real,
7282 is_character,
7283 charvalue,
7284 is_list,
7285 is_vector,
7286 list_length,
7287 ivalue,
7288 fill_vector,
7289 vector_elem,
7290 set_vector_elem,
7291 is_port,
7292 is_pair,
7293 pair_car,
7294 pair_cdr,
7295 set_car,
7296 set_cdr,
7297
7298 is_symbol,
7299 symname,
7300
7301 is_syntax,
7302 is_proc,
7303 is_foreign,
7304 syntaxname,
7305 is_closure,
7306 is_macro,
7307 closure_code,
7308 closure_env,
7309
7310 is_continuation,
7311 is_promise,
7312 is_environment,
7313 is_immutable,
7314 setimmutable,
7315
7316 scheme_load_file,
7317 scheme_load_string
7318 };
7319 #endif
7320
7321 scheme *scheme_init_new() {
7322 scheme *sc=(scheme*)malloc(sizeof(scheme));
7323 if(!scheme_init(sc)) {
7324 free(sc);
7325 return 0;
7326 } else {
7327 return sc;
7328 }
7329 }
7330
7331 scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free) {
7332 scheme *sc=(scheme*)malloc(sizeof(scheme));
7333 if(!scheme_init_custom_alloc(sc,malloc,free)) {
7334 free(sc);
7335 return 0;
7336 } else {
7337 return sc;
7338 }
7339 }
7340
7341
7342 int scheme_init(scheme *sc) {
7343 return scheme_init_custom_alloc(sc,malloc,free);
7344 }
7345
7346 int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
7347 int i, n=sizeof(dispatch_table)/sizeof(dispatch_table[0]);
7348 pointer x;
7349
7350 num_zero.is_fixnum=1;
7351 num_zero.value.ivalue=0;
7352 num_one.is_fixnum=1;
7353 num_one.value.ivalue=1;
7354
7355 #if USE_INTERFACE
7356 sc->vptr=&vtbl;
7357 #endif
7358 sc->gensym_cnt=0;
7359 sc->malloc=malloc;
7360 sc->free=free;
7361 sc->last_cell_seg = -1;
7362 sc->sink = &sc->_sink;
7363 sc->NIL = &sc->_NIL;
7364 sc->T = &sc->_HASHT;
7365 sc->F = &sc->_HASHF;
7366 sc->EOF_OBJ=&sc->_EOF_OBJ;
7367 sc->free_cell = &sc->_NIL;
7368 sc->fcells = 0;
7369 sc->no_memory=0;
7370 sc->inport=sc->NIL;
7371 sc->outport=sc->NIL;
7372 sc->save_inport=sc->NIL;
7373 sc->loadport=sc->NIL;
7374 sc->nesting=0;
7375 sc->interactive_repl=0;
7376
7377 if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
7378 sc->no_memory=1;
7379 return 0;
7380 }
7381 sc->gc_verbose = 0;
7382 dump_stack_initialize(sc);
7383 sc->code = sc->NIL;
7384 sc->tracing=0;
7385
7386 /* init sc->NIL */
7387 typeflag(sc->NIL) = (T_ATOM | MARK);
7388 car(sc->NIL) = cdr(sc->NIL) = sc->NIL;
7389 /* init T */
7390 typeflag(sc->T) = (T_ATOM | MARK);
7391 car(sc->T) = cdr(sc->T) = sc->T;
7392 /* init F */
7393 typeflag(sc->F) = (T_ATOM | MARK);
7394 car(sc->F) = cdr(sc->F) = sc->F;
7395 /* init sink */
7396 typeflag(sc->sink) = (T_PAIR | MARK);
7397 car(sc->sink) = sc->NIL;
7398 /* init c_nest */
7399 sc->c_nest = sc->NIL;
7400
7401 sc->oblist = oblist_initial_value(sc);
7402 /* init global_env */
7403 new_frame_in_env(sc, sc->NIL);
7404 sc->global_env = sc->envir;
7405 /* init else */
7406 x = mk_symbol(sc,"else");
7407 new_slot_in_env(sc, x, sc->T);
7408
7409 assign_syntax(sc, "lambda");
7410 assign_syntax(sc, "quote");
7411 assign_syntax(sc, "define");
7412 assign_syntax(sc, "if");
7413 assign_syntax(sc, "begin");
7414 assign_syntax(sc, "set!");
7415 assign_syntax(sc, "let");
7416 assign_syntax(sc, "let*");
7417 assign_syntax(sc, "letrec");
7418 assign_syntax(sc, "cond");
7419 assign_syntax(sc, "delay");
7420 assign_syntax(sc, "and");
7421 assign_syntax(sc, "or");
7422 assign_syntax(sc, "cons-stream");
7423 assign_syntax(sc, "macro");
7424 assign_syntax(sc, "case");
7425
7426 for(i=0; i<n; i++) {
7427 if(dispatch_table[i].name!=0) {
7428 assign_proc(sc, (enum scheme_opcodes)i, dispatch_table[i].name);
7429 }
7430 }
7431
7432 /* initialization of global pointers to special symbols */
7433 sc->LAMBDA = mk_symbol(sc, "lambda");
7434 sc->QUOTE = mk_symbol(sc, "quote");
7435 sc->QQUOTE = mk_symbol(sc, "quasiquote");
7436 sc->UNQUOTE = mk_symbol(sc, "unquote");
7437 sc->UNQUOTESP = mk_symbol(sc, "unquote-splicing");
7438 sc->FEED_TO = mk_symbol(sc, "=>");
7439 sc->COLON_HOOK = mk_symbol(sc,"*colon-hook*");
7440 sc->ERROR_HOOK = mk_symbol(sc, "*error-hook*");
7441 sc->SHARP_HOOK = mk_symbol(sc, "*sharp-hook*");
7442 sc->COMPILE_HOOK = mk_symbol(sc, "*compile-hook*");
7443
7444 return !sc->no_memory;
7445 }
7446
7447 void scheme_set_input_port_file(scheme *sc, FILE *fin) {
7448 sc->inport=port_from_file(sc,fin,port_input);
7449 }
7450
7451 void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end) {
7452 sc->inport=port_from_string(sc,start,past_the_end,port_input);
7453 }
7454
7455 void scheme_set_output_port_file(scheme *sc, FILE *fout) {
7456 sc->outport=port_from_file(sc,fout,port_output);
7457 }
7458
7459 void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end) {
7460 sc->outport=port_from_string(sc,start,past_the_end,port_output);
7461 }
7462
7463 void scheme_set_external_data(scheme *sc, void *p) {
7464 sc->ext_data=p;
7465 }
7466
7467 void scheme_deinit(scheme *sc) {
7468 int i;
7469
7470 #if SHOW_ERROR_LINE
7471 char *fname;
7472 #endif
7473
7474 sc->oblist=sc->NIL;
7475 sc->global_env=sc->NIL;
7476 dump_stack_free(sc);
7477 sc->envir=sc->NIL;
7478 sc->code=sc->NIL;
7479 sc->args=sc->NIL;
7480 sc->value=sc->NIL;
7481 if(is_port(sc->inport)) {
7482 typeflag(sc->inport) = T_ATOM;
7483 }
7484 sc->inport=sc->NIL;
7485 sc->outport=sc->NIL;
7486 if(is_port(sc->save_inport)) {
7487 typeflag(sc->save_inport) = T_ATOM;
7488 }
7489 sc->save_inport=sc->NIL;
7490 if(is_port(sc->loadport)) {
7491 typeflag(sc->loadport) = T_ATOM;
7492 }
7493 sc->loadport=sc->NIL;
7494 sc->gc_verbose=0;
7495 gc(sc,sc->NIL,sc->NIL);
7496
7497 for(i=0; i<=sc->last_cell_seg; i++) {
7498 sc->free(sc->alloc_seg[i]);
7499 }
7500
7501 #if SHOW_ERROR_LINE
7502 for(i=0; i<=sc->file_i; i++) {
7503 if (sc->load_stack[i].kind & port_file) {
7504 fname = sc->load_stack[i].rep.stdio.filename;
7505 if(fname)
7506 sc->free(fname);
7507 }
7508 }
7509 #endif
7510 }
7511
7512 void scheme_load_file(scheme *sc, FILE *fin)
7513 { scheme_load_named_file(sc,fin,0); }
7514
7515 void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename) {
7516 dump_stack_reset(sc);
7517 sc->envir = sc->global_env;
7518 sc->file_i=0;
7519 sc->load_stack[0].kind=port_input|port_file;
7520 sc->load_stack[0].rep.stdio.file=fin;
7521 sc->loadport=mk_port(sc,sc->load_stack);
7522 sc->retcode=0;
7523 if(fin==stdin) {
7524 sc->interactive_repl=1;
7525 }
7526
7527 #if SHOW_ERROR_LINE
7528 sc->load_stack[0].rep.stdio.curr_line = 0;
7529 if(fin!=stdin && filename)
7530 sc->load_stack[0].rep.stdio.filename = store_string(sc, strlen(filename), filename, 0);
7531 #endif
7532
7533 sc->inport=sc->loadport;
7534 sc->args = mk_integer(sc,sc->file_i);
7535 Eval_Cycle(sc, OP_T0LVL);
7536 typeflag(sc->loadport)=T_ATOM;
7537 if(sc->retcode==0) {
7538 sc->retcode=sc->nesting!=0;
7539 }
7540 }
7541
7542 void scheme_load_string(scheme *sc, const char *cmd) {
7543 dump_stack_reset(sc);
7544 sc->envir = sc->global_env;
7545 sc->file_i=0;
7546 sc->load_stack[0].kind=port_input|port_string;
7547 sc->load_stack[0].rep.string.start=(char*)cmd; /* This func respects const */
7548 sc->load_stack[0].rep.string.past_the_end=(char*)cmd+strlen(cmd);
7549 sc->load_stack[0].rep.string.curr=(char*)cmd;
7550 sc->loadport=mk_port(sc,sc->load_stack);
7551 sc->retcode=0;
7552 sc->interactive_repl=0;
7553 sc->inport=sc->loadport;
7554 sc->args = mk_integer(sc,sc->file_i);
7555 Eval_Cycle(sc, OP_T0LVL);
7556 typeflag(sc->loadport)=T_ATOM;
7557 if(sc->retcode==0) {
7558 sc->retcode=sc->nesting!=0;
7559 }
7560 }
7561
7562 void scheme_define(scheme *sc, pointer envir, pointer symbol, pointer value) {
7563 pointer x;
7564
7565 x=find_slot_in_env(sc,envir,symbol,0);
7566 if (x != sc->NIL) {
7567 set_slot_in_env(sc, x, value);
7568 } else {
7569 new_slot_spec_in_env(sc, envir, symbol, value);
7570 }
7571 }
7572
7573 #if !STANDALONE
7574 void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr)
7575 {
7576 scheme_define(sc,
7577 sc->global_env,
7578 mk_symbol(sc,sr->name),
7579 mk_foreign_func(sc, sr->f));
7580 }
7581
7582 void scheme_register_foreign_func_list(scheme * sc,
7583 scheme_registerable * list,
7584 int count)
7585 {
7586 int i;
7587 for(i = 0; i < count; i++)
7588 {
7589 scheme_register_foreign_func(sc, list + i);
7590 }
7591 }
7592
7593 pointer scheme_apply0(scheme *sc, const char *procname)
7594 { return scheme_eval(sc, cons(sc,mk_symbol(sc,procname),sc->NIL)); }
7595
7596 void save_from_C_call(scheme *sc)
7597 {
7598 pointer saved_data =
7599 cons(sc,
7600 car(sc->sink),
7601 cons(sc,
7602 sc->envir,
7603 sc->dump));
7604 /* Push */
7605 sc->c_nest = cons(sc, saved_data, sc->c_nest);
7606 /* Truncate the dump stack so TS will return here when done, not
7607 directly resume pre-C-call operations. */
7608 dump_stack_reset(sc);
7609 }
7610 void restore_from_C_call(scheme *sc)
7611 {
7612 car(sc->sink) = caar(sc->c_nest);
7613 sc->envir = cadar(sc->c_nest);
7614 sc->dump = cdr(cdar(sc->c_nest));
7615 /* Pop */
7616 sc->c_nest = cdr(sc->c_nest);
7617 }
7618
7619 /* "func" and "args" are assumed to be already eval'ed. */
7620 pointer scheme_call(scheme *sc, pointer func, pointer args)
7621 {
7622 int old_repl = sc->interactive_repl;
7623 sc->interactive_repl = 0;
7624 save_from_C_call(sc);
7625 sc->envir = sc->global_env;
7626 sc->args = args;
7627 sc->code = func;
7628 sc->retcode = 0;
7629 Eval_Cycle(sc, OP_APPLY);
7630 sc->interactive_repl = old_repl;
7631 restore_from_C_call(sc);
7632 return sc->value;
7633 }
7634
7635 pointer scheme_eval(scheme *sc, pointer obj)
7636 {
7637 int old_repl = sc->interactive_repl;
7638 sc->interactive_repl = 0;
7639 save_from_C_call(sc);
7640 sc->args = sc->NIL;
7641 sc->code = obj;
7642 sc->retcode = 0;
7643 Eval_Cycle(sc, OP_EVAL);
7644 sc->interactive_repl = old_repl;
7645 restore_from_C_call(sc);
7646 return sc->value;
7647 }
7648
7649
7650 #endif
7651
7652 /* ========== Main ========== */
7653
7654 #if STANDALONE
7655
7656 #if defined(__APPLE__) && !defined (OSX)
7657 int main()
7658 {
7659 extern MacTS_main(int argc, char **argv);
7660 char** argv;
7661 int argc = ccommand(&argv);
7662 MacTS_main(argc,argv);
7663 return 0;
7664 }
7665 int MacTS_main(int argc, char **argv) {
7666 #else
7667 int main(int argc, char **argv) {
7668 #endif
7669 scheme sc;
7670 FILE *fin;
7671 char *file_name=InitFile;
7672 int retcode;
7673 int isfile=1;
7674
7675 if(argc==1) {
7676 printf(banner);
7677 }
7678 if(argc==2 && strcmp(argv[1],"-?")==0) {
7679 printf("Usage: tinyscheme -?\n");
7680 printf("or: tinyscheme [<file1> <file2> ...]\n");
7681 printf("followed by\n");
7682 printf(" -1 <file> [<arg1> <arg2> ...]\n");
7683 printf(" -c <Scheme commands> [<arg1> <arg2> ...]\n");
7684 printf("assuming that the executable is named tinyscheme.\n");
7685 printf("Use - as filename for stdin.\n");
7686 return 1;
7687 }
7688 if(!scheme_init(&sc)) {
7689 fprintf(stderr,"Could not initialize!\n");
7690 return 2;
7691 }
7692 scheme_set_input_port_file(&sc, stdin);
7693 scheme_set_output_port_file(&sc, stdout);
7694 #if USE_DL
7695 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"load-extension"),mk_foreign_func(&sc, scm_load_ext));
7696 #endif
7697 argv++;
7698 if(access(file_name,0)!=0) {
7699 char *p=getenv("TINYSCHEMEINIT");
7700 if(p!=0) {
7701 file_name=p;
7702 }
7703 }
7704 do {
7705 if(strcmp(file_name,"-")==0) {
7706 fin=stdin;
7707 } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0) {
7708 pointer args=sc.NIL;
7709 isfile=file_name[1]=='1';
7710 file_name=*argv++;
7711 if(strcmp(file_name,"-")==0) {
7712 fin=stdin;
7713 } else if(isfile) {
7714 fin=fopen(file_name,"r");
7715 }
7716 for(;*argv;argv++) {
7717 pointer value=mk_string(&sc,*argv);
7718 args=cons(&sc,value,args);
7719 }
7720 args=reverse_in_place(&sc,sc.NIL,args);
7721 scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args);
7722
7723 } else {
7724 fin=fopen(file_name,"r");
7725 }
7726 if(isfile && fin==0) {
7727 fprintf(stderr,"Could not open file %s\n",file_name);
7728 } else {
7729 if(isfile) {
7730 scheme_load_named_file(&sc,fin,file_name);
7731 } else {
7732 scheme_load_string(&sc,file_name);
7733 }
7734 if(!isfile || fin!=stdin) {
7735 if(sc.retcode!=0) {
7736 fprintf(stderr,"Errors encountered reading %s\n",file_name);
7737 }
7738 if(isfile) {
7739 fclose(fin);
7740 }
7741 }
7742 }
7743 file_name=*argv++;
7744 } while(file_name!=0);
7745 if(argc==1) {
7746 scheme_load_named_file(&sc,stdin,0);
7747 }
7748 retcode=sc.retcode;
7749 scheme_deinit(&sc);
7750
7751 return retcode;
7752 }
7753
7754 #endif
7755
7756 /*
7757 Local variables:
7758 c-file-style: "k&r"
7759 End:
7760 */
-(0 . 0)(1 . 255)
7765 /* SCHEME.H */
7766
7767 #ifndef _SCHEME_H
7768 #define _SCHEME_H
7769
7770 #include <stdio.h>
7771
7772 #ifdef __cplusplus
7773 extern "C" {
7774 #endif
7775
7776 /*
7777 * Default values for #define'd symbols
7778 */
7779 #ifndef STANDALONE /* If used as standalone interpreter */
7780 # define STANDALONE 1
7781 #endif
7782
7783 #ifndef _MSC_VER
7784 # define USE_STRCASECMP 1
7785 # ifndef USE_STRLWR
7786 # define USE_STRLWR 1
7787 # endif
7788 # define SCHEME_EXPORT
7789 #else
7790 # define USE_STRCASECMP 0
7791 # define USE_STRLWR 0
7792 # ifdef _SCHEME_SOURCE
7793 # define SCHEME_EXPORT __declspec(dllexport)
7794 # else
7795 # define SCHEME_EXPORT __declspec(dllimport)
7796 # endif
7797 #endif
7798
7799 #if USE_NO_FEATURES
7800 # define USE_MATH 0
7801 # define USE_CHAR_CLASSIFIERS 0
7802 # define USE_ASCII_NAMES 0
7803 # define USE_STRING_PORTS 0
7804 # define USE_ERROR_HOOK 0
7805 # define USE_TRACING 0
7806 # define USE_COLON_HOOK 0
7807 # define USE_DL 0
7808 # define USE_PLIST 0
7809 #endif
7810
7811 /*
7812 * Leave it defined if you want continuations, and also for the Sharp Zaurus.
7813 * Undefine it if you only care about faster speed and not strict Scheme compatibility.
7814 */
7815 #define USE_SCHEME_STACK
7816
7817 #if USE_DL
7818 # define USE_INTERFACE 1
7819 #endif
7820
7821
7822 #ifndef USE_MATH /* If math support is needed */
7823 # define USE_MATH 1
7824 #endif
7825
7826 #ifndef USE_CHAR_CLASSIFIERS /* If char classifiers are needed */
7827 # define USE_CHAR_CLASSIFIERS 1
7828 #endif
7829
7830 #ifndef USE_ASCII_NAMES /* If extended escaped characters are needed */
7831 # define USE_ASCII_NAMES 1
7832 #endif
7833
7834 #ifndef USE_STRING_PORTS /* Enable string ports */
7835 # define USE_STRING_PORTS 1
7836 #endif
7837
7838 #ifndef USE_TRACING
7839 # define USE_TRACING 1
7840 #endif
7841
7842 #ifndef USE_PLIST
7843 # define USE_PLIST 0
7844 #endif
7845
7846 /* To force system errors through user-defined error handling (see *error-hook*) */
7847 #ifndef USE_ERROR_HOOK
7848 # define USE_ERROR_HOOK 1
7849 #endif
7850
7851 #ifndef USE_COLON_HOOK /* Enable qualified qualifier */
7852 # define USE_COLON_HOOK 1
7853 #endif
7854
7855 #ifndef USE_STRCASECMP /* stricmp for Unix */
7856 # define USE_STRCASECMP 0
7857 #endif
7858
7859 #ifndef USE_STRLWR
7860 # define USE_STRLWR 1
7861 #endif
7862
7863 #ifndef STDIO_ADDS_CR /* Define if DOS/Windows */
7864 # define STDIO_ADDS_CR 0
7865 #endif
7866
7867 #ifndef INLINE
7868 # define INLINE
7869 #endif
7870
7871 #ifndef USE_INTERFACE
7872 # define USE_INTERFACE 0
7873 #endif
7874
7875 #ifndef SHOW_ERROR_LINE /* Show error line in file */
7876 # define SHOW_ERROR_LINE 1
7877 #endif
7878
7879 typedef struct scheme scheme;
7880 typedef struct cell *pointer;
7881
7882 typedef void * (*func_alloc)(size_t);
7883 typedef void (*func_dealloc)(void *);
7884
7885 /* num, for generic arithmetic */
7886 typedef struct num {
7887 char is_fixnum;
7888 union {
7889 long ivalue;
7890 double rvalue;
7891 } value;
7892 } num;
7893
7894 SCHEME_EXPORT scheme *scheme_init_new();
7895 SCHEME_EXPORT scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free);
7896 SCHEME_EXPORT int scheme_init(scheme *sc);
7897 SCHEME_EXPORT int scheme_init_custom_alloc(scheme *sc, func_alloc, func_dealloc);
7898 SCHEME_EXPORT void scheme_deinit(scheme *sc);
7899 void scheme_set_input_port_file(scheme *sc, FILE *fin);
7900 void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end);
7901 SCHEME_EXPORT void scheme_set_output_port_file(scheme *sc, FILE *fin);
7902 void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end);
7903 SCHEME_EXPORT void scheme_load_file(scheme *sc, FILE *fin);
7904 SCHEME_EXPORT void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename);
7905 SCHEME_EXPORT void scheme_load_string(scheme *sc, const char *cmd);
7906 SCHEME_EXPORT pointer scheme_apply0(scheme *sc, const char *procname);
7907 SCHEME_EXPORT pointer scheme_call(scheme *sc, pointer func, pointer args);
7908 SCHEME_EXPORT pointer scheme_eval(scheme *sc, pointer obj);
7909 void scheme_set_external_data(scheme *sc, void *p);
7910 SCHEME_EXPORT void scheme_define(scheme *sc, pointer env, pointer symbol, pointer value);
7911
7912 typedef pointer (*foreign_func)(scheme *, pointer);
7913
7914 pointer _cons(scheme *sc, pointer a, pointer b, int immutable);
7915 pointer mk_integer(scheme *sc, long num);
7916 pointer mk_real(scheme *sc, double num);
7917 pointer mk_symbol(scheme *sc, const char *name);
7918 pointer gensym(scheme *sc);
7919 pointer mk_string(scheme *sc, const char *str);
7920 pointer mk_counted_string(scheme *sc, const char *str, int len);
7921 pointer mk_empty_string(scheme *sc, int len, char fill);
7922 pointer mk_character(scheme *sc, int c);
7923 pointer mk_foreign_func(scheme *sc, foreign_func f);
7924 void putstr(scheme *sc, const char *s);
7925 int list_length(scheme *sc, pointer a);
7926 int eqv(pointer a, pointer b);
7927
7928
7929 #if USE_INTERFACE
7930 struct scheme_interface {
7931 void (*scheme_define)(scheme *sc, pointer env, pointer symbol, pointer value);
7932 pointer (*cons)(scheme *sc, pointer a, pointer b);
7933 pointer (*immutable_cons)(scheme *sc, pointer a, pointer b);
7934 pointer (*reserve_cells)(scheme *sc, int n);
7935 pointer (*mk_integer)(scheme *sc, long num);
7936 pointer (*mk_real)(scheme *sc, double num);
7937 pointer (*mk_symbol)(scheme *sc, const char *name);
7938 pointer (*gensym)(scheme *sc);
7939 pointer (*mk_string)(scheme *sc, const char *str);
7940 pointer (*mk_counted_string)(scheme *sc, const char *str, int len);
7941 pointer (*mk_character)(scheme *sc, int c);
7942 pointer (*mk_vector)(scheme *sc, int len);
7943 pointer (*mk_foreign_func)(scheme *sc, foreign_func f);
7944 void (*putstr)(scheme *sc, const char *s);
7945 void (*putcharacter)(scheme *sc, int c);
7946
7947 int (*is_string)(pointer p);
7948 char *(*string_value)(pointer p);
7949 int (*is_number)(pointer p);
7950 num (*nvalue)(pointer p);
7951 long (*ivalue)(pointer p);
7952 double (*rvalue)(pointer p);
7953 int (*is_integer)(pointer p);
7954 int (*is_real)(pointer p);
7955 int (*is_character)(pointer p);
7956 long (*charvalue)(pointer p);
7957 int (*is_list)(scheme *sc, pointer p);
7958 int (*is_vector)(pointer p);
7959 int (*list_length)(scheme *sc, pointer vec);
7960 long (*vector_length)(pointer vec);
7961 void (*fill_vector)(pointer vec, pointer elem);
7962 pointer (*vector_elem)(pointer vec, int ielem);
7963 pointer (*set_vector_elem)(pointer vec, int ielem, pointer newel);
7964 int (*is_port)(pointer p);
7965
7966 int (*is_pair)(pointer p);
7967 pointer (*pair_car)(pointer p);
7968 pointer (*pair_cdr)(pointer p);
7969 pointer (*set_car)(pointer p, pointer q);
7970 pointer (*set_cdr)(pointer p, pointer q);
7971
7972 int (*is_symbol)(pointer p);
7973 char *(*symname)(pointer p);
7974
7975 int (*is_syntax)(pointer p);
7976 int (*is_proc)(pointer p);
7977 int (*is_foreign)(pointer p);
7978 char *(*syntaxname)(pointer p);
7979 int (*is_closure)(pointer p);
7980 int (*is_macro)(pointer p);
7981 pointer (*closure_code)(pointer p);
7982 pointer (*closure_env)(pointer p);
7983
7984 int (*is_continuation)(pointer p);
7985 int (*is_promise)(pointer p);
7986 int (*is_environment)(pointer p);
7987 int (*is_immutable)(pointer p);
7988 void (*setimmutable)(pointer p);
7989 void (*load_file)(scheme *sc, FILE *fin);
7990 void (*load_string)(scheme *sc, const char *input);
7991 };
7992 #endif
7993
7994 #if !STANDALONE
7995 typedef struct scheme_registerable
7996 {
7997 foreign_func f;
7998 const char * name;
7999 }
8000 scheme_registerable;
8001
8002 void scheme_register_foreign_func_list(scheme * sc,
8003 scheme_registerable * list,
8004 int n);
8005
8006 #endif /* !STANDALONE */
8007
8008 #ifdef __cplusplus
8009 }
8010 #endif
8011
8012 #endif
8013
8014
8015 /*
8016 Local variables:
8017 c-file-style: "k&r"
8018 End:
8019 */