sllul/scm.c

4116 lines
132 KiB
C

/* KScheme, a BRUTAL EDIT of MiniScheme, by Zak Fenton MMXX
* CHANGES from Mini-Scheme 0.85 to KScheme 0.1:
* - Fixed up some old-style C code that modern/C++ compilers complain about (mostly changes to function definitions, now compiles in Visual Studio 2019)
* - Removed copyrighted parts of init.scm (assuming the sections with copyright notices aren't covered by the public domain dedication in this file)
* - Made partly embeddable (all globals now stored in a struct passed between each function, each function now has kscm_ prefix with an extra underscore
* for most of them to indicate that it's part of a private API for now)
* - Changed name (Mini-Scheme -> KScheme, as in "kernel scheme")
* - Maybe more features coming...
*
* ---------- Mini-Scheme Interpreter Version 0.85 ----------
*
* coded by Atsushi Moriwaki (11/5/1989)
*
* E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp
*
* THIS SOFTWARE IS IN THE PUBLIC DOMAIN
* ------------------------------------
* This software is completely free to copy, modify and/or re-distribute.
* But I would appreciate it if you left my name on the code as the author.
*
*/
/*--
*
* This version has been modified by Chris Pressey.
* current version is 0.85p1 (as yet unreleased)
*
* This version has been modified by R.C. Secrist.
*
* Mini-Scheme is now maintained by Akira KIDA.
*
* This is a revised and modified version by Akira KIDA.
* current version is 0.85k4 (15 May 1994)
*
* Please send suggestions, bug reports and/or requests to:
* <SDI00379@niftyserve.or.jp>
*--
*/
#define KSCM_PLATFORM_BSD
//#define KSCM_PLUSPLUS
// If KSCM_CONFIG_USE_PRECISE is defined, overflow detection will occur in basic math functions
#define KSCM_CONFIG_USE_PRECISE
// This just allows unsafe legacy C functions in Visual Studio. It should be disabled and fixed properly but not the highest priority.
#define _CRT_SECURE_NO_WARNINGS
#ifdef KSCM_PLUSPLUS
extern "C" {
#endif
/*
* Here is System declaration.
* Please define exactly one symbol in the following section.
*/
/* #define LSC */ /* LightSpeed C for Macintosh */
/* #define LSC4 */ /* THINK C version 4.0 for Macintosh */
/* #define MPW2 */ /* Macintosh Programmer's Workshop v2.0x */
/* #define KSCM_PLATFORM_BSD */ /* 4.x KSCM_PLATFORM_BSD */
/* #define MSC */ /* Microsoft C Compiler v.4.00 - 7.00 */
/* #define KSCM_PLATFORM_TURBOC */ /* Turbo C compiler v.2.0, or TC++ 1.0 */
/* #define SYSV */ /* System-V, or POSIX */
/* #define KSCM_PLATFORM_VAXC */ /* VAX/VMS KSCM_PLATFORM_VAXC 2.x or later */ /* (automatic) */
#ifdef __BORLANDC__ /* Borland C++ - MS-DOS */
#define KSCM_PLATFORM_TURBOC
#endif
#ifdef __TURBOC__ /* Turbo C V1.5 - MS-DOS */
#define KSCM_PLATFORM_TURBOC
#endif
#ifdef mips /* DECstation running OSF/1 */
#define KSCM_PLATFORM_BSD
#endif
#ifdef __osf__ /* Alpha AXP running OSF/1 */
#define KSCM_PLATFORM_BSD
#endif
#ifdef __DECC /* Alpha AXP running VMS */
#define KSCM_PLATFORM_VAXC
#endif
#ifdef _AIX /* RS/6000 running AIX */
#define KSCM_PLATFORM_BSD
#endif
/*
* Define or undefine following symbols as you need.
*/
// #define VERBOSE /* define this if you want verbose GC */
#define KSCM_CONFIG_AVOID_HACK_LOOP /* define this if your compiler is poor
* enougth to complain "do { } while (0)"
* construction.
*/
//#define KSCM_CONFIG_USE_SETJMP /* undef this if you do not want to use setjmp() */
#define KSCM_CONFIG_USE_QQUOTE /* undef this if you do not need quasiquote */
#define KSCM_CONFIG_USE_MACRO /* undef this if you do not need macro */
#define KSCM_CONFIG_USE_PERSIST /* undef this if you do not need persistence */
#define KSCM_CONFIG_USE_PRECISE /* undef this if you do not need overflow detection and precise integer size */
#define KSCM_CONFIG_USE_STRUCTS /* undef this if you do not need additional structure types (buffers & abstractions) */
#define KSCM_CONFIG_USE_FLOATS /* undef this if you do not need floating-point functionality (i.e. undefine this if you're running in kernel mode) */
#define KSCM_CONFIG_USE_OBJECTS /* undef this if you do not need object-oriented/vector features (these are handy but may complicate simple implementations) */
#define KSCM_CONFIG_USE_UTF8 /* undef this if you do not need Unicode support */
//#define KSCM_CONFIG_USE_CONSOLE /* undef this if you do not need extended console functions. */
#ifdef KSCM_CONFIG_USE_CONSOLE
#include <sys/ioctl.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#endif
#define KSCM_CONFIG_MAXLOADS 20 /* the maximum depth of the load stack */
#ifdef KSCM_CONFIG_USE_PRECISE
#include <stdint.h>
#endif
#ifdef KSCM_CONFIG_USE_QQUOTE
/*--
* If your machine can't support "forward single quotation character"
* i.e., '`', you may have trouble to use backquote.
* So use '^' in place of '`'.
*/
# define BACKQUOTE '`'
#endif
/*
* Basic memory allocation units
*/
#ifdef KSCM_PLATFORM_TURBOC /* rcs */
#define KSCM_CONFIG_CELL_SEGSIZE 2048
#define KSCM_CONFIG_CELL_NSEGMENT 100
#define KSCM_CONFIG_STR_SEGSIZE 2048
#define KSCM_CONFIG_STR_NSEGMENT 100
#else
#define KSCM_CONFIG_CELL_SEGSIZE 10000 /* # of cells in one segment */
#define KSCM_CONFIG_CELL_NSEGMENT 100 /* # of segments for cells */
#define KSCM_CONFIG_STR_SEGSIZE 10000 /* bytes of one string segment */
#define KSCM_CONFIG_STR_NSEGMENT 10000 /* # of segments for strings */
#endif
#define KSCM_CONFIG_BANNER "Hello, This is KScheme (kscm) 0.3, based on Mini-Scheme Interpreter Version 0.85p1.\n"
#define KSCM_CONFIG_PERSIST_MAGIC "KSCM"
#define KSCM_CONFIG_PERSIST_VERSION 2
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
#ifdef KSCM_CONFIG_USE_SETJMP
#include <setjmp.h>
#endif
/* System dependency */
#ifdef LSC
#include <strings.h>
#include <unix.h>
#define malloc(x) NewPtr((long)(x))
#define KSCM_CONFIG_PROMPT "> "
#define KSCM_CONFIG_INITFILE "init.scm"
#define KSCM_CONFIG_FIRST_CELLSEGS 5
#endif
#ifdef LSC4
#include <string.h>
#include <stdlib.h>
#define malloc(x) NewPtr((long)(x))
#define KSCM_CONFIG_PROMPT "> "
#define KSCM_CONFIG_INITFILE "init.scm"
#define KSCM_CONFIG_FIRST_CELLSEGS 5
#endif
#ifdef MPW2
#include <strings.h>
#include <memory.h>
#define malloc(x) NewPtr((long)(x))
#define KSCM_CONFIG_PROMPT "> [enter at next line]\n"
#define KSCM_CONFIG_INITFILE "init.scm"
#define KSCM_CONFIG_FIRST_CELLSEGS 5
#endif
#ifdef KSCM_PLATFORM_BSD
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#define KSCM_CONFIG_PROMPT "> "
#define KSCM_CONFIG_INITFILE "init.scm"
#define KSCM_CONFIG_FIRST_CELLSEGS 10
#endif
// Old definition, no detection
#ifdef MSC
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <process.h>
#define KSCM_CONFIG_PROMPT "> "
#define KSCM_CONFIG_INITFILE "init.scm"
#define KSCM_CONFIG_FIRST_CELLSEGS 3
#endif
#ifdef KSCM_PLATFORM_TURBOC
#include <string.h>
#include <stdlib.h>
#define KSCM_CONFIG_PROMPT "> "
#define KSCM_CONFIG_INITFILE "init.scm"
#define KSCM_CONFIG_FIRST_CELLSEGS 3
#endif
// Old definition, no detection
#ifdef SYSV
#include <string.h>
#include <malloc.h>
#if __STDC__
# include <stdlib.h>
#endif
#define KSCM_CONFIG_PROMPT "> "
#define KSCM_CONFIG_INITFILE "init.scm"
#define KSCM_CONFIG_FIRST_CELLSEGS 10
#endif
#ifdef KSCM_PLATFORM_VAXC
#include <string.h>
#include <stdlib.h>
#define KSCM_CONFIG_PROMPT "> "
#define KSCM_CONFIG_INITFILE "init.scm"
#define KSCM_CONFIG_FIRST_CELLSEGS 10
#endif
#ifdef __GNUC__
/*
* If we use gcc, KSCM_CONFIG_AVOID_HACK_LOOP is unnecessary
*/
#undef KSCM_CONFIG_AVOID_HACK_LOOP
#endif
#ifndef KSCM_CONFIG_FIRST_CELLSEGS
#error Please define your system type.
/*
* We refrain this to raise an error anyway even if on pre-ANSI system.
*/
error Please define your system type.
#endif
/* ========== Evaluation Cycle ========== */
/* operator code */
#define KSCM_OP_LOAD 0
#define KSCM_OP_T0LVL 1
#define KSCM_OP_T1LVL 2
#define KSCM_OP_READ 3
#define KSCM_OP_VALUEPRINT 4
#define KSCM_OP_EVAL 5
#define KSCM_OP_E0ARGS 6
#define KSCM_OP_E1ARGS 7
#define KSCM_OP_APPLY 8
#define KSCM_OP_DOMACRO 9
#define KSCM_OP_LAMBDA 10
#define KSCM_OP_QUOTE 11
#define KSCM_OP_DEF0 12
#define KSCM_OP_DEF1 13
#define KSCM_OP_BEGIN 14
#define KSCM_OP_IF0 15
#define KSCM_OP_IF1 16
#define KSCM_OP_SET0 17
#define KSCM_OP_SET1 18
#define KSCM_OP_LET0 19
#define KSCM_OP_LET1 20
#define KSCM_OP_LET2 21
#define KSCM_OP_LET0AST 22
#define KSCM_OP_LET1AST 23
#define KSCM_OP_LET2AST 24
#define KSCM_OP_LET0REC 25
#define KSCM_OP_LET1REC 26
#define KSCM_OP_LET2REC 27
#define KSCM_OP_COND0 28
#define KSCM_OP_COND1 29
#define KSCM_OP_DELAY 30
#define KSCM_OP_AND0 31
#define KSCM_OP_AND1 32
#define KSCM_OP_OR0 33
#define KSCM_OP_OR1 34
#define KSCM_OP_C0STREAM 35
#define KSCM_OP_C1STREAM 36
#define KSCM_OP_0MACRO 37
#define KSCM_OP_1MACRO 38
#define KSCM_OP_CASE0 39
#define KSCM_OP_CASE1 40
#define KSCM_OP_CASE2 41
#define KSCM_OP_PEVAL 42
#define KSCM_OP_PAPPLY 43
#define KSCM_OP_CONTINUATION 44
#define KSCM_OP_ADD 45
#define KSCM_OP_SUB 46
#define KSCM_OP_MUL 47
#define KSCM_OP_DIV 48
#define KSCM_OP_REM 49
#define KSCM_OP_CAR 50
#define KSCM_OP_CDR 51
#define KSCM_OP_CONS 52
#define KSCM_OP_SETCAR 53
#define KSCM_OP_SETCDR 54
#define KSCM_OP_NOT 55
#define KSCM_OP_BOOL 56
#define KSCM_OP_NULL 57
#define KSCM_OP_ZEROP 58
#define KSCM_OP_POSP 59
#define KSCM_OP_NEGP 60
#define KSCM_OP_NEQ 61
#define KSCM_OP_LESS 62
#define KSCM_OP_GRE 63
#define KSCM_OP_LEQ 64
#define KSCM_OP_GEQ 65
#define KSCM_OP_SYMBOL 66
#define KSCM_OP_NUMBER 67
#define KSCM_OP_STRING 68
#define KSCM_OP_PROC 69
#define KSCM_OP_PAIR 70
#define KSCM_OP_EQ 71
#define KSCM_OP_EQV 72
#define KSCM_OP_FORCE 73
#define KSCM_OP_WRITE 74
#define KSCM_OP_DISPLAY 75
#define KSCM_OP_NEWLINE 76
#define KSCM_OP_ERR0 77
#define KSCM_OP_ERR1 78
#define KSCM_OP_REVERSE 79
#define KSCM_OP_APPEND 80
#define KSCM_OP_PUT 81
#define KSCM_OP_GET 82
#define KSCM_OP_QUIT 83
#define KSCM_OP_GC 84
#define KSCM_OP_GCVERB 85
#define KSCM_OP_NEWSEGMENT 86
#define KSCM_OP_RDSEXPR 87
#define KSCM_OP_RDLIST 88
#define KSCM_OP_RDDOT 89
#define KSCM_OP_RDQUOTE 90
#define KSCM_OP_RDQQUOTE 91
#define KSCM_OP_RDUNQUOTE 92
#define KSCM_OP_RDUQTSP 93
#define KSCM_OP_P0LIST 94
#define KSCM_OP_P1LIST 95
#define KSCM_OP_LIST_LENGTH 96
#define KSCM_OP_ASSQ 97
#define KSCM_OP_PRINT_WIDTH 98
#define KSCM_OP_P0_WIDTH 99
#define KSCM_OP_P1_WIDTH 100
#define KSCM_OP_GET_CLOSURE 101
#define KSCM_OP_CLOSUREP 102
#define KSCM_OP_MACROP 103
#define KSCM_OP_STRCAT 104
#define KSCM_OP_STRLEN 105
#define KSCM_OP_STRGET 106
#define KSCM_OP_SAVE_STATE 107
#define KSCM_OP_RESUME_STATE 108
#define KSCM_OP_BUFFER 109
#define KSCM_OP_BUFFER_NEW 110
#define KSCM_OP_BUFFER_LEN 111
#define KSCM_OP_BUFFER_GET 112
#define KSCM_OP_BUFFER_SET 113
#define KSCM_OP_ABSTRACTION 114
#define KSCM_OP_ABSTRACTION_NEW 115
#define KSCM_OP_ABSTRACTION_TYPE 116
#define KSCM_OP_ABSTRACTION_VALUE 117
#define KSCM_OP_OBJECT 118
#define KSCM_OP_OBJECT_NEW 119
#define KSCM_OP_OBJECT_LEN 120
#define KSCM_OP_OBJECT_GET 121
#define KSCM_OP_OBJECT_SET 122
#define KSCM_OP_OBJECT_RETYPE 123
#define KSCM_OP_SYMBOL_TO_STRING 124
#define KSCM_OP_BUFFER_LOAD 125
#define KSCM_OP_BUFFER_SAVE 126
#define KSCM_OP_CONSOLE_MODE 127
#define KSCM_OP_CONSOLE_NEXT 128
#define KSCM_OP_CONSOLE_POLL 129
#define KSCM_OP_CONSOLE_WIDTH 130
#define KSCM_OP_CONSOLE_HEIGHT 131
#define KSCM_TOK_LPAREN 0
#define KSCM_TOK_RPAREN 1
#define KSCM_TOK_DOT 2
#define KSCM_TOK_ATOM 3
#define KSCM_TOK_QUOTE 4
#define KSCM_TOK_COMMENT 5
#define KSCM_TOK_DQUOTE 6
#ifdef KSCM_CONFIG_USE_QQUOTE
# define KSCM_TOK_BQUOTE 7
# define KSCM_TOK_COMMA 8
# define KSCM_TOK_ATMARK 9
#endif
#define KSCM_TOK_SHARP 10
typedef struct kscm kscm_t;
/* cell structure */
struct kscm_cell {
unsigned long _flag; // TODO: This should probably always be 32-bit
union {
struct {
char* _svalue;
short _keynum;
} _string;
struct {
long _ivalue; // TODO: This should probably always be 32-bit, i.e. representing a flexible "small int" value
} _number;
struct {
struct kscm_cell* _car;
struct kscm_cell* _cdr;
} _cons;
#ifdef KSCM_CONFIG_USE_STRUCTS
struct {
unsigned long _length;
unsigned char* _data;
} _buffer;
#endif
#ifdef KSCM_CONFIG_USE_FLOATS
struct {
double _dvalue;
} _float64;
#endif
#ifdef KSCM_CONFIG_USE_OBJECTS
struct {
struct kscm_cell* _type;
long _count;
long _gccount;
struct kscm_cell** _elements;
} _objx;
#endif
} _object;
};
typedef struct kscm_cell* kscm_object_t;
typedef struct kscm_gcstate kscm_gcstate_t;
struct kscm_gcstate {
kscm_object_t object;
size_t offset;
};
#define KSCM_PERSIST_TINT32 1
#define KSCM_PERSIST_TSTRING 2
#define KSCM_PERSIST_TSYMBOL 3
#define KSCM_PERSIST_TPAIR 4
#define KSCM_PERSIST_TPROC 5
#define KSCM_PERSIST_TCLOSURE 6
#define KSCM_PERSIST_TSYNTAX 7
#define KSCM_PERSIST_TCONTINUATION 8
#define KSCM_PERSIST_TBUFFER 9
#define KSCM_PERSIST_TABSTRACTION 10
#define KSCM_PERSIST_TOBJX 11
#define KSCM_PERSIST_TFLOAT32_RESERVED 12
#define KSCM_PERSIST_TFLOAT64 13
#define KSCM_PERSIST_TUINT64_RESERVED 14
#define KSCM_PERSIST_TINT64_RESERVED 15
#define KSCM_T_STRING 1 /* 0000000000000001 */
#define KSCM_T_NUMBER 2 /* 0000000000000010 */
#define KSCM_T_SYMBOL 4 /* 0000000000000100 */
#define KSCM_T_SYNTAX 8 /* 0000000000001000 */
#define KSCM_T_PROC 16 /* 0000000000010000 */
#define KSCM_T_PAIR 32 /* 0000000000100000 */
#define KSCM_T_CLOSURE 64 /* 0000000001000000 */
#define KSCM_T_CONTINUATION 128 /* 0000000010000000 */
#ifdef KSCM_CONFIG_USE_MACRO
# define KSCM_T_MACRO 256/* 0000000100000000 */
#endif
#define KSCM_T_PROMISE 512 /* 0000001000000000 */
#define KSCM_T_BUFFER 1024/* 0000010000000000 */
#define KSCM_T_ABSTRACTION 2048/* 0000100000000000 */
#define KSCM_T_OBJX 4096/* 0001000000000000 */
#define KSCM_T_FLOAT64 8192/* 0010000000000000 */
#define KSCM_T_ATOM 16384 /* 0100000000000000 */ /* only for gc */
#define KSCM_CLRATOM 49151 /* 1011111111111111 */ /* only for gc */
#define KSCM_MARK 32768 /* 1000000000000000 */
#define KSCM_UNMARK 32767 /* 0111111111111111 */
/* macros for cell operations */
#define kscm__type(kscm,p) ((p)->_flag)
#define kscm__isstring(kscm,p) (kscm__type(kscm, p)&KSCM_T_STRING)
#define kscm__strvalue(kscm,p) ((p)->_object._string._svalue)
#define kscm__keynum(kscm,p) ((p)->_object._string._keynum)
#define kscm__isnumber(kscm,p) (kscm__type(kscm, p)&KSCM_T_NUMBER)
#define kscm__ivalue(kscm,p) ((p)->_object._number._ivalue)
#ifdef KSCM_CONFIG_USE_FLOATS
#define kscm__isfloat64(kscm,p) (kscm__type(kscm, p)&KSCM_T_FLOAT64)
#define kscm__dvalue(kscm,p) ((p)->_object._float64._dvalue)
#endif
#define kscm__ispair(kscm,p) (kscm__type(kscm,p)&KSCM_T_PAIR)
#define kscm__car(kscm,p) (p)->_object._cons._car
#define kscm__cdr(kscm,p) (p)->_object._cons._cdr
#define kscm__issymbol(kscm,p) (kscm__type(kscm, p)&KSCM_T_SYMBOL)
#define kscm__symname(kscm,p) kscm__strvalue(kscm, kscm__car(kscm, p))
#define kscm__hasprop(kscm,p) (kscm__type(kscm, p)&KSCM_T_SYMBOL)
#define kscm__symprop(kscm,p) kscm__cdr(kscm, p)
#define kscm__issyntax(kscm,p) (kscm__type(kscm, p)&KSCM_T_SYNTAX)
#define kscm__isproc(kscm,p) (kscm__type(kscm, p)&KSCM_T_PROC)
#define kscm__syntaxname(kscm,p) kscm__strvalue(kscm, kscm__car(kscm, p))
#define kscm__syntaxnum(kscm,p) kscm__keynum(kscm, kscm__car(kscm, p))
#define kscm__procnum(kscm,p) kscm__ivalue(kscm, p)
#define kscm__isclosure(kscm,p) (kscm__type(kscm, p)&KSCM_T_CLOSURE)
#ifdef KSCM_CONFIG_USE_MACRO
# define kscm__ismacro(kscm,p) (kscm__type(kscm, p)&KSCM_T_MACRO)
#endif
#define kscm__closure_code(kscm,p) kscm__car(kscm, p)
#define kscm__closure_env(kscm,p) kscm__cdr(kscm, p)
#define kscm__iscontinuation(kscm,p) (kscm__type(kscm, p)&KSCM_T_CONTINUATION)
#define kscm__cont_dump(kscm,p) kscm__cdr(kscm, p)
#define kscm__ispromise(kscm,p) (kscm__type(kscm,p)&KSCM_T_PROMISE)
#define kscm__setpromise(kscm,p) kscm__type(kscm,p) |= KSCM_T_PROMISE
#ifdef KSCM_CONFIG_USE_STRUCTS
#define kscm__isbuffer(kscm,p) (kscm__type(kscm,p)&KSCM_T_BUFFER)
#define kscm__isabstraction(kscm,p) (kscm__type(kscm,p)&KSCM_T_ABSTRACTION)
#endif
#ifdef KSCM_CONFIG_USE_OBJECTS
#define kscm__isobjx(kscm,p) (kscm__type(kscm,p)&KSCM_T_OBJX)
#endif
#define kscm__isatom(kscm,p) (kscm__type(kscm,p)&KSCM_T_ATOM)
#define kscm__setatom(kscm,p) kscm__type(kscm,p) |= KSCM_T_ATOM
#define kscm__clratom(kscm,p) kscm__type(kscm,p) &= KSCM_CLRATOM
#define kscm__ismark(kscm,p) (kscm__type(kscm, p)&KSCM_MARK)
#define kscm__setmark(kscm,p) kscm__type(kscm, p) |= KSCM_MARK
#define kscm__clrmark(kscm,p) kscm__type(kscm, p) &= KSCM_UNMARK
#define kscm__caar(kscm, p) kscm__car(kscm, kscm__car(kscm, p))
#define kscm__cadr(kscm, p) kscm__car(kscm, kscm__cdr(kscm, p))
#define kscm__cdar(kscm, p) kscm__cdr(kscm, kscm__car(kscm, p))
#define kscm__cddr(kscm, p) kscm__cdr(kscm, kscm__cdr(kscm, p))
#define kscm__cadar(kscm, p) kscm__car(kscm, kscm__cdr(kscm, kscm__car(kscm, p)))
#define kscm__caddr(kscm, p) kscm__car(kscm, kscm__cdr(kscm, kscm__cdr(kscm, p)))
#define kscm__cadaar(kscm, p) kscm__car(kscm, kscm__cdr(kscm, kscm__car(kscm, kscm__car(kscm, p))))
#define kscm__cadddr(kscm, p) kscm__car(kscm, kscm__cdr(kscm, kscm__cdr(kscm, kscm__cdr(kscm, p))))
#define kscm__cddddr(kscm, p) kscm__cdr(kscm, kscm__cdr(kscm, kscm__cdr(kscm, kscm__cdr(kscm, p))))
#define LINESIZE 1024
struct kscm {
/* arrays for segments */
kscm_object_t* cell_seg;
int last_cell_seg;// = -1;
int gcstate_max;
kscm_gcstate_t* gcstate;
//char* str_seg[KSCM_CONFIG_STR_NSEGMENT];
//int str_seglast;// = -1;
/* We use 4 registers (actually, some more registers are used internally). */
kscm_object_t args; /* register for arguments of function */
kscm_object_t envir; /* stack register for current environment */
kscm_object_t code; /* register for current code */
kscm_object_t dump; /* stack register for next evaluation */
/* The VM is currently single-threaded, but to facilitate compatibility with future/other versions
* some information is associated with the "main thread" as though it were one thread in a multi-threaded
* environment.
*/
int _threadstate;
kscm_object_t _threadname;
kscm_object_t _threadopts;
kscm_object_t _threadobject;
/* Right now, the state format just contains the number of bytes per reference (either 4 or 8). */
int _stateformat;
//struct kscm_cell _NIL;
kscm_object_t NIL;// = &_NIL; /* special cell representing empty cell */
//struct kscm_cell _T;
kscm_object_t T;// = &_T; /* special cell representing #t */
//struct kscm_cell _F;
kscm_object_t F;// = &_F; /* special cell representing #f */
kscm_object_t oblist;// = &_NIL; /* pointer to symbol table */
kscm_object_t global_env; /* pointer to global environment */
/* global pointers to special symbols */
kscm_object_t LAMBDA; /* pointer to syntax lambda */
kscm_object_t QUOTE; /* pointer to syntax quote */
#ifdef KSCM_CONFIG_USE_QQUOTE
kscm_object_t QQUOTE; /* pointer to symbol quasiquote */
kscm_object_t UNQUOTE; /* pointer to symbol unquote */
kscm_object_t UNQUOTESP; /* pointer to symbol unquote-splicing */
#endif
kscm_object_t free_cell;// = &_NIL; /* pointer to top of free cells */
long fcells;// = 0; /* # of free cells */
//FILE* infp; /* input file */
FILE* inputs[KSCM_CONFIG_MAXLOADS];
int inputtop; // = 0; (TODO: Remove the other initialisers - assume calloc or similar clears memory prior during manual initialisation)
FILE* outfp; /* output file */
#ifdef KSCM_CONFIG_USE_SETJMP
jmp_buf error_jmp;
#endif
char gc_verbose; /* if gc_verbose is not zero, print gc status */
int quiet;// = 0; /* if not zero, print KSCM_CONFIG_BANNER, KSCM_CONFIG_PROMPT, results */
int all_errors_fatal;// = 0; /* if not zero, every error is a FatalError */
FILE* tmpfp;
int tok;
int print_flag;
kscm_object_t value;
short _operator;
char linebuff[LINESIZE];
char strbuff[256];
char* currentline;// = linebuff;
char* endline;// = linebuff;
};
/* allocate new cell segment */
int kscm__alloc_cellseg(kscm_t *kscm, int n)
{
/*register*/ kscm_object_t p;
/*register*/ long i;
/*register*/ int k;
for (k = 0; k < n; k++) {
if (kscm->last_cell_seg >= (KSCM_CONFIG_CELL_NSEGMENT - 1))
return k;
p = (kscm_object_t)calloc(1,KSCM_CONFIG_CELL_SEGSIZE * sizeof(struct kscm_cell));
if (p == (kscm_object_t)0)
return k;
kscm->last_cell_seg++;
kscm->cell_seg[kscm->last_cell_seg] = p;
kscm->fcells += KSCM_CONFIG_CELL_SEGSIZE;
for (i = 0; i < KSCM_CONFIG_CELL_SEGSIZE; i++) {
kscm__type(kscm, p+i) = 0;
kscm__car(kscm, p+i) = kscm->NIL;
kscm__cdr(kscm, p+i) = kscm->free_cell;
kscm->free_cell = p+i;
//p++;
}
//for (i = 0; i < (KSCM_CONFIG_CELL_SEGSIZE - 1); i++/*, p++*/) {
/* kscm__type(kscm, p) = 0;
kscm__car(kscm, p) = kscm->NIL;
kscm__cdr(kscm, p) = (p + 1);
//fprintf(stderr, "Added cell %d @ %lx %lx %lx\n", i, kscm__cdr(kscm, p), (p + 1), kscm->NIL);
p++;
}
kscm__type(kscm, p) = 0;
kscm__car(kscm, p) = kscm->NIL;
kscm__cdr(kscm, p) = kscm->free_cell;
kscm->free_cell = kscm->cell_seg[kscm->last_cell_seg];*/
}
return n;
}
/* allocate new string segment */
/*int kscm__alloc_strseg(kscm_t* kscm, int n)
{
register char* p;
register long i;
register int k;
for (k = 0; k < n; k++) {
if (kscm->str_seglast >= KSCM_CONFIG_STR_NSEGMENT)
return k;
p = (char*)malloc(KSCM_CONFIG_STR_SEGSIZE * sizeof(char));
if (p == (char*)0)
return k;
kscm->str_seg[++kscm->str_seglast] = p;
for (i = 0; i < KSCM_CONFIG_STR_SEGSIZE; i++)
*p++ = (char)(-1);
}
return n;
}*/
void kscm__fatal_error(kscm_t* kscm, const char* msg, const char* a, const char* b, const char* c);
void kscm__error(kscm_t* kscm, const char* msg, const char* a, const char* b, const char* c);
void kscm__init_globals(kscm_t* kscm);
kscm_object_t kscm__mk_string(kscm_t* kscm, const char* str);
struct kscm_cell _NIL;
struct kscm_cell _T;
struct kscm_cell _F;
/* initialization of Mini-Scheme */
void kscm__init_scheme(kscm_t* kscm)
{
memset(&_NIL, 0, sizeof(struct kscm_cell));
memset(&_T, 0, sizeof(struct kscm_cell));
memset(&_F, 0, sizeof(struct kscm_cell));
/*register*/ kscm_object_t i;
kscm->last_cell_seg = -1;
//kscm->str_seglast = -1;
kscm->NIL = &_NIL;
kscm->T = &_T;
kscm->F = &_F;
kscm->oblist = &_NIL;
kscm->free_cell = &_NIL;
fprintf(stderr, "Initialising scheme...\n");
if (kscm__alloc_cellseg(kscm, KSCM_CONFIG_FIRST_CELLSEGS) != KSCM_CONFIG_FIRST_CELLSEGS)
kscm__fatal_error(kscm, "Unable to allocate initial cell segments", NULL, NULL, NULL);
/*if (!kscm__alloc_strseg(kscm, 1))
kscm__fatal_error(kscm, "Unable to allocate initial string segments", NULL, NULL, NULL);*/
#ifdef VERBOSE
kscm->gc_verbose = 1;
#else
kscm->gc_verbose = 0;
#endif
kscm->_stateformat = 4;
kscm->_threadstate = 1;
kscm->_threadobject = kscm->NIL;
fprintf(stderr, "Initialising strings...\n");
kscm->_threadname = kscm__mk_string(kscm, "main");
fprintf(stderr, "Initialising strings...\n");
kscm->_threadopts = kscm__mk_string(kscm, "");
fprintf(stderr, "Initialising globals...\n");
kscm__init_globals(kscm);
}
void kscm__gc(kscm_t* kscm,/* register*/ kscm_object_t a, /*register*/ kscm_object_t b);
/* get new cell. parameter a, b is marked by gc. */
kscm_object_t kscm__get_cell(kscm_t* kscm, /*register*/ kscm_object_t a, /*register*/ kscm_object_t b)
{
// return calloc(1,sizeof(struct kscm_cell));
//#if 0
/*register*/ kscm_object_t x;
//fprintf(stderr, "A\n");
if (kscm->free_cell == kscm->NIL) {
//fprintf(stderr, "B\n");
kscm__gc(kscm, a, b);
if (kscm->free_cell == kscm->NIL) {
//fprintf(stderr, "C\n");
#ifdef KSCM_CONFIG_USE_SETJMP
if (!kscm__alloc_cellseg(kscm, 1)) {
//fprintf(stderr, "D\n");
kscm->args = kscm->envir = kscm->code = kscm->dump = kscm->NIL;
kscm__gc(kscm, kscm->NIL, kscm->NIL);
if (kscm->free_cell != kscm->NIL) {
kscm__error(kscm, "run out of cells --- rerurn to top level", NULL, NULL, NULL);
} else {
kscm__fatal_error(kscm, "run out of cells --- unable to recover cells", NULL, NULL, NULL);
}
}
#else
if (!kscm__alloc_cellseg(kscm, 1)) {
//fprintf(stderr, "E\n");
kscm__fatal_error(kscm, "run out of cells --- unable to recover cells", NULL, NULL, NULL);
}
#endif
}
}
//fprintf(stderr, "F\n");
x = kscm->free_cell;
//fprintf(stderr, "G %lx\n", x);
//fprintf(stderr, "G %lx\n", kscm__cdr(kscm, x));
kscm->free_cell = kscm__cdr(kscm, x);
//fprintf(stderr, "H\n");
kscm->fcells--;
//fprintf(stderr, "I\n");
return x;
//#endif
}
/* get new cons cell */
kscm_object_t kscm__cons(kscm_t* kscm, register kscm_object_t a, register kscm_object_t b)
{
register kscm_object_t x = kscm__get_cell(kscm, a, b);
kscm__type(kscm, x) = KSCM_T_PAIR;
kscm__car(kscm, x) = a;
kscm__cdr(kscm, x) = b;
return (x);
}
/* get number atom */
kscm_object_t kscm__mk_number(kscm_t* kscm, register long num)
{
register kscm_object_t x = kscm__get_cell(kscm, kscm->NIL, kscm->NIL);
kscm__type(kscm, x) = (KSCM_T_NUMBER | KSCM_T_ATOM);
kscm__ivalue(kscm, x) = num;
return (x);
}
#ifdef KSCM_CONFIG_USE_FLOATS
kscm_object_t kscm__mk_float64(kscm_t* kscm, double value) {
kscm_object_t x = kscm__get_cell(kscm, kscm->NIL, kscm->NIL);
kscm__type(kscm, x) = (KSCM_T_FLOAT64 | KSCM_T_ATOM);
x->_object._float64._dvalue = value;
return x;
}
#endif
/* allocate name to string area */
//char* kscm__store_string(kscm_t* kscm, const char *name)
//{
// register char* q = NULL;
// register short i;
// long len, remain;
//
// /* first check name has already listed */
// for (i = 0; i <= kscm->str_seglast; i++)
// for (q = kscm->str_seg[i]; *q != (char)(-1); ) {
// if (!strcmp(q, name))
// goto FOUND;
// while (*q++)
// ; /* get next string */
// }
// len = strlen(name) + 2;
// // TODO: Replace legacy types, it's starting to get ugly. -Zak
// remain = (long long)KSCM_CONFIG_STR_SEGSIZE - ((long long)q - (long long)kscm->str_seg[kscm->str_seglast]);
// if (remain < len) {
// if (!kscm__alloc_strseg(kscm, 1))
// kscm__fatal_error(kscm, "run out of string area", NULL, NULL, NULL);
// q = kscm->str_seg[kscm->str_seglast];
// /*if ((long long)KSCM_CONFIG_STR_SEGSIZE - ((long long)q - (long long)kscm->str_seg[kscm->str_seglast])) {
// fprintf(stderr, "String in question's total length is %d", len);
// kscm__fatal_error(kscm, "string too big", NULL, NULL, NULL);
// }*/
// }
// strcpy(q, name);
//FOUND:
// return (q);
//}
/* get new string */
kscm_object_t kscm__mk_string(kscm_t* kscm, const char *str)
{
/*register*/ kscm_object_t x = kscm__get_cell(kscm, kscm->NIL, kscm->NIL);
#ifdef __WIN32
kscm__strvalue(kscm, x) = _strdup(str);//kscm__store_string(kscm, str);
#else
kscm__strvalue(kscm, x) = strdup(str);//kscm__store_string(kscm, str);
#endif
kscm__type(kscm, x) = (KSCM_T_STRING | KSCM_T_ATOM);
kscm__keynum(kscm, x) = (short)(-1);
return (x);
}
/* get new symbol */
kscm_object_t kscm__mk_symbol(kscm_t* kscm, const char *name)
{
register kscm_object_t x;
/* fisrt check oblist */
for (x = kscm->oblist; x != kscm->NIL; x = kscm__cdr(kscm, x))
if (!strcmp(name, kscm__symname(kscm, kscm__car(kscm, x))))
break;
if (x != kscm->NIL)
return (kscm__car(kscm, x));
else {
x = kscm__cons(kscm, kscm__mk_string(kscm, name), kscm->NIL);
kscm__type(kscm, x) = KSCM_T_SYMBOL;
kscm->oblist = kscm__cons(kscm, x, kscm->oblist);
return (x);
}
}
#ifdef KSCM_CONFIG_USE_STRUCTS
kscm_object_t kscm__mk_buffer(kscm_t* kscm, long len) {
void* d = calloc(1, len);
if (d == NULL) {
return kscm->NIL;
}
kscm_object_t result = kscm__get_cell(kscm, kscm->NIL, kscm->NIL);
kscm__type(kscm, result) = (KSCM_T_BUFFER | KSCM_T_ATOM);
result->_object._buffer._length = len;
result->_object._buffer._data = (unsigned char*) d;
return result;
}
kscm_object_t kscm__mk_abstraction(kscm_t* kscm, register kscm_object_t a, register kscm_object_t b)
{
register kscm_object_t x = kscm__get_cell(kscm, a, b);
kscm__type(kscm, x) = KSCM_T_ABSTRACTION;
kscm__car(kscm, x) = a;
kscm__cdr(kscm, x) = b;
return (x);
}
#endif
#ifdef KSCM_CONFIG_USE_OBJECTS
kscm_object_t kscm__mk_objx(kscm_t* kscm, kscm_object_t typ, long len) {
void* d = calloc(sizeof(kscm_object_t), len);
if (d == NULL) {
return kscm->NIL;
}
kscm_object_t result = kscm__get_cell(kscm, typ, kscm->NIL);
kscm__type(kscm, result) = KSCM_T_OBJX;
result->_object._objx._type = typ;
result->_object._objx._count = len;
result->_object._objx._elements = (kscm_object_t*)d;
long i;
for (i = 0; i < len; i++) {
result->_object._objx._elements[i] = kscm->NIL;
}
return result;
}
#endif
#ifdef KSCM_CONFIG_USE_PRECISE
int kscm__safedigit(kscm_t* kscm, int base, char d) {
if (base <= 10) {
if (d >= '0' && d < '0' + base) {
return d - '0';
}
else {
return -1;
}
}
else if (base == 16) {
if (d >= '0' && d < '0' + 10) {
return d - '0';
}
else if (d >= 'a' && d < 'a' + 6) {
return 10 + (d - 'a');
}
else if (d >= 'A' && d < 'A' + 6) {
return 10 + (d - 'A');
}
else {
return -1;
}
}
else {
return -1;
}
}
kscm_object_t kscm__mk_safenum(kscm_t* kscm, int base, const char* src) {
char c;
const char* p;
int32_t v = 0;
int negate = 0;
p = src;
if (p[0] == '-') {
negate = 1;
p++;
}
else if (p[0] == '+') {
p++;
}
if (kscm__safedigit(kscm, base, p[0]) < 0) {
return kscm->F;
}
while (kscm__safedigit(kscm, base, p[0]) >= 0) {
int64_t lv = ((int64_t)v) * base + kscm__safedigit(kscm, base, p[0]);
v = (int32_t)lv;
//printf("Adding digit %d to get %d\n", kscm__safedigit(kscm, base, p[0]), v);
if (((int64_t)v) != lv) {
return kscm->F;
}
p++;
}
if (negate) {
v = -v;
}
return kscm__mk_number(kscm, v);
}
#endif
/* make symbol or number atom from string */
kscm_object_t kscm__mk_atom(kscm_t* kscm, const char *q)
{
char c;
const char *p;
p = q;
if (!isdigit(c = *p++)) {
if ((c != '+' && c != '-') || !isdigit(*p))
return (kscm__mk_symbol(kscm, q));
}
#ifdef KSCM_CONFIG_USE_FLOATS
bool isFloat = false;
bool hasE = false;
bool hasESign = false;
char prev = ' ';
for (; (c = *p) != 0; ++p) {
if (!isdigit(c)) {
if (!isFloat && c == '.') {
isFloat = true;
}
else if (isFloat && !hasE && (c == 'e' || c == 'E')) {
hasE = true;
}
else if (isFloat && hasE && (prev == 'e' || prev == 'E') && (c == '+' || c == '-')) {
hasESign = true;
}
else {
return (kscm__mk_symbol(kscm, q));
}
}
prev = c;
}
if (isFloat) {
return kscm__mk_float64(kscm, atof(q));
}
#else
for (; (c = *p) != 0; ++p)
if (!isdigit(c))
return (kscm__mk_symbol(kscm, q));
#endif
#ifdef KSCM_CONFIG_USE_PRECISE
kscm_object_t result = kscm__mk_safenum(kscm, 10, q);
if (result == kscm->F) {
//fprintf(stderr, "WARNING: Math overflow in '%s'\n", q);
result = kscm__cons(kscm, kscm__mk_symbol(kscm, "parse-number"), kscm__cons(kscm, kscm__mk_string(kscm, q), kscm->NIL));
}
return result;
#else
return (kscm__mk_number(kscm, atol(q)));
#endif
}
/* make constant */
kscm_object_t kscm__mk_const(kscm_t* kscm, const char *name)
{
long x;
char tmp[256];
if (!strcmp(name, "t"))
return (kscm->T);
else if (!strcmp(name, "f"))
return (kscm->F);
else if (*name == 'o') {/* #o (octal) */
sprintf(tmp, "0%s", /*&name[1]*/ name+1);
fprintf(stderr, "TODO: Octal parsing!\n"); exit(-1);
//sscanf(tmp, "%lo", (unsigned long int*) & x);
return (kscm__mk_number(kscm, x));
}
else if (*name == 'd') { /* #d (decimal) */
x = atoll(name+1); //sscanf(&name[1], "%ld", &x);
return (kscm__mk_number(kscm, x));
}
else if (*name == 'x') { /* #x (hex) */
sprintf(tmp, "0x%s", &name[1]);
fprintf(stderr, "TODO: Hex parsing!\n"); exit(-1);
//sscanf(tmp, "%lx", (unsigned long int*) & x);
return (kscm__mk_number(kscm, x));
}
else
return (kscm->NIL);
}
/* ========== garbage collector ========== */
/*--
* We use algorithm E (Kunuth, The Art of Computer Programming Vol.1,
* sec.3.5) for marking.
*
* NOTE: The implementation is complicated a bit when using object-oriented/vector extensions.
* I've decided to just use recursive marking in this case, but I've added some documentation to
* the original algorithm as well in case anyone wants to update it.
*/
#ifdef KSCM_CONFIG_USE_OBJECTS
#define KSCM_GC_MAXREC 100000
void kscm__fastmark(kscm_t* kscm, kscm_object_t root) {
int stacklevel = 0;
kscm->gcstate[stacklevel].object = root;
kscm->gcstate[stacklevel].offset = 0;
while (stacklevel >= 0) {
kscm_object_t a = kscm->gcstate[stacklevel].object;
long o = kscm->gcstate[stacklevel].offset;
if (o == 0) {
if (kscm__ismark(kscm, a)) {
stacklevel--;
continue;
}
kscm__setmark(kscm, a);
if (kscm__isatom(kscm, a)) {
stacklevel--;
continue;
}
}
kscm->gcstate[stacklevel].offset = o + 1;
if (stacklevel + 1 >= kscm->gcstate_max) {
fprintf(stderr, "ERROR: Garbage collection stack limit reached! Current limit is set at %d!\n", kscm->gcstate_max);
exit(-1);
}
if (kscm__isobjx(kscm, a)) {
if (o == 0) {
stacklevel++;
kscm->gcstate[stacklevel].object = a->_object._objx._type;
kscm->gcstate[stacklevel].offset = 0;
} else if (o - 1 >= a->_object._objx._count) {
stacklevel--;
continue;
} else {
stacklevel++;
kscm->gcstate[stacklevel].object = a->_object._objx._elements[o-1];
kscm->gcstate[stacklevel].offset = 0;
}
} else { /* Is pair or pair-like abstraction*/
if (o == 0) {
stacklevel++;
kscm->gcstate[stacklevel].object = kscm__car(kscm, a);
kscm->gcstate[stacklevel].offset = 0;
} else if (o == 1) {
stacklevel++;
kscm->gcstate[stacklevel].object = kscm__cdr(kscm, a);
kscm->gcstate[stacklevel].offset = 0;
} else {
stacklevel--;
continue;
}
}
}
}
void kscm__recursivemark(kscm_t* kscm, kscm_object_t a, int recursionlevel) {
printf("Recursion=%d\n", recursionlevel);
if (recursionlevel > KSCM_GC_MAXREC) {
fprintf(stderr, "WARNING: Garbage collector is recursing like a motherfucker\n");
recursionlevel = 0; // We just reset it though, the warning should be enough to show if it's becoming a problem
}
if (kscm__ismark(kscm, a)) {
return;
}
kscm__setmark(kscm, a);
if (kscm__isatom(kscm, a)) {
return;
}
if (kscm__isobjx(kscm, a)) {
kscm__recursivemark(kscm, a->_object._objx._type, recursionlevel + 1);
int i;
for (i = 0; i < a->_object._objx._count; i++) {
//printf("Recursively marking object at index %d\n", i);
kscm__recursivemark(kscm, a->_object._objx._elements[i], recursionlevel + 1);
}
} else { /* Is pair or pair-like abstraction*/
kscm__recursivemark(kscm, kscm__car(kscm, a), recursionlevel + 1);
kscm__recursivemark(kscm, kscm__cdr(kscm, a), recursionlevel + 1);
}
}
void kscm__mark(kscm_t* kscm, kscm_object_t a) {
//kscm__recursivemark(kscm, a, 1);
kscm__fastmark(kscm, a);
}
#else
void kscm__mark(kscm_t* kscm, kscm_object_t a)
{
register kscm_object_t t; /* Used to track the previous object. This object will in turn be used to track it's previous. */
register kscm_object_t q; /* Used as a temporary value to hold our subreferences. */
register kscm_object_t p; /* Points to the current object. */
/* E1: Start of algorithm. Reset t and p. */
E1: t = (kscm_object_t)0;
p = a;
/* E2: Start by marking p (i.e. marking it as "keep this cell"). */
E2: kscm__setmark(kscm, p);
/* E3: Check type. If it's an atom (not built out of references to other cells) we can skip marking references. */
E3: if (kscm__isatom(kscm, p))
goto E6;
/* E4: Mark first reference ("car" or equivalent) if it's not already marked. */
E4:
q = kscm__car(kscm, p);
if (q && !kscm__ismark(kscm, q)) {
kscm__setatom(kscm, p);
kscm__car(kscm, p) = t;
t = p;
p = q;
goto E2;
}
/* E5: Mark second/nth references if they're not already marked. */
E5: q = kscm__cdr(kscm, p);
if (q && !kscm__ismark(kscm, q)) {
kscm__cdr(kscm, p) = t;
t = p;
p = q;
goto E2;
}
/* E6: This object is now fully marked. If there's no previous object, we can just return. Otherwise,
* we reload the previous object (and set the new previous to the one stored in "car" or equivalent),
* and continue marking it's subreferences.
*/
E6: if (!t)
return;
q = t;
if (kscm__isatom(kscm, q)) {
kscm__clratom(kscm, q);
t = kscm__car(kscm, q);
kscm__car(kscm, q) = p;
p = q;
goto E5;
}
else {
t = kscm__cdr(kscm, q);
kscm__cdr(kscm, q) = p;
p = q;
goto E6;
}
}
#endif
/* garbage collection. parameter a, b is marked. */
void kscm__gc(kscm_t* kscm, /*register*/ kscm_object_t a, /*register*/ kscm_object_t b)
{
/*register*/ kscm_object_t p;
/*register*/ short i;
/*register*/ long j;
if (kscm->gc_verbose)
printf("gc...");
/* mark system globals */
kscm__mark(kscm, kscm->oblist);
kscm__mark(kscm, kscm->global_env);
/* mark current registers */
kscm__mark(kscm, kscm->args);
kscm__mark(kscm, kscm->envir);
kscm__mark(kscm, kscm->code);
kscm__mark(kscm, kscm->dump);
/* mark thread values (this implementation is single-threaded but we keep them anyway) */
kscm__mark(kscm, kscm->_threadname);
kscm__mark(kscm, kscm->_threadopts);
kscm__mark(kscm, kscm->_threadobject);
/* mark variables a, b */
kscm__mark(kscm, a);
kscm__mark(kscm, b);
/* garbage collect */
kscm__clrmark(kscm, kscm->NIL);
kscm->fcells = 0;
kscm->free_cell = kscm->NIL;
for (i = 0; i <= kscm->last_cell_seg; i++) {
j = 0;
for (/*j = 0,*/ p = kscm->cell_seg[i]; j < KSCM_CONFIG_CELL_SEGSIZE; j++/*, p++*/) {
if (kscm__ismark(kscm, p))
kscm__clrmark(kscm, p);
else {
if (kscm__isstring(kscm, p)) {
if (p->_object._string._svalue != NULL) {
free(p->_object._string._svalue);
}
}
#ifdef KSCM_CONFIG_USE_STRUCTS
if (kscm__isbuffer(kscm, p)) {
if (p->_object._buffer._data != NULL) {
//fprintf(stderr, "Freeing a buffer of %d length\n", p->_object._buffer._length);
free(p->_object._buffer._data);
p->_object._buffer._data = NULL;
}
}
#endif
#ifdef KSCM_CONFIG_USE_OBJECTS
if (kscm__isobjx(kscm, p)) {
if (p->_object._objx._elements != NULL) {
free(p->_object._objx._elements);
p->_object._objx._elements = NULL;
}
}
#endif
// TODO: Should probably clear the whole structure before setting defaults or adding to free list
// (this could help avoid bugs if larger-than-pair structures aren't cleared or reset properly elsewhere)
kscm__type(kscm, p) = 0;
kscm__cdr(kscm, p) = kscm->free_cell;
kscm__car(kscm, p) = kscm->NIL;
kscm->free_cell = p;
kscm->fcells++;
}
p = p + 1;
}
}
if (kscm->gc_verbose)
printf(" done %ld cells are recovered.\n", kscm->fcells);
}
/* ========== Rootines for Reading ========== */
/* get new character from input file */
int kscm__inchar(kscm_t* kscm)
{
if (kscm->currentline >= kscm->endline) { /* input buffer is empty */
if (feof(kscm->inputs[kscm->inputtop])) {
fclose(kscm->inputs[kscm->inputtop]);
if (kscm->inputtop > 0) { // return to outer input
kscm->inputs[kscm->inputtop] = NULL;
kscm->inputtop--;
if (kscm->inputs[kscm->inputtop] == stdin) {
if (!kscm->quiet)
{printf(KSCM_CONFIG_PROMPT);fflush(stdout);}
}
}
else { // go back to the top-level
kscm->inputs[kscm->inputtop] = stdin;
if (!kscm->quiet)
{printf(KSCM_CONFIG_PROMPT);fflush(stdout);}
}
}
strcpy(kscm->linebuff, "\n"); // TODO: Why's this here? -Zak.
if (fgets(kscm->currentline = kscm->linebuff, LINESIZE, kscm->inputs[kscm->inputtop]) == NULL)
if (kscm->inputs[kscm->inputtop] == stdin) {
if (!kscm->quiet)
fprintf(stderr, "Good-bye\n");
exit(0);
}
kscm->endline = kscm->linebuff + strlen(kscm->linebuff);
}
return (*kscm->currentline++);
}
/* clear input buffer */
void kscm__clearinput(kscm_t* kscm)
{
kscm->currentline = kscm->endline = kscm->linebuff;
}
/* back to standard input */
void kscm__resetinput(kscm_t* kscm)
{
/*if (kscm->inputs[kscm->inputtop] != stdin) {
fclose(kscm->inputs[kscm->inputtop]);
kscm->inputs[kscm->inputtop] = stdin;
}*/
while (kscm->inputtop > 0 || kscm->inputs[kscm->inputtop] != stdin) {
fclose(kscm->inputs[kscm->inputtop]);
if (kscm->inputtop > 0) { // return to outer input
kscm->inputs[kscm->inputtop] = NULL;
kscm->inputtop--;
}
else { // go back to the top-level
kscm->inputs[kscm->inputtop] = stdin;
if (!kscm->quiet)
{printf(KSCM_CONFIG_PROMPT);fflush(stdout);}
}
}
kscm__clearinput(kscm);
}
/* back character to input buffer */
void kscm__backchar(kscm_t* kscm)
{
kscm->currentline--;
}
int kscm__isdelim(kscm_t* kscm, const char* s, char c);
/* read chacters to delimiter */
char* kscm__readstr(kscm_t* kscm, const char *delim)
{
char* p = kscm->strbuff;
while (kscm__isdelim(kscm, delim, (*p++ = kscm__inchar(kscm))))
;
kscm__backchar(kscm);
*--p = '\0';
return (kscm->strbuff);
}
/* read string expression "xxx...xxx" */
char* kscm__readstrexp(kscm_t* kscm)
{
char c, * p = kscm->strbuff;
for (;;) {
if ((c = kscm__inchar(kscm)) != '"')
*p++ = c;
else if (p > kscm->strbuff&&* (p - 1) == '\\')
*(p - 1) = '"';
else {
*p = '\0';
return (kscm->strbuff);
}
}
}
/* check c is delimiter */
int kscm__isdelim(kscm_t* kscm, const char *s, char c)
{
while (*s)
if (*s++ == c)
return (0);
return (1);
}
/* skip white characters */
void kscm__skipspace(kscm_t* kscm)
{
while (isspace(kscm__inchar(kscm)))
;
kscm__backchar(kscm);
}
/* get token */
int kscm__token(kscm_t* kscm)
{
kscm__skipspace(kscm);
switch (kscm__inchar(kscm)) {
case '(':
return (KSCM_TOK_LPAREN);
case ')':
return (KSCM_TOK_RPAREN);
case '.':
return (KSCM_TOK_DOT);
case '\'':
return (KSCM_TOK_QUOTE);
case ';':
return (KSCM_TOK_COMMENT);
case '"':
return (KSCM_TOK_DQUOTE);
#ifdef KSCM_CONFIG_USE_QQUOTE
case BACKQUOTE:
return (KSCM_TOK_BQUOTE);
case ',':
if (kscm__inchar(kscm) == '@')
return (KSCM_TOK_ATMARK);
else {
kscm__backchar(kscm);
return (KSCM_TOK_COMMA);
}
#endif
case '#':
return (KSCM_TOK_SHARP);
default:
kscm__backchar(kscm);
return (KSCM_TOK_ATOM);
}
}
/* ========== Rootines for Printing ========== */
#define kscm__ok_abbrev(kscm,x) (kscm__ispair(kscm, x) && kscm__cdr(kscm, x) == kscm->NIL)
void kscm__strunquote(kscm_t* kscm, char *p, const char *s)
{
*p++ = '"';
for (; *s; ++s) {
if (*s == '"') {
*p++ = '\\';
*p++ = '"';
}
else if (*s == '\n') {
*p++ = '\\';
*p++ = 'n';
}
else
*p++ = *s;
}
*p++ = '"';
*p = '\0';
}
/* print atoms */
int kscm__printatom(kscm_t* kscm, kscm_object_t l, int f)
{
char *p = NULL;
if (l == kscm->NIL)
p = (char*)(void*)"()";
else if (l == kscm->T)
p = (char*)(void*)"#t";
else if (l == kscm->F)
p = (char*)(void*)"#f";
else if (kscm__isnumber(kscm, l)) {
p = kscm->strbuff;
sprintf(p, "%ld", kscm__ivalue(kscm, l));
}
else if (kscm__isfloat64(kscm, l)) {
p = kscm->strbuff;
sprintf(p, "%f", l->_object._float64._dvalue);
}
else if (kscm__isstring(kscm, l)) {
if (!f)
p = kscm__strvalue(kscm, l);
else {
p = kscm->strbuff;
kscm__strunquote(kscm, p, kscm__strvalue(kscm, l));
}
}
else if (kscm__issymbol(kscm, l))
p = kscm__symname(kscm, l);
else if (kscm__isproc(kscm, l)) {
p = kscm->strbuff;
sprintf(p, "#<PROCEDURE %ld>", kscm__procnum(kscm, l));
#ifdef KSCM_CONFIG_USE_MACRO
}
else if (kscm__ismacro(kscm, l)) {
p = (char*)(void*)"#<MACRO>";
#endif
#ifdef KSCM_CONFIG_USE_STRUCTS
}
else if (kscm__isbuffer(kscm, l)) {
p = (char*)(void*)"#<BUFFER>";
}
else if (kscm__isabstraction(kscm, l)) {
p = (char*)(void*)"#<ABSTRACTION>";
#endif
#ifdef KSCM_CONFIG_USE_OBJECTS
}
else if (kscm__isobjx(kscm, l)) {
p = (char*)(void*)"#<OBJECT>";
#endif
}
else if (kscm__isclosure(kscm, l))
p = (char*)(void*)"#<CLOSURE>";
else if (kscm__iscontinuation(kscm, l))
p = (char*)(void*)"#<CONTINUATION>";
if (f < 0)
return strlen(p);
fputs(p, kscm->outfp);
return 0;
}
/* ========== Rootines for Evaluation Cycle ========== */
/* make closure. c is code. e is environment */
kscm_object_t kscm__mk_closure(kscm_t* kscm, register kscm_object_t c, register kscm_object_t e)
{
register kscm_object_t x = kscm__get_cell(kscm, c, e);
kscm__type(kscm, x) = KSCM_T_CLOSURE;
kscm__car(kscm, x) = c;
kscm__cdr(kscm, x) = e;
return (x);
}
/* make continuation. */
kscm_object_t kscm__mk_continuation(kscm_t* kscm, register kscm_object_t d)
{
register kscm_object_t x = kscm__get_cell(kscm, kscm->NIL, d);
kscm__type(kscm, x) = KSCM_T_CONTINUATION;
kscm__cont_dump(kscm, x) = d;
return (x);
}
/* reverse list -- make new cells */
kscm_object_t kscm__reverse(kscm_t* kscm, register kscm_object_t a) /* a must be checked by gc */
{
register kscm_object_t p = kscm->NIL;
for (; kscm__ispair(kscm, a); a = kscm__cdr(kscm, a))
p = kscm__cons(kscm, kscm__car(kscm, a), p);
return (p);
}
/* reverse list --- no make new cells */
kscm_object_t kscm__non_alloc_rev(kscm_t* kscm, kscm_object_t term, kscm_object_t list)
{
register kscm_object_t p = list, result = term, q;
while (p != kscm->NIL) {
q = kscm__cdr(kscm, p);
kscm__cdr(kscm, p) = result;
result = p;
p = q;
}
return (result);
}
/* append list -- make new cells */
kscm_object_t kscm__append(kscm_t* kscm, register kscm_object_t a, register kscm_object_t b)
{
register kscm_object_t p = b, q;
if (a != kscm->NIL) {
a = kscm__reverse(kscm, a);
while (a != kscm->NIL) {
q = kscm__cdr(kscm, a);
kscm__cdr(kscm, a) = p;
p = a;
a = q;
}
}
return (p);
}
/* equivalence of atoms */
int kscm__eqv(kscm_t* kscm, register kscm_object_t a, register kscm_object_t b)
{
if (kscm__isstring(kscm, a)) {
if (kscm__isstring(kscm, b))
return (!strcmp(kscm__strvalue(kscm, a), kscm__strvalue(kscm, b)));
else
return (0);
}
else if (kscm__isnumber(kscm, a)) {
if (kscm__isnumber(kscm, b))
return (kscm__ivalue(kscm, a) == kscm__ivalue(kscm, b));
else
return (0);
}
else
return (a == b);
}
/* true or false value macro */
#define kscm__istrue(kscm,p) ((p) != kscm->NIL && (p) != kscm->F)
#define kscm__isfalse(kscm,p) ((p) == kscm->NIL || (p) == kscm->F)
/* Error macro */
#ifdef KSCM_CONFIG_AVOID_HACK_LOOP
# define KSCM__BEGIN {
# define KSCM__END }
#else
/*
* I believe this is better, but some compiler complains....
*/
# define KSCM__BEGIN do {
# define KSCM__END } while (0)
#endif
#define kscm__error_0(kscm,s) KSCM__BEGIN \
kscm->args = kscm__cons(kscm, kscm__mk_string(kscm, (s)), kscm->NIL); \
kscm->_operator = (short)KSCM_OP_ERR0; \
return kscm->T; KSCM__END
#define kscm__error_1(kscm,s, a) KSCM__BEGIN \
kscm->args = kscm__cons(kscm, (a), kscm->NIL); \
kscm->args = kscm__cons(kscm, kscm__mk_string(kscm, (s)), kscm->args); \
kscm->_operator = (short)KSCM_OP_ERR0; \
return kscm->T; KSCM__END
/* control macros for Eval_Cycle */
#define kscm__s_goto(kscm,a) KSCM__BEGIN \
kscm->_operator = (short)(a); \
return kscm->T; KSCM__END
#define kscm__s_save(kscm,a, b, c) do{ \
kscm->dump = kscm__cons(kscm, kscm->envir, kscm__cons(kscm, (c), kscm->dump)); \
kscm->dump = kscm__cons(kscm, (b), kscm->dump); \
kscm->dump = kscm__cons(kscm, kscm__mk_number(kscm, (long)(a)), kscm->dump);}while(0)
#define kscm__s_return(kscm,a) KSCM__BEGIN \
kscm->value = (a); \
kscm->_operator = kscm__ivalue(kscm, kscm__car(kscm, kscm->dump)); \
kscm->args = kscm__cadr(kscm, kscm->dump); \
kscm->envir = kscm__caddr(kscm, kscm->dump); \
kscm->code = kscm__cadddr(kscm, kscm->dump); \
kscm->dump = kscm__cddddr(kscm, kscm->dump); \
return kscm->T; KSCM__END
#define kscm__s_retbool(kscm,tf) kscm__s_return(kscm, (tf) ? kscm->T : kscm->F)
kscm_object_t kscm__opexe_0(kscm_t* kscm, register short op)
{
register kscm_object_t x;
register kscm_object_t y = NULL;
switch (op) {
case KSCM_OP_LOAD: /* load */
if (!kscm__isstring(kscm, kscm__car(kscm, kscm->args))) {
kscm__error_0(kscm, "load -- argument is not string");
}
if (kscm->inputtop + 1 >= KSCM_CONFIG_MAXLOADS) {
kscm__error_0(kscm, "load -- depth of loaded files has reached the KSCM_CONFIG_MAXLOADS value");
}
if ((kscm->inputs[kscm->inputtop + 1] = fopen(kscm__strvalue(kscm, kscm__car(kscm, kscm->args)), "r")) == NULL) {
//kscm->inputs[kscm->inputtop] = stdin;
kscm__error_1(kscm, "Unable to open", kscm__car(kscm, kscm->args));
}
kscm->inputtop++;
if (!kscm->quiet)
fprintf(kscm->outfp, "loading %s", kscm__strvalue(kscm, kscm__car(kscm, kscm->args)));
kscm__s_goto(kscm, KSCM_OP_T0LVL);
case KSCM_OP_T0LVL: /* top level */
if (!kscm->quiet)
fprintf(kscm->outfp, "\n");
kscm->dump = kscm->NIL;
kscm->envir = kscm->global_env;
kscm__s_save(kscm, KSCM_OP_VALUEPRINT, kscm->NIL, kscm->NIL);
kscm__s_save(kscm, KSCM_OP_T1LVL, kscm->NIL, kscm->NIL);
if (kscm->inputs[kscm->inputtop] == stdin && !kscm->quiet)
{printf(KSCM_CONFIG_PROMPT);fflush(stdout);}
kscm__s_goto(kscm, KSCM_OP_READ);
case KSCM_OP_T1LVL: /* top level */
kscm->code = kscm->value;
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_READ: /* read */
kscm->tok = kscm__token(kscm);
kscm__s_goto(kscm, KSCM_OP_RDSEXPR);
case KSCM_OP_VALUEPRINT: /* print evalution result */
kscm->print_flag = 1;
kscm->args = kscm->value;
if (kscm->quiet) {
kscm__s_goto(kscm, KSCM_OP_T0LVL);
}
else {
kscm__s_save(kscm, KSCM_OP_T0LVL, kscm->NIL, kscm->NIL);
kscm__s_goto(kscm, KSCM_OP_P0LIST);
}
case KSCM_OP_EVAL: /* main part of evalution */
if (kscm__issymbol(kscm, kscm->code)) { /* symbol */
for (x = kscm->envir; x != kscm->NIL; x = kscm__cdr(kscm, x)) {
for (y = kscm__car(kscm, x); y != kscm->NIL; y = kscm__cdr(kscm, y))
if (kscm__caar(kscm, y) == kscm->code)
break;
if (y != kscm->NIL)
break;
}
if (x != kscm->NIL) {
kscm__s_return(kscm, kscm__cdar(kscm, y));
}
else {
kscm__error_1(kscm, "Unbounded variable", kscm->code);
}
}
else if (kscm__ispair(kscm, kscm->code)) {
if (kscm__issyntax(kscm, x = kscm__car(kscm, kscm->code))) { /* SYNTAX */
kscm->code = kscm__cdr(kscm, kscm->code);
kscm__s_goto(kscm, kscm__syntaxnum(kscm, x));
}
else {/* first, eval top element and eval arguments */
#ifdef KSCM_CONFIG_USE_MACRO
kscm__s_save(kscm, KSCM_OP_E0ARGS, kscm->NIL, kscm->code);
#else
s_save(kscm, KSCM_OP_E1ARGS, kscm->NIL, cdr(code));
#endif
kscm->code = kscm__car(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
}
}
else {
kscm__s_return(kscm, kscm->code);
}
#ifdef KSCM_CONFIG_USE_MACRO
case KSCM_OP_E0ARGS: /* eval arguments */
if (kscm__ismacro(kscm, kscm->value)) { /* macro expansion */
kscm__s_save(kscm, KSCM_OP_DOMACRO, kscm->NIL, kscm->NIL);
kscm->args = kscm__cons(kscm, kscm->code, kscm->NIL);
kscm->code = kscm->value;
kscm__s_goto(kscm, KSCM_OP_APPLY);
}
else {
kscm->code = kscm__cdr(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_E1ARGS);
}
#endif
case KSCM_OP_E1ARGS: /* eval arguments */
kscm->args = kscm__cons(kscm, kscm->value, kscm->args);
if (kscm__ispair(kscm, kscm->code)) { /* continue */
kscm__s_save(kscm, KSCM_OP_E1ARGS, kscm->args, kscm__cdr(kscm, kscm->code));
kscm->code = kscm__car(kscm, kscm->code);
kscm->args = kscm->NIL;
kscm__s_goto(kscm, KSCM_OP_EVAL);
}
else { /* end */
kscm->args = kscm__reverse(kscm, kscm->args);
kscm->code = kscm__car(kscm, kscm->args);
kscm->args = kscm__cdr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_APPLY);
}
case KSCM_OP_APPLY: /* apply 'code' to 'args' */
if (kscm__isproc(kscm, kscm->code)) {
kscm__s_goto(kscm, kscm__procnum(kscm, kscm->code)); /* PROCEDURE */
}
else if (kscm__isclosure(kscm, kscm->code)) { /* CLOSURE */
/* make environment */
kscm->envir = kscm__cons(kscm, kscm->NIL, kscm__closure_env(kscm, kscm->code));
y = kscm->args;
for (x = kscm__car(kscm, kscm__closure_code(kscm, kscm->code))/*, y = kscm->args*/;
kscm__ispair(kscm, x); x = kscm__cdr(kscm, x)/*, y = kscm__cdr(kscm, y)*/) {
if (y == kscm->NIL) {
kscm__error_0(kscm, "Few arguments");
}
else {
kscm__car(kscm, kscm->envir) = kscm__cons(kscm, kscm__cons(kscm, kscm__car(kscm, x), kscm__car(kscm, y)), kscm__car(kscm, kscm->envir));
}
y = kscm__cdr(kscm, y);
}
if (x == kscm->NIL) {
/*--
* if (y != kscm->NIL) {
* Error_0("Many arguments");
* }
*/
}
else if (kscm__issymbol(kscm, x))
kscm__car(kscm, kscm->envir) = kscm__cons(kscm, kscm__cons(kscm, x, y), kscm__car(kscm, kscm->envir));
else {
kscm__error_0(kscm, "Syntax error in closure");
}
kscm->code = kscm__cdr(kscm, kscm__closure_code(kscm, kscm->code));
kscm->args = kscm->NIL;
kscm__s_goto(kscm, KSCM_OP_BEGIN);
}
else if (kscm__iscontinuation(kscm, kscm->code)) { /* CONTINUATION */
kscm->dump = kscm__cont_dump(kscm, kscm->code);
kscm__s_return(kscm, kscm->args != kscm->NIL ? kscm__car(kscm, kscm->args) : kscm->NIL);
}
else {
kscm__error_0(kscm, "Illegal function");
}
#ifdef KSCM_CONFIG_USE_MACRO
case KSCM_OP_DOMACRO: /* do macro */
kscm->code = kscm->value;
kscm__s_goto(kscm, KSCM_OP_EVAL);
#endif
case KSCM_OP_LAMBDA: /* lambda */
kscm__s_return(kscm, kscm__mk_closure(kscm, kscm->code, kscm->envir));
case KSCM_OP_QUOTE: /* quote */
kscm__s_return(kscm, kscm__car(kscm, kscm->code));
case KSCM_OP_DEF0: /* define */
if (kscm__ispair(kscm, kscm__car(kscm, kscm->code))) {
x = kscm__caar(kscm, kscm->code);
kscm->code = kscm__cons(kscm, kscm->LAMBDA, kscm__cons(kscm, kscm__cdar(kscm, kscm->code), kscm__cdr(kscm, kscm->code)));
}
else {
x = kscm__car(kscm, kscm->code);
kscm->code = kscm__cadr(kscm, kscm->code);
}
if (!kscm__issymbol(kscm, x)) {
kscm__error_0(kscm, "Variable is not symbol");
}
kscm__s_save(kscm, KSCM_OP_DEF1, kscm->NIL, x);
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_DEF1: /* define */
for (x = kscm__car(kscm, kscm->envir); x != kscm->NIL; x = kscm__cdr(kscm, x))
if (kscm__caar(kscm, x) == kscm->code)
break;
if (x != kscm->NIL)
kscm__cdar(kscm, x) = kscm->value;
else
kscm__car(kscm, kscm->envir) = kscm__cons(kscm, kscm__cons(kscm, kscm->code, kscm->value), kscm__car(kscm, kscm->envir));
kscm__s_return(kscm, kscm->code);
case KSCM_OP_SET0: /* set! */
kscm__s_save(kscm, KSCM_OP_SET1, kscm->NIL, kscm__car(kscm, kscm->code));
kscm->code = kscm__cadr(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_SET1: /* set! */
for (x = kscm->envir; x != kscm->NIL; x = kscm__cdr(kscm, x)) {
for (y = kscm__car(kscm, x); y != kscm->NIL; y = kscm__cdr(kscm, y))
if (kscm__caar(kscm, y) == kscm->code)
break;
if (y != kscm->NIL)
break;
}
if (x != kscm->NIL) {
kscm__cdar(kscm, y) = kscm->value;
kscm__s_return(kscm, kscm->value);
}
else {
kscm__error_1(kscm, "Unbounded variable", kscm->code);
}
case KSCM_OP_BEGIN: /* begin */
if (!kscm__ispair(kscm, kscm->code)) {
kscm__s_return(kscm, kscm->code);
}
if (kscm__cdr(kscm, kscm->code) != kscm->NIL) {
kscm__s_save(kscm, KSCM_OP_BEGIN, kscm->NIL, kscm__cdr(kscm, kscm->code));
}
kscm->code = kscm__car(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_IF0: /* if */
kscm__s_save(kscm, KSCM_OP_IF1, kscm->NIL, kscm__cdr(kscm, kscm->code));
kscm->code = kscm__car(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_IF1: /* if */
if (kscm__istrue(kscm, kscm->value))
kscm->code = kscm__car(kscm, kscm->code);
else
kscm->code = kscm__cadr(kscm, kscm->code); /* (if #f 1) ==> () because
* car(kscm->NIL) = kscm->NIL */
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_LET0: /* let */
kscm->args = kscm->NIL;
kscm->value = kscm->code;
kscm->code = kscm__issymbol(kscm, kscm__car(kscm, kscm->code)) ? kscm__cadr(kscm, kscm->code) : kscm__car(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_LET1);
case KSCM_OP_LET1: /* let (caluculate parameters) */
kscm->args = kscm__cons(kscm, kscm->value, kscm->args);
if (kscm__ispair(kscm, kscm->code)) { /* continue */
kscm__s_save(kscm, KSCM_OP_LET1, kscm->args, kscm__cdr(kscm, kscm->code));
kscm->code = kscm__cadar(kscm, kscm->code);
kscm->args = kscm->NIL;
kscm__s_goto(kscm, KSCM_OP_EVAL);
}
else { /* end */
kscm->args = kscm__reverse(kscm, kscm->args);
kscm->code = kscm__car(kscm, kscm->args);
kscm->args = kscm__cdr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_LET2);
}
case KSCM_OP_LET2: /* let */
kscm->envir = kscm__cons(kscm, kscm->NIL, kscm->envir);
y = kscm->args;
for (x = kscm__issymbol(kscm, kscm__car(kscm, kscm->code)) ? kscm__cadr(kscm, kscm->code) : kscm__car(kscm, kscm->code)/*, y = kscm->args*/;
y != kscm->NIL; x = kscm__cdr(kscm, x)/*, y = kscm__cdr(kscm, y)*/)
kscm__car(kscm, kscm->envir) = kscm__cons(kscm, kscm__cons(kscm, kscm__caar(kscm, x), kscm__car(kscm, y)), kscm__car(kscm, kscm->envir));
y = kscm__cdr(kscm, y);
if (kscm__issymbol(kscm, kscm__car(kscm, kscm->code))) { /* named let */
kscm->args = kscm->NIL;
for (x = kscm__cadr(kscm, kscm->code) /*, kscm->args = kscm->NIL*/; x != kscm->NIL; x = kscm__cdr(kscm, x))
kscm->args = kscm__cons(kscm, kscm__caar(kscm, x), kscm->args);
x = kscm__mk_closure(kscm, kscm__cons(kscm, kscm__reverse(kscm, kscm->args), kscm__cddr(kscm, kscm->code)), kscm->envir);
kscm__car(kscm, kscm->envir) = kscm__cons(kscm, kscm__cons(kscm, kscm__car(kscm, kscm->code), x), kscm__car(kscm, kscm->envir));
kscm->code = kscm__cddr(kscm, kscm->code);
kscm->args = kscm->NIL;
}
else {
kscm->code = kscm__cdr(kscm, kscm->code);
kscm->args = kscm->NIL;
}
kscm__s_goto(kscm, KSCM_OP_BEGIN);
case KSCM_OP_LET0AST: /* let* */
if (kscm__car(kscm, kscm->code) == kscm->NIL) {
kscm->envir = kscm__cons(kscm, kscm->NIL, kscm->envir);
kscm->code = kscm__cdr(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_BEGIN);
}
kscm__s_save(kscm, KSCM_OP_LET1AST, kscm__cdr(kscm, kscm->code), kscm__car(kscm, kscm->code));
kscm->code = kscm__cadaar(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_LET1AST: /* let* (make new frame) */
kscm->envir = kscm__cons(kscm, kscm->NIL, kscm->envir);
kscm__s_goto(kscm, KSCM_OP_LET2AST);
case KSCM_OP_LET2AST: /* let* (caluculate parameters) */
kscm__car(kscm, kscm->envir) = kscm__cons(kscm, kscm__cons(kscm, kscm__caar(kscm, kscm->code), kscm->value), kscm__car(kscm, kscm->envir));
kscm->code = kscm__cdr(kscm, kscm->code);
if (kscm__ispair(kscm, kscm->code)) { /* continue */
kscm__s_save(kscm, KSCM_OP_LET2AST, kscm->args, kscm->code);
kscm->code = kscm__cadar(kscm, kscm->code);
kscm->args = kscm->NIL;
kscm__s_goto(kscm, KSCM_OP_EVAL);
}
else { /* end */
kscm->code = kscm->args;
kscm->args = kscm->NIL;
kscm__s_goto(kscm, KSCM_OP_BEGIN);
}
default:
sprintf(kscm->strbuff, "%d is illegal operator", kscm->_operator);
kscm__error_0(kscm, kscm->strbuff);
}
return kscm->T;
}
kscm_object_t kscm__opexe_1(kscm_t* kscm, register short op)
{
register kscm_object_t x, y;
switch (op) {
case KSCM_OP_LET0REC: /* letrec */
kscm->envir = kscm__cons(kscm, kscm->NIL, kscm->envir);
kscm->args = kscm->NIL;
kscm->value = kscm->code;
kscm->code = kscm__car(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_LET1REC);
case KSCM_OP_LET1REC: /* letrec (caluculate parameters) */
kscm->args = kscm__cons(kscm, kscm->value, kscm->args);
if (kscm__ispair(kscm, kscm->code)) { /* continue */
kscm__s_save(kscm, KSCM_OP_LET1REC, kscm->args, kscm__cdr(kscm, kscm->code));
kscm->code = kscm__cadar(kscm, kscm->code);
kscm->args = kscm->NIL;
kscm__s_goto(kscm, KSCM_OP_EVAL);
}
else { /* end */
kscm->args = kscm__reverse(kscm, kscm->args);
kscm->code = kscm__car(kscm, kscm->args);
kscm->args = kscm__cdr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_LET2REC);
}
case KSCM_OP_LET2REC: /* letrec */
y = kscm->args;
for (x = kscm__car(kscm, kscm->code)/*, y = kscm->args*/; y != kscm->NIL; x = kscm__cdr(kscm, x)/*, y = kscm__cdr(kscm, y)*/) {
kscm__car(kscm, kscm->envir) = kscm__cons(kscm, kscm__cons(kscm, kscm__caar(kscm, x), kscm__car(kscm, y)), kscm__car(kscm, kscm->envir));
y = kscm__cdr(kscm, y);
}
kscm->code = kscm__cdr(kscm, kscm->code);
kscm->args = kscm->NIL;
kscm__s_goto(kscm, KSCM_OP_BEGIN);
case KSCM_OP_COND0: /* cond */
if (!kscm__ispair(kscm, kscm->code)) {
kscm__error_0(kscm, "Syntax error in cond");
}
kscm__s_save(kscm, KSCM_OP_COND1, kscm->NIL, kscm->code);
kscm->code = kscm__caar(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_COND1: /* cond */
if (kscm__istrue(kscm, kscm->value)) {
if ((kscm->code = kscm__cdar(kscm, kscm->code)) == kscm->NIL) {
kscm__s_return(kscm, kscm->value);
}
kscm__s_goto(kscm, KSCM_OP_BEGIN);
}
else {
if ((kscm->code = kscm__cdr(kscm, kscm->code)) == kscm->NIL) {
kscm__s_return(kscm, kscm->NIL);
}
else {
kscm__s_save(kscm, KSCM_OP_COND1, kscm->NIL, kscm->code);
kscm->code = kscm__caar(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
}
}
case KSCM_OP_DELAY: /* delay */
x = kscm__mk_closure(kscm, kscm__cons(kscm, kscm->NIL, kscm->code), kscm->envir);
kscm__setpromise(kscm, x);
kscm__s_return(kscm, x);
case KSCM_OP_AND0: /* and */
if (kscm->code == kscm->NIL) {
kscm__s_return(kscm, kscm->T);
}
kscm__s_save(kscm, KSCM_OP_AND1, kscm->NIL, kscm__cdr(kscm, kscm->code));
kscm->code = kscm__car(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_AND1: /* and */
if (kscm__isfalse(kscm, kscm->value)) {
kscm__s_return(kscm, kscm->value);
}
else if (kscm->code == kscm->NIL) {
kscm__s_return(kscm, kscm->value);
}
else {
kscm__s_save(kscm, KSCM_OP_AND1, kscm->NIL, kscm__cdr(kscm, kscm->code));
kscm->code = kscm__car(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
}
case KSCM_OP_OR0: /* or */
if (kscm->code == kscm->NIL) {
kscm__s_return(kscm, kscm->F);
}
kscm__s_save(kscm, KSCM_OP_OR1, kscm->NIL, kscm__cdr(kscm, kscm->code));
kscm->code = kscm__car(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_OR1: /* or */
if (kscm__istrue(kscm, kscm->value)) {
kscm__s_return(kscm, kscm->value);
}
else if (kscm->code == kscm->NIL) {
kscm__s_return(kscm, kscm->value);
}
else {
kscm__s_save(kscm, KSCM_OP_OR1, kscm->NIL, kscm__cdr(kscm, kscm->code));
kscm->code = kscm__car(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
}
case KSCM_OP_C0STREAM: /* cons-stream */
kscm__s_save(kscm, KSCM_OP_C1STREAM, kscm->NIL, kscm__cdr(kscm, kscm->code));
kscm->code = kscm__car(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_C1STREAM: /* cons-stream */
kscm->args = kscm->value; /* save value to register args for gc */
x = kscm__mk_closure(kscm, kscm__cons(kscm, kscm->NIL, kscm->code), kscm->envir);
kscm__setpromise(kscm, x);
kscm__s_return(kscm, kscm__cons(kscm, kscm->args, x));
#ifdef KSCM_CONFIG_USE_MACRO
case KSCM_OP_0MACRO: /* macro */
x = kscm__car(kscm, kscm->code);
kscm->code = kscm__cadr(kscm, kscm->code);
if (!kscm__issymbol(kscm, x)) {
kscm__error_0(kscm, "Variable is not symbol");
}
kscm__s_save(kscm, KSCM_OP_1MACRO, kscm->NIL, x);
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_1MACRO: /* macro */
kscm__type(kscm, kscm->value) |= KSCM_T_MACRO;
for (x = kscm__car(kscm, kscm->envir); x != kscm->NIL; x = kscm__cdr(kscm, x))
if (kscm__caar(kscm, x) == kscm->code)
break;
if (x != kscm->NIL)
kscm__cdar(kscm, x) = kscm->value;
else
kscm__car(kscm, kscm->envir) = kscm__cons(kscm, kscm__cons(kscm, kscm->code, kscm->value), kscm__car(kscm, kscm->envir));
kscm__s_return(kscm, kscm->code);
#endif
case KSCM_OP_CASE0: /* case */
kscm__s_save(kscm, KSCM_OP_CASE1, kscm->NIL, kscm__cdr(kscm, kscm->code));
kscm->code = kscm__car(kscm, kscm->code);
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_CASE1: /* case */
for (x = kscm->code; x != kscm->NIL; x = kscm__cdr(kscm, x)) {
if (!kscm__ispair(kscm, y = kscm__caar(kscm, x)))
break;
for (; y != kscm->NIL; y = kscm__cdr(kscm, y))
if (kscm__eqv(kscm, kscm__car(kscm, y), kscm->value))
break;
if (y != kscm->NIL)
break;
}
if (x != kscm->NIL) {
if (kscm__ispair(kscm, kscm__caar(kscm, x))) {
kscm->code = kscm__cdar(kscm, x);
kscm__s_goto(kscm, KSCM_OP_BEGIN);
}
else {/* else */
kscm__s_save(kscm, KSCM_OP_CASE2, kscm->NIL, kscm__cdar(kscm, x));
kscm->code = kscm__caar(kscm, x);
kscm__s_goto(kscm, KSCM_OP_EVAL);
}
}
else {
kscm__s_return(kscm, kscm->NIL);
}
case KSCM_OP_CASE2: /* case */
if (kscm__istrue(kscm, kscm->value)) {
kscm__s_goto(kscm, KSCM_OP_BEGIN);
}
else {
kscm__s_return(kscm, kscm->NIL);
}
case KSCM_OP_PAPPLY: /* apply */
kscm->code = kscm__car(kscm, kscm->args);
kscm->args = kscm__cadr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_APPLY);
case KSCM_OP_PEVAL: /* eval */
kscm->code = kscm__car(kscm, kscm->args);
kscm->args = kscm->NIL;
kscm__s_goto(kscm, KSCM_OP_EVAL);
case KSCM_OP_CONTINUATION: /* call-with-current-continuation */
kscm->code = kscm__car(kscm, kscm->args);
kscm->args = kscm__cons(kscm, kscm__mk_continuation(kscm, kscm->dump), kscm->NIL);
kscm__s_goto(kscm, KSCM_OP_APPLY);
default:
sprintf(kscm->strbuff, "%d is illegal operator", kscm->_operator);
kscm__error_0(kscm, kscm->strbuff);
}
return kscm->T;
}
kscm_object_t kscm__opexe_2(kscm_t* kscm, register short op)
{
register kscm_object_t x, y;
#ifdef KSCM_CONFIG_USE_PRECISE
int32_t v;
#else
register long v;
#endif
switch (op) {
case KSCM_OP_ADD: /* + */
v = 0;
for (x = kscm->args/*, v = 0*/; x != kscm->NIL; x = kscm__cdr(kscm, x)) {
if (!kscm__isnumber(kscm, kscm__car(kscm, x))) {
kscm__s_retbool(kscm, 0);
}
#ifdef KSCM_CONFIG_USE_PRECISE
int64_t lv = ((int64_t)v) + ((int64_t)kscm__ivalue(kscm, kscm__car(kscm, x)));
v = (int32_t)lv;
if (((int64_t)v) != lv) {
kscm__s_retbool(kscm, 0);
}
#else
v += kscm__ivalue(kscm, kscm__car(kscm, x));
#endif
}
kscm__s_return(kscm, kscm__mk_number(kscm, v));
case KSCM_OP_SUB: /* - */
v = v = kscm__ivalue(kscm, kscm__car(kscm, kscm->args));
for (x = kscm__cdr(kscm, kscm->args)/*, v = kscm__ivalue(kscm, kscm__car(kscm, kscm->args))*/; x != kscm->NIL; x = kscm__cdr(kscm, x)) {
if (!kscm__isnumber(kscm, kscm__car(kscm, x))) {
kscm__s_retbool(kscm, 0);
}
#ifdef KSCM_CONFIG_USE_PRECISE
int64_t lv = ((int64_t)v) - ((int64_t)kscm__ivalue(kscm, kscm__car(kscm, x)));
v = (int32_t)lv;
if (((int64_t)v) != lv) {
kscm__s_retbool(kscm, 0);
}
#else
v -= kscm__ivalue(kscm, kscm__car(kscm, x));
#endif
}
kscm__s_return(kscm, kscm__mk_number(kscm, v));
case KSCM_OP_MUL: /* * */
v = 1;
for (x = kscm->args/*, v = 1*/; x != kscm->NIL; x = kscm__cdr(kscm, x)) {
if (!kscm__isnumber(kscm, kscm__car(kscm, x))) {
kscm__s_retbool(kscm, 0);
}
#ifdef KSCM_CONFIG_USE_PRECISE
int64_t lv = ((int64_t)v) * ((int64_t)kscm__ivalue(kscm, kscm__car(kscm, x)));
v = (int32_t)lv;
if (((int64_t)v) != lv) {
kscm__s_retbool(kscm, 0);
}
#else
v *= kscm__ivalue(kscm, kscm__car(kscm, x));
#endif
}
kscm__s_return(kscm, kscm__mk_number(kscm, v));
case KSCM_OP_DIV: /* / */
v = kscm__ivalue(kscm, kscm__car(kscm, kscm->args));
for (x = kscm__cdr(kscm, kscm->args)/*, v = kscm__ivalue(kscm, kscm__car(kscm, kscm->args))*/; x != kscm->NIL; x = kscm__cdr(kscm, x)) {
if (!kscm__isnumber(kscm, kscm__car(kscm, x))) {
kscm__s_retbool(kscm, 0);
}
if (kscm__ivalue(kscm, kscm__car(kscm, x)) != 0)
v /= kscm__ivalue(kscm, kscm__car(kscm, x));
else {
#ifdef KSCM_CONFIG_USE_PRECISE
kscm__s_retbool(kscm, 0);
#else
kscm__error_0(kscm, "Divided by zero");
#endif
}
}
kscm__s_return(kscm, kscm__mk_number(kscm, v));
case KSCM_OP_REM: /* remainder */
v = kscm__ivalue(kscm, kscm__car(kscm, kscm->args));
for (x = kscm__cdr(kscm, kscm->args)/*, v = kscm__ivalue(kscm, kscm__car(kscm, kscm->args))*/; x != kscm->NIL; x = kscm__cdr(kscm, x)) {
if (!kscm__isnumber(kscm, kscm__car(kscm, x))) {
kscm__s_retbool(kscm, 0);
}
if (kscm__ivalue(kscm, kscm__car(kscm, x)) != 0)
v %= kscm__ivalue(kscm, kscm__car(kscm, x));
else {
#ifdef KSCM_CONFIG_USE_PRECISE
kscm__s_retbool(kscm, 0);
#else
kscm__error_0(kscm, "Divided by zero");
#endif
}
}
kscm__s_return(kscm, kscm__mk_number(kscm, v));
case KSCM_OP_CAR: /* car */
if (kscm__ispair(kscm, kscm__car(kscm, kscm->args))) {
kscm__s_return(kscm, kscm__caar(kscm, kscm->args));
}
else {
kscm__error_0(kscm, "Unable to car for non-cons cell");
}
case KSCM_OP_CDR: /* cdr */
if (kscm__ispair(kscm, kscm__car(kscm, kscm->args))) {
kscm__s_return(kscm, kscm__cdar(kscm, kscm->args));
}
else {
kscm__error_0(kscm, "Unable to cdr for non-cons cell");
}
case KSCM_OP_CONS: /* cons */
kscm__cdr(kscm, kscm->args) = kscm__cadr(kscm, kscm->args);
kscm__s_return(kscm, kscm->args);
case KSCM_OP_SETCAR: /* set-car! */
if (kscm__ispair(kscm, kscm__car(kscm, kscm->args))) {
kscm__caar(kscm, kscm->args) = kscm__cadr(kscm, kscm->args);
kscm__s_return(kscm, kscm__car(kscm, kscm->args));
}
else {
kscm__error_0(kscm, "Unable to set-car! for non-cons cell");
}
case KSCM_OP_SETCDR: /* set-cdr! */
if (kscm__ispair(kscm, kscm__car(kscm, kscm->args))) {
kscm__cdar(kscm, kscm->args) = kscm__cadr(kscm, kscm->args);
kscm__s_return(kscm, kscm__car(kscm, kscm->args));
}
else {
kscm__error_0(kscm, "Unable to set-cdr! for non-cons cell");
}
default:
sprintf(kscm->strbuff, "%d is illegal operator", kscm->_operator);
kscm__error_0(kscm, kscm->strbuff);
}
return kscm->T;
}
kscm_object_t kscm__opexe_3(kscm_t* kscm, register short op)
{
register kscm_object_t x, y;
switch (op) {
case KSCM_OP_NOT: /* not */
kscm__s_retbool(kscm, kscm__isfalse(kscm, kscm__car(kscm, kscm->args)));
case KSCM_OP_BOOL: /* boolean? */
kscm__s_retbool(kscm, kscm__car(kscm, kscm->args) == kscm->F || kscm__car(kscm, kscm->args) == kscm->T);
case KSCM_OP_NULL: /* null? */
kscm__s_retbool(kscm, kscm__car(kscm, kscm->args) == kscm->NIL);
case KSCM_OP_ZEROP: /* zero? */
kscm__s_retbool(kscm, kscm__ivalue(kscm, kscm__car(kscm, kscm->args)) == 0);
case KSCM_OP_POSP: /* positive? */
kscm__s_retbool(kscm, kscm__ivalue(kscm, kscm__car(kscm, kscm->args)) > 0);
case KSCM_OP_NEGP: /* negative? */
kscm__s_retbool(kscm, kscm__ivalue(kscm, kscm__car(kscm, kscm->args)) < 0);
case KSCM_OP_NEQ: /* = */
kscm__s_retbool(kscm, kscm__ivalue(kscm, kscm__car(kscm, kscm->args)) == kscm__ivalue(kscm, kscm__cadr(kscm, kscm->args)));
case KSCM_OP_LESS: /* < */
kscm__s_retbool(kscm, kscm__ivalue(kscm, kscm__car(kscm, kscm->args)) < kscm__ivalue(kscm, kscm__cadr(kscm, kscm->args)));
case KSCM_OP_GRE: /* > */
kscm__s_retbool(kscm, kscm__ivalue(kscm, kscm__car(kscm, kscm->args)) > kscm__ivalue(kscm, kscm__cadr(kscm, kscm->args)));
case KSCM_OP_LEQ: /* <= */
kscm__s_retbool(kscm, kscm__ivalue(kscm, kscm__car(kscm, kscm->args)) <= kscm__ivalue(kscm, kscm__cadr(kscm, kscm->args)));
case KSCM_OP_GEQ: /* >= */
kscm__s_retbool(kscm, kscm__ivalue(kscm, kscm__car(kscm, kscm->args)) >= kscm__ivalue(kscm, kscm__cadr(kscm, kscm->args)));
case KSCM_OP_SYMBOL: /* symbol? */
kscm__s_retbool(kscm, kscm__issymbol(kscm, kscm__car(kscm, kscm->args)));
case KSCM_OP_NUMBER: /* number? */
kscm__s_retbool(kscm, kscm__isnumber(kscm, kscm__car(kscm, kscm->args)));
case KSCM_OP_STRING: /* string? */
kscm__s_retbool(kscm, kscm__isstring(kscm, kscm__car(kscm, kscm->args)));
case KSCM_OP_PROC: /* procedure? */
/*--
* continuation should be procedure by the example
* (call-with-current-continuation procedure?) ==> #t
* in R^3 report sec. 6.9
*/
kscm__s_retbool(kscm, kscm__isproc(kscm, kscm__car(kscm, kscm->args)) || kscm__isclosure(kscm, kscm__car(kscm, kscm->args))
|| kscm__iscontinuation(kscm, kscm__car(kscm, kscm->args)));
case KSCM_OP_PAIR: /* pair? */
kscm__s_retbool(kscm, kscm__ispair(kscm, kscm__car(kscm, kscm->args)));
case KSCM_OP_EQ: /* eq? */
kscm__s_retbool(kscm, kscm__car(kscm, kscm->args) == kscm__cadr(kscm, kscm->args));
case KSCM_OP_EQV: /* eqv? */
kscm__s_retbool(kscm, kscm__eqv(kscm, kscm__car(kscm, kscm->args), kscm__cadr(kscm, kscm->args)));
default:
sprintf(kscm->strbuff, "%d is illegal operator", kscm->_operator);
kscm__error_0(kscm, kscm->strbuff);
}
return kscm->T;
}
kscm_object_t kscm__opexe_4(kscm_t* kscm, register short op)
{
register kscm_object_t x, y;
switch (op) {
case KSCM_OP_FORCE: /* force */
kscm->code = kscm__car(kscm, kscm->args);
if (kscm__ispromise(kscm, kscm->code)) {
kscm->args = kscm->NIL;
kscm__s_goto(kscm, KSCM_OP_APPLY);
}
else {
kscm__s_return(kscm, kscm->code);
}
case KSCM_OP_WRITE: /* write */
kscm->print_flag = 1;
kscm->args = kscm__car(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0LIST);
case KSCM_OP_DISPLAY: /* display */
kscm->print_flag = 0;
kscm->args = kscm__car(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0LIST);
case KSCM_OP_NEWLINE: /* newline */
fprintf(kscm->outfp, "\n");
kscm__s_return(kscm, kscm->T);
case KSCM_OP_ERR0: /* error */
if (!kscm__isstring(kscm, kscm__car(kscm, kscm->args))) {
kscm__error_0(kscm, "error -- first argument must be string");
}
kscm->tmpfp = kscm->outfp;
kscm->outfp = stderr;
if (kscm->all_errors_fatal) {
kscm__fatal_error(kscm, kscm__strvalue(kscm, kscm__car(kscm, kscm->args)), NULL, NULL, NULL);
}
fprintf(kscm->outfp, "Error: ");
fprintf(kscm->outfp, "%s", kscm__strvalue(kscm, kscm__car(kscm, kscm->args)));
kscm->args = kscm__cdr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_ERR1);
case KSCM_OP_ERR1: /* error */
fprintf(kscm->outfp, " ");
if (kscm->args != kscm->NIL) {
kscm__s_save(kscm, KSCM_OP_ERR1, kscm__cdr(kscm, kscm->args), kscm->NIL);
kscm->args = kscm__car(kscm, kscm->args);
kscm->print_flag = 1;
kscm__s_goto(kscm, KSCM_OP_P0LIST);
}
else {
fprintf(kscm->outfp, "\n");
kscm__resetinput(kscm);
kscm->outfp = kscm->tmpfp;
kscm__s_goto(kscm, KSCM_OP_T0LVL);
}
case KSCM_OP_REVERSE: /* reverse */
kscm__s_return(kscm, kscm__reverse(kscm, kscm__car(kscm, kscm->args)));
case KSCM_OP_APPEND: /* append */
kscm__s_return(kscm, kscm__append(kscm, kscm__car(kscm, kscm->args), kscm__cadr(kscm, kscm->args)));
case KSCM_OP_PUT: /* put */
if (!kscm__hasprop(kscm, kscm__car(kscm, kscm->args)) || !kscm__hasprop(kscm, kscm__cadr(kscm, kscm->args))) {
kscm__error_0(kscm, "Illegal use of put");
}
y = kscm__cadr(kscm, kscm->args);
for (x = kscm__symprop(kscm, kscm__car(kscm, kscm->args))/*, y = kscm__cadr(kscm, kscm->args)*/; x != kscm->NIL; x = kscm__cdr(kscm, x))
if (kscm__caar(kscm, x) == y)
break;
if (x != kscm->NIL)
kscm__cdar(kscm, x) = kscm__caddr(kscm, kscm->args);
else
kscm__symprop(kscm, kscm__car(kscm, kscm->args)) = kscm__cons(kscm, kscm__cons(kscm, y, kscm__caddr(kscm, kscm->args)),
kscm__symprop(kscm, kscm__car(kscm, kscm->args)));
kscm__s_return(kscm, kscm->T);
case KSCM_OP_GET: /* get */
if (!kscm__hasprop(kscm, kscm__car(kscm, kscm->args)) || !kscm__hasprop(kscm, kscm__cadr(kscm, kscm->args))) {
kscm__error_0(kscm, "Illegal use of get");
}
y = kscm__cadr(kscm, kscm->args);
for (x = kscm__symprop(kscm, kscm__car(kscm, kscm->args))/*, y = kscm__cadr(kscm, kscm->args)*/; x != kscm->NIL; x = kscm__cdr(kscm, x))
if (kscm__caar(kscm, x) == y)
break;
if (x != kscm->NIL) {
kscm__s_return(kscm, kscm__cdar(kscm, x));
}
else {
kscm__s_return(kscm, kscm->NIL);
}
case KSCM_OP_QUIT: /* quit */
return (kscm->NIL);
case KSCM_OP_GC: /* gc */
kscm__gc(kscm, kscm->NIL, kscm->NIL);
kscm__s_return(kscm, kscm->T);
case KSCM_OP_GCVERB: /* gc-verbose */
{ int was = kscm->gc_verbose;
kscm->gc_verbose = (kscm__car(kscm, kscm->args) != kscm->F);
kscm__s_retbool(kscm, was);
}
case KSCM_OP_NEWSEGMENT: /* new-segment */
if (!kscm__isnumber(kscm, kscm__car(kscm, kscm->args))) {
kscm__error_0(kscm, "new-segment -- argument must be number");
}
fprintf(kscm->outfp, "allocate %d new segments\n",
kscm__alloc_cellseg(kscm, (int)kscm__ivalue(kscm, kscm__car(kscm, kscm->args))));
kscm__s_return(kscm, kscm->T);
}
}
kscm_object_t kscm__opexe_5(kscm_t* kscm, register short op)
{
register kscm_object_t x, y;
switch (op) {
/* ========== reading part ========== */
case KSCM_OP_RDSEXPR:
switch (kscm->tok) {
case KSCM_TOK_COMMENT:
while (kscm__inchar(kscm) != '\n')
;
kscm->tok = kscm__token(kscm);
kscm__s_goto(kscm, KSCM_OP_RDSEXPR);
case KSCM_TOK_LPAREN:
kscm->tok = kscm__token(kscm);
if (kscm->tok == KSCM_TOK_RPAREN) {
kscm__s_return(kscm, kscm->NIL);
}
else if (kscm->tok == KSCM_TOK_DOT) {
kscm__error_0(kscm, "syntax error -- illegal dot expression");
}
else {
kscm__s_save(kscm, KSCM_OP_RDLIST, kscm->NIL, kscm->NIL);
kscm__s_goto(kscm, KSCM_OP_RDSEXPR);
}
case KSCM_TOK_QUOTE:
kscm__s_save(kscm, KSCM_OP_RDQUOTE, kscm->NIL, kscm->NIL);
kscm->tok = kscm__token(kscm);
kscm__s_goto(kscm, KSCM_OP_RDSEXPR);
#ifdef KSCM_CONFIG_USE_QQUOTE
case KSCM_TOK_BQUOTE:
kscm__s_save(kscm, KSCM_OP_RDQQUOTE, kscm->NIL, kscm->NIL);
kscm->tok = kscm__token(kscm);
kscm__s_goto(kscm, KSCM_OP_RDSEXPR);
case KSCM_TOK_COMMA:
kscm__s_save(kscm, KSCM_OP_RDUNQUOTE, kscm->NIL, kscm->NIL);
kscm->tok = kscm__token(kscm);
kscm__s_goto(kscm, KSCM_OP_RDSEXPR);
case KSCM_TOK_ATMARK:
kscm__s_save(kscm, KSCM_OP_RDUQTSP, kscm->NIL, kscm->NIL);
kscm->tok = kscm__token(kscm);
kscm__s_goto(kscm, KSCM_OP_RDSEXPR);
#endif
case KSCM_TOK_ATOM:
kscm__s_return(kscm, kscm__mk_atom(kscm, kscm__readstr(kscm, "();\t\n ")));
case KSCM_TOK_DQUOTE:
kscm__s_return(kscm, kscm__mk_string(kscm, kscm__readstrexp(kscm)));
case KSCM_TOK_SHARP:
if ((x = kscm__mk_const(kscm, kscm__readstr(kscm, "();\t\n "))) == kscm->NIL) {
kscm__error_0(kscm, "Undefined sharp expression");
}
else {
kscm__s_return(kscm, x);
}
default:
kscm__error_0(kscm, "syntax error -- illegal token");
}
break;
case KSCM_OP_RDLIST:
kscm->args = kscm__cons(kscm, kscm->value, kscm->args);
kscm->tok = kscm__token(kscm);
if (kscm->tok == KSCM_TOK_COMMENT) {
while (kscm__inchar(kscm) != '\n')
;
kscm->tok = kscm__token(kscm);
}
if (kscm->tok == KSCM_TOK_RPAREN) {
kscm__s_return(kscm, kscm__non_alloc_rev(kscm, kscm->NIL, kscm->args));
}
else if (kscm->tok == KSCM_TOK_DOT) {
kscm__s_save(kscm, KSCM_OP_RDDOT, kscm->args, kscm->NIL);
kscm->tok = kscm__token(kscm);
kscm__s_goto(kscm, KSCM_OP_RDSEXPR);
}
else {
kscm__s_save(kscm, KSCM_OP_RDLIST, kscm->args, kscm->NIL);;
kscm__s_goto(kscm, KSCM_OP_RDSEXPR);
}
case KSCM_OP_RDDOT:
if (kscm__token(kscm) != KSCM_TOK_RPAREN) {
kscm__error_0(kscm, "syntax error -- illegal dot expression");
}
else {
kscm__s_return(kscm, kscm__non_alloc_rev(kscm, kscm->value, kscm->args));
}
case KSCM_OP_RDQUOTE:
kscm__s_return(kscm, kscm__cons(kscm, kscm->QUOTE, kscm__cons(kscm, kscm->value, kscm->NIL)));
#ifdef KSCM_CONFIG_USE_QQUOTE
case KSCM_OP_RDQQUOTE:
kscm__s_return(kscm, kscm__cons(kscm, kscm->QQUOTE, kscm__cons(kscm, kscm->value, kscm->NIL)));
case KSCM_OP_RDUNQUOTE:
kscm__s_return(kscm, kscm__cons(kscm, kscm->UNQUOTE, kscm__cons(kscm, kscm->value, kscm->NIL)));
case KSCM_OP_RDUQTSP:
kscm__s_return(kscm, kscm__cons(kscm, kscm->UNQUOTESP, kscm__cons(kscm, kscm->value, kscm->NIL)));
#endif
/* ========== printing part ========== */
case KSCM_OP_P0LIST:
if (!kscm__ispair(kscm, kscm->args)) {
kscm__printatom(kscm, kscm->args, kscm->print_flag);
kscm__s_return(kscm, kscm->T);
}
else if (kscm__car(kscm, kscm->args) == kscm->QUOTE && kscm__ok_abbrev(kscm, kscm__cdr(kscm, kscm->args))) {
fprintf(kscm->outfp, "'");
kscm->args = kscm__cadr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0LIST);
}
else if (kscm__car(kscm, kscm->args) == kscm->QQUOTE && kscm__ok_abbrev(kscm, kscm__cdr(kscm, kscm->args))) {
fprintf(kscm->outfp, "`");
kscm->args = kscm__cadr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0LIST);
}
else if (kscm__car(kscm, kscm->args) == kscm->UNQUOTE && kscm__ok_abbrev(kscm, kscm__cdr(kscm, kscm->args))) {
fprintf(kscm->outfp, ",");
kscm->args = kscm__cadr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0LIST);
}
else if (kscm__car(kscm, kscm->args) == kscm->UNQUOTESP && kscm__ok_abbrev(kscm, kscm__cdr(kscm, kscm->args))) {
fprintf(kscm->outfp, ",@");
kscm->args = kscm__cadr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0LIST);
}
else {
fprintf(kscm->outfp, "(");
kscm__s_save(kscm, KSCM_OP_P1LIST, kscm__cdr(kscm, kscm->args), kscm->NIL);
kscm->args = kscm__car(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0LIST);
}
case KSCM_OP_P1LIST:
if (kscm__ispair(kscm, kscm->args)) {
kscm__s_save(kscm, KSCM_OP_P1LIST, kscm__cdr(kscm, kscm->args), kscm->NIL);
fprintf(kscm->outfp, " ");
kscm->args = kscm__car(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0LIST);
}
else {
if (kscm->args != kscm->NIL) {
fprintf(kscm->outfp, " . ");
kscm__printatom(kscm, kscm->args, kscm->print_flag);
}
fprintf(kscm->outfp, ")");
kscm__s_return(kscm, kscm->T);
}
default:
sprintf(kscm->strbuff, "%d is illegal operator", kscm->_operator);
kscm__error_0(kscm, kscm->strbuff);
}
return kscm->T;
}
kscm_object_t kscm__opexe_6(kscm_t* kscm, register short op)
{
register kscm_object_t x, y;
register long v;
static long w;
char buffer[32];
switch (op) {
case KSCM_OP_LIST_LENGTH: /* list-length */ /* a.k */
v = 0;
for (x = kscm__car(kscm, kscm->args)/*, v = 0*/; kscm__ispair(kscm, x); x = kscm__cdr(kscm, x))
++v;
kscm__s_return(kscm, kscm__mk_number(kscm, v));
case KSCM_OP_ASSQ: /* assq */ /* a.k */
x = kscm__car(kscm, kscm->args);
for (y = kscm__cadr(kscm, kscm->args); kscm__ispair(kscm, y); y = kscm__cdr(kscm, y)) {
if (!kscm__ispair(kscm, kscm__car(kscm, y))) {
kscm__error_0(kscm, "Unable to handle non pair element");
}
if (x == kscm__caar(kscm, y))
break;
}
if (kscm__ispair(kscm, y)) {
kscm__s_return(kscm, kscm__car(kscm, y));
}
else {
kscm__s_return(kscm, kscm->F);
}
case KSCM_OP_PRINT_WIDTH: /* print-width */ /* a.k */
w = 0;
kscm->args = kscm__car(kscm, kscm->args);
kscm->print_flag = -1;
kscm__s_goto(kscm, KSCM_OP_P0_WIDTH);
case KSCM_OP_P0_WIDTH:
if (!kscm__ispair(kscm, kscm->args)) {
w += kscm__printatom(kscm, kscm->args, kscm->print_flag);
kscm__s_return(kscm, kscm__mk_number(kscm, w));
}
else if (kscm__car(kscm, kscm->args) == kscm->QUOTE
&& kscm__ok_abbrev(kscm, kscm__cdr(kscm, kscm->args))) {
++w;
kscm->args = kscm__cadr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0_WIDTH);
}
else if (kscm__car(kscm, kscm->args) == kscm->QQUOTE
&& kscm__ok_abbrev(kscm, kscm__cdr(kscm, kscm->args))) {
++w;
kscm->args = kscm__cadr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0_WIDTH);
}
else if (kscm__car(kscm, kscm->args) == kscm->UNQUOTE
&& kscm__ok_abbrev(kscm, kscm__cdr(kscm, kscm->args))) {
++w;
kscm->args = kscm__cadr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0_WIDTH);
}
else if (kscm__car(kscm, kscm->args) == kscm->UNQUOTESP
&& kscm__ok_abbrev(kscm, kscm__cdr(kscm, kscm->args))) {
w += 2;
kscm->args = kscm__cadr(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0_WIDTH);
}
else {
++w;
kscm__s_save(kscm, KSCM_OP_P1_WIDTH, kscm__cdr(kscm, kscm->args), kscm->NIL);
kscm->args = kscm__car(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0_WIDTH);
}
case KSCM_OP_P1_WIDTH:
if (kscm__ispair(kscm, kscm->args)) {
kscm__s_save(kscm, KSCM_OP_P1_WIDTH, kscm__cdr(kscm, kscm->args), kscm->NIL);
++w;
kscm->args = kscm__car(kscm, kscm->args);
kscm__s_goto(kscm, KSCM_OP_P0_WIDTH);
}
else {
if (kscm->args != kscm->NIL)
w += 3 + kscm__printatom(kscm, kscm->args, kscm->print_flag);
++w;
kscm__s_return(kscm, kscm__mk_number(kscm, w));
}
case KSCM_OP_GET_CLOSURE: /* get-closure-code */ /* a.k */
kscm->args = kscm__car(kscm, kscm->args);
if (kscm->args == kscm->NIL) {
kscm__s_return(kscm, kscm->F);
}
else if (kscm__isclosure(kscm, kscm->args)) {
kscm__s_return(kscm, kscm__cons(kscm, kscm->LAMBDA, kscm__closure_code(kscm, kscm->value)));
#ifdef KSCM_CONFIG_USE_MACRO
}
else if (kscm__ismacro(kscm, kscm->args)) {
kscm__s_return(kscm, kscm__cons(kscm, kscm->LAMBDA, kscm__closure_code(kscm, kscm->value)));
#endif
}
else {
kscm__s_return(kscm, kscm->F);
}
case KSCM_OP_CLOSUREP: /* closure? */
/*
* Note, macro object is also a closure.
* Therefore, (closure? <#MACRO>) ==> #t
*/
if (kscm__car(kscm, kscm->args) == kscm->NIL) {
kscm__s_return(kscm, kscm->F);
}
kscm__s_retbool(kscm, kscm__isclosure(kscm, kscm__car(kscm, kscm->args)));
#ifdef KSCM_CONFIG_USE_MACRO
case KSCM_OP_MACROP: /* macro? */
if (kscm__car(kscm, kscm->args) == kscm->NIL) {
kscm__s_return(kscm, kscm->F);
}
kscm__s_retbool(kscm, kscm__ismacro(kscm, kscm__car(kscm, kscm->args)));
#endif
default:
sprintf(kscm->strbuff, "%d is illegal operator", kscm->_operator);
kscm__error_0(kscm, kscm->strbuff);
}
return kscm->T; /* NOTREACHED */
}
#ifdef KSCM_CONFIG_USE_PERSIST
unsigned int kscm_get_persistent_address(kscm_t* kscm, kscm_object_t obj) {
int i;
if (obj == kscm->NIL) {
return 0;
} else if (obj == kscm->F) {
return 1;
} else if (obj == kscm->T) {
return 2;
}
uintptr_t addr = (uintptr_t)obj;
//fprintf(stderr, "addr is %d\n", addr);
for (i = 0; i <= kscm->last_cell_seg; i++) {
uintptr_t segaddr = (uintptr_t)(kscm->cell_seg[i]);
//fprintf(stderr, "segaddr %d is %d\n", i, segaddr);
if (segaddr != 0 && addr >= segaddr && addr < segaddr + (KSCM_CONFIG_CELL_SEGSIZE * sizeof(struct kscm_cell))) {
//fprintf(stderr, "it's in here!\n");
int segment = i + 1;
uintptr_t offset = addr - segaddr;
if ((offset % sizeof(struct kscm_cell))) {
return -1;
}
int index = offset / sizeof(struct kscm_cell);
return (segment * KSCM_CONFIG_CELL_SEGSIZE) + index;
}
}
return -1;
}
int kscm__fwrite_byte(kscm_t* kscm, FILE* f, char val) {
fputc(val, f);
return 1;
}
int kscm__fwrite_int(kscm_t* kscm, FILE* f, int val) {
//fprintf(stderr, "writing %x %x %x %x\n", val & 0xFF, (val >> 8) & 0xFF, (val >> 16) & 0xFF, (val >> 24) & 0xFF);
fputc((val & 0xFF), f);
fputc(((val >> 8) & 0xFF), f);
fputc(((val >> 16) & 0xFF), f);
fputc(((val >> 24) & 0xFF), f);
return 4;
}
int kscm__fwrite_strl(kscm_t* kscm, FILE* f, const char* str, int len) {
if (str == NULL) {
return kscm__fwrite_int(kscm, f, 0);
}
int written = kscm__fwrite_int(kscm, f, len);
if (written != 4) {
return written;
}
int i;
for (i = 0; i < len; i++) {
fputc(str[i], f);
written++;
}
return written;
}
int kscm__fwrite_str(kscm_t* kscm, FILE* f, const char* str) {
return kscm__fwrite_strl(kscm, f, str, strlen(str));
}
int kscm_save_state(kscm_t* kscm, const char* filename, const char* opts) {
if (filename == NULL || strlen(filename) < 1) {
fprintf(stderr, "Filename expected\n");
return -1;
}
FILE* f = fopen(filename, "wb");
if (f == NULL) {
fprintf(stderr, "Failed to open '%s' for writing\n", filename);
return -1; // Not saved
}
fprintf(stderr, "Saving state to '%s' opts '%s'...\n", filename, opts);
kscm__fwrite_str(kscm, f, KSCM_CONFIG_PERSIST_MAGIC);
//fclose(f); if (1) return 0;
kscm__fwrite_int(kscm, f, KSCM_CONFIG_PERSIST_VERSION);
// Bytes per id (higher bits may be reused later for flags)
kscm__fwrite_int(kscm, f, kscm->_stateformat);
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->NIL));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->F));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->T));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->oblist));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->global_env));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->LAMBDA));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->QUOTE));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->QQUOTE));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->UNQUOTE));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->UNQUOTESP));
/* NOTE: The format has been reorganised (as of "version 2" of the format) to allow for
* multithreading, which isn't supported on this implementation, but now thread-specific
* data is stored separately.
*/
/* Begin by writing the number of threads (always 1, for now). */
kscm__fwrite_int(kscm, f, 1);
kscm__fwrite_int(kscm, f, kscm->_threadstate);
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->_threadname));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->_threadopts));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->_threadobject));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->args));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->envir));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->code));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->dump));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->value));
kscm__fwrite_int(kscm, f, kscm->_operator);
//fprintf(stderr, "Persistent addresses: ->T=%d ->F=%d ->NIL=%d\n", kscm_get_persistent_address(kscm, kscm->T), kscm_get_persistent_address(kscm, kscm->F), kscm_get_persistent_address(kscm, kscm->NIL));
//fprintf(stderr, "Persistent addresses: ->args=%d ->envir=%d ->code=%d ->dump=%d\n", kscm_get_persistent_address(kscm, kscm->args), kscm_get_persistent_address(kscm, kscm->envir), kscm_get_persistent_address(kscm, kscm->code), kscm_get_persistent_address(kscm, kscm->dump));
int s;
for (s = 0; s <= kscm->last_cell_seg; s++) {
fprintf(stderr, ".");
int i;
for (i = 0; i < KSCM_CONFIG_CELL_SEGSIZE; i++) {
kscm_object_t obj = (kscm->cell_seg[s])+i;//&(kscm->cell_seg[s][i]);
if (obj->_flag == 0) { // free ?
//fprintf(stderr, "Object at %d:%d is free\n", s, i);
}
else {
fprintf(stderr, "Object at %d:%d is non-free\n", s, i);
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, obj));
if (kscm__isnumber(kscm, obj)) {
if (!kscm__isatom(kscm, obj)) {
fprintf(stderr, "int isn't atom\n");
exit(-1);
}
kscm__fwrite_byte(kscm, f, KSCM_PERSIST_TINT32);
kscm__fwrite_int(kscm, f, kscm__ivalue(kscm, obj));
}
else if (kscm__issymbol(kscm, obj)) {
if (kscm__isatom(kscm, obj)) {
fprintf(stderr, "symbol is atom\n");
exit(-1);
}
kscm__fwrite_byte(kscm, f, kscm__issyntax(kscm, obj) ? KSCM_PERSIST_TSYNTAX : KSCM_PERSIST_TSYMBOL);
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm__car(kscm, obj)));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm__cdr(kscm, obj)));
}
else if (kscm__isstring(kscm, obj)) {
if (!kscm__isatom(kscm, obj)) {
fprintf(stderr, "string isn't atom\n");
exit(-1);
}
kscm__fwrite_byte(kscm, f, KSCM_PERSIST_TSTRING);
kscm__fwrite_int(kscm, f, obj->_object._string._keynum);
kscm__fwrite_str(kscm, f, kscm__strvalue(kscm, obj));
}
else if (kscm__ispair(kscm, obj)) {
if (kscm__isatom(kscm, obj)) {
fprintf(stderr, "pair is atom\n");
exit(-1);
}
kscm__fwrite_byte(kscm, f, KSCM_PERSIST_TPAIR);
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm__car(kscm, obj)));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm__cdr(kscm, obj)));
}
else if (kscm__isproc(kscm, obj)) {
if (!kscm__isatom(kscm, obj)) {
fprintf(stderr, "proc isn't atom\n");
exit(-1);
}
kscm__fwrite_byte(kscm, f, KSCM_PERSIST_TPROC);
kscm__fwrite_int(kscm, f, kscm__ivalue(kscm, obj));
}
else if (kscm__isclosure(kscm, obj)) {
if (kscm__isatom(kscm, obj)) {
fprintf(stderr, "closure is atom\n");
exit(-1);
}
kscm__fwrite_byte(kscm, f, KSCM_PERSIST_TCLOSURE);
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm__car(kscm, obj)));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm__cdr(kscm, obj)));
}
else if (kscm__iscontinuation(kscm, obj)) {
if (kscm__isatom(kscm, obj)) {
fprintf(stderr, "closure is atom\n");
exit(-1);
}
kscm__fwrite_byte(kscm, f, KSCM_PERSIST_TCONTINUATION);
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm__car(kscm, obj)));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm__cdr(kscm, obj)));
}
#ifdef KSCM_CONFIG_USE_STRUCTS
else if (kscm__isabstraction(kscm, obj)) {
if (kscm__isatom(kscm, obj)) {
fprintf(stderr, "abstraction is atom\n");
exit(-1);
}
kscm__fwrite_byte(kscm, f, KSCM_PERSIST_TABSTRACTION);
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm__car(kscm, obj)));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm__cdr(kscm, obj)));
}
else if (kscm__isbuffer(kscm, obj)) {
if (!kscm__isatom(kscm, obj)) {
fprintf(stderr, "buffer isn't atom\n");
exit(-1);
}
kscm__fwrite_byte(kscm, f, KSCM_PERSIST_TBUFFER);
kscm__fwrite_strl(kscm, f, (const char*)(obj->_object._buffer._data), obj->_object._buffer._length);
}
#endif
#ifdef KSCM_CONFIG_USE_FLOATS
else if (kscm__isfloat64(kscm, obj)) {
double tmp = obj->_object._float64._dvalue;
char* bytes = (char*)(void*)(&tmp) /*obj->_object._float64._dvalue*/;
kscm__fwrite_byte(kscm, f, KSCM_PERSIST_TFLOAT64);
// NOTE: This assumes floating-point endian is the same on all platforms
kscm__fwrite_byte(kscm, f, bytes[0]);
kscm__fwrite_byte(kscm, f, bytes[1]);
kscm__fwrite_byte(kscm, f, bytes[2]);
kscm__fwrite_byte(kscm, f, bytes[3]);
kscm__fwrite_byte(kscm, f, bytes[4]);
kscm__fwrite_byte(kscm, f, bytes[5]);
kscm__fwrite_byte(kscm, f, bytes[6]);
kscm__fwrite_byte(kscm, f, bytes[7]);
}
#endif
#ifdef KSCM_CONFIG_USE_OBJECTS
else if (kscm__isobjx(kscm, obj)) {
if (kscm__isatom(kscm, obj)) {
fprintf(stderr, "object is atom\n");
exit(-1);
}
kscm__fwrite_byte(kscm, f, KSCM_PERSIST_TOBJX);
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, obj->_object._objx._type));
kscm__fwrite_int(kscm, f, obj->_object._objx._count);
int i;
for (i = 0; i < obj->_object._objx._count; i++) {
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, obj->_object._objx._elements[i]));
}
}
#endif
else {
fprintf(stderr, "Object at %d:%d is non-free but unknown type: %d\n", s, i, obj->_flag);
return -1; // Not saved
}
}
}
}
kscm__fwrite_int(kscm, f, 0); // Zero address to indicate end of objects
kscm__fwrite_int(kscm, f, 0); // Additional zero to indicate no additional data (may be extended in future versions)
fclose(f);
fprintf(stderr, "\n");
return 0; // Saved
}
int kscm__fread_byte(kscm_t* kscm, FILE* f, char* result) {
int r = fgetc(f);
*result = r;
return 1;
}
int kscm__fread_int(kscm_t* kscm, FILE* f, int* result) {
*result = 0;
*result |= (fgetc(f) & 0xff);
*result |= (fgetc(f) & 0xff) << 8;
*result |= (fgetc(f) & 0xff) << 16;
*result |= (fgetc(f) & 0xff) << 24;
return 4;
}
int kscm__fread_str(kscm_t* kscm, FILE* f, const char** result) {
int len;
if (kscm__fread_int(kscm, f, &len) != 4) {
*result = NULL;
return 0;
}
//fprintf(stderr, "Got length %d\n", len);
if (len > 1000) {
*result = NULL;
return 0;
}
*result = (const char*) calloc(len + 1, 1);
if (*result == NULL) {
return 0;
}
int i;
for (i = 0; i < len; i++) {
((* (char**)result)[i]) = (char)fgetc(f);
}
return len;
}
kscm_object_t kscm_get_object_address(kscm_t* kscm, int persistent_address) {
if (persistent_address == 0) {
return kscm->NIL;
} else if (persistent_address == 1) {
return kscm->F;
} else if (persistent_address == 2) {
return kscm->T;
}
int idx = persistent_address % KSCM_CONFIG_CELL_SEGSIZE;
int segnum = persistent_address / KSCM_CONFIG_CELL_SEGSIZE;
if (segnum < 1) {
return NULL;
}
segnum--;
if (segnum >= KSCM_CONFIG_CELL_NSEGMENT) {
return NULL;
}
while (segnum > kscm->last_cell_seg) {
kscm->last_cell_seg++;
kscm->cell_seg[kscm->last_cell_seg] = (kscm_object_t) calloc(KSCM_CONFIG_CELL_SEGSIZE, sizeof(struct kscm_cell));
}
return kscm->cell_seg[segnum] + idx; //&kscm->cell_seg[segnum][idx];
}
int kscm_resume_state(kscm_t* kscm, const char* filename, const char* opts) {
if (filename == NULL || strlen(filename) < 1) {
fprintf(stderr, "Filename expected\n");
return -1;
}
FILE* f = fopen(filename, "rb");
if (f == NULL) {
fprintf(stderr, "Failed to open '%s' for reading\n", filename);
return -1; // Not saved
}
fprintf(stderr, "Reading state from '%s' opts '%s'...\n", filename, opts);
const char* tmpstr;
int tmpint;
kscm__fread_str(kscm, f, &tmpstr);
if (tmpstr == NULL || strcmp(tmpstr, KSCM_CONFIG_PERSIST_MAGIC) != 0) {
fprintf(stderr, "Failed to read '%s': Bad magic string\n", filename);
free((void*)tmpstr);
return -1;
}
free((void*)tmpstr);
kscm__fread_int(kscm, f, &tmpint);
if (tmpint != KSCM_CONFIG_PERSIST_VERSION) {
fprintf(stderr, "Failed to read '%s': Bad version number, expected %d but got %d\n", filename, KSCM_CONFIG_PERSIST_VERSION, tmpint);
return -1;
}
kscm__fread_int(kscm, f, &tmpint);
if (tmpint != 4) {
fprintf(stderr, "Failed to read '%s': Bad format options, expected 4 but got %d\n", filename, tmpint);
return -1;
}
kscm->_stateformat = tmpint;
kscm__fread_int(kscm, f, &tmpint);
if (tmpint != 0) {
fprintf(stderr, "Failed to read '%s': Bad NIL index, expected %d but got %d\n", filename, 0, tmpint);
return -1;
}
kscm__fread_int(kscm, f, &tmpint);
if (tmpint != 1) {
fprintf(stderr, "Failed to read '%s': Bad F index, expected %d but got %d\n", filename, 1, tmpint);
return -1;
}
kscm__fread_int(kscm, f, &tmpint);
if (tmpint != 2) {
fprintf(stderr, "Failed to read '%s': Bad T index, expected %d but got %d\n", filename, 2, tmpint);
return -1;
}
kscm__fread_int(kscm, f, &tmpint);
kscm->oblist = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->global_env = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->LAMBDA = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->QUOTE = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->QQUOTE = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->UNQUOTE = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->UNQUOTESP = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
if (tmpint != 1) {
fprintf(stderr, "Failed to read '%s': Bad number of threads, this VM only supports 1 thread but got %d\n", filename, tmpint);
return -1;
}
/*
kscm__fwrite_int(kscm, f, 1);
kscm__fwrite_int(kscm, f, kscm->_threadstate);
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->_threadname));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->_threadopts));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->_threadobject));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->args));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->envir));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->code));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->dump));
kscm__fwrite_int(kscm, f, kscm_get_persistent_address(kscm, kscm->value));
kscm__fwrite_int(kscm, f, kscm->_operator);
*/
kscm__fread_int(kscm, f, &tmpint);
kscm->_threadstate = tmpint;
kscm__fread_int(kscm, f, &tmpint);
kscm->_threadname = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->_threadopts = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->_threadobject = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->args = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->envir = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->code = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->dump = kscm_get_object_address(kscm, tmpint);
/* At least for the main thread, the value/operator options are discarded. */
kscm__fread_int(kscm, f, &tmpint);
kscm__fread_int(kscm, f, &tmpint);
kscm->value = kscm->NIL; //kscm_get_object_address(kscm, tmpint);
kscm->_operator = 0;
//fprintf(stderr, "Persistent addresses: ->T=%d ->F=%d ->NIL=%d\n", kscm_get_persistent_address(kscm, kscm->T), kscm_get_persistent_address(kscm, kscm->F), kscm_get_persistent_address(kscm, kscm->NIL));
//fprintf(stderr, "Persistent addresses: ->args=%d ->envir=%d ->code=%d ->dump=%d\n", kscm_get_persistent_address(kscm, kscm->args), kscm_get_persistent_address(kscm, kscm->envir), kscm_get_persistent_address(kscm, kscm->code), kscm_get_persistent_address(kscm, kscm->dump));
/* Clear all of the cell memory. Any new blocks that get automatically allocated will be cleared upon allocation. */
int i;
for (i = 0; i <= kscm->last_cell_seg; i++) {
memset(kscm->cell_seg[i], 0, sizeof(struct kscm_cell) * KSCM_CONFIG_CELL_SEGSIZE);
}
int objid;
do {
if (kscm__fread_int(kscm, f, &objid) != 4) {
fprintf(stderr, "WTFERR1\n");
exit(-1);
return -1;
}
if (objid == 0) break;
kscm_object_t obj = kscm_get_object_address(kscm, objid);
if (obj == NULL) {
fprintf(stderr, "WTFERR2\n");
exit(-1);
return -1;
}
char typ = 0;
if (kscm__fread_byte(kscm, f, &typ) != 1) {
fprintf(stderr, "WTFERR3\n");
exit(-1);
return -1;
}
fprintf(stderr, "Got type %d\n", typ);
const char* tmpstr;
switch (typ) {
case KSCM_PERSIST_TINT32:
obj->_flag = KSCM_T_NUMBER | KSCM_T_ATOM;
kscm__fread_int(kscm, f, &tmpint);
obj->_object._number._ivalue = tmpint;
break;
case KSCM_PERSIST_TSTRING:
obj->_flag = KSCM_T_STRING | KSCM_T_ATOM;
kscm__fread_int(kscm, f, &tmpint);
obj->_object._string._keynum = tmpint;
tmpint = kscm__fread_str(kscm, f, &tmpstr);
if (tmpint < 0) {
fprintf(stderr, "WTFERR4\n");
exit(-1);
return -1;
}
//fprintf(stderr, "Got str len %d '%s'\n", tmpint, tmpstr);
#ifdef __WIN32
obj->_object._string._svalue = _strdup(tmpstr);//kscm__store_string(kscm, tmpstr);
#else
obj->_object._string._svalue = strdup(tmpstr);//kscm__store_string(kscm, tmpstr);
#endif
free((void*)tmpstr);
break;
case KSCM_PERSIST_TSYMBOL:
obj->_flag = KSCM_T_SYMBOL;
kscm__fread_int(kscm, f, &tmpint);
obj->_object._cons._car = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
obj->_object._cons._cdr = kscm_get_object_address(kscm, tmpint);
break;
case KSCM_PERSIST_TPAIR:
obj->_flag = KSCM_T_PAIR;
kscm__fread_int(kscm, f, &tmpint);
obj->_object._cons._car = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
obj->_object._cons._cdr = kscm_get_object_address(kscm, tmpint);
break;
case KSCM_PERSIST_TPROC:
obj->_flag = KSCM_T_PROC | KSCM_T_ATOM;
kscm__fread_int(kscm, f, &tmpint);
obj->_object._number._ivalue = tmpint;
break;
case KSCM_PERSIST_TCLOSURE:
obj->_flag = KSCM_T_CLOSURE;
kscm__fread_int(kscm, f, &tmpint);
obj->_object._cons._car = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
obj->_object._cons._cdr = kscm_get_object_address(kscm, tmpint);
break;
case KSCM_PERSIST_TSYNTAX:
obj->_flag = KSCM_T_SYMBOL | KSCM_T_SYNTAX;
kscm__fread_int(kscm, f, &tmpint);
obj->_object._cons._car = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
obj->_object._cons._cdr = kscm_get_object_address(kscm, tmpint);
break;
case KSCM_PERSIST_TCONTINUATION:
obj->_flag = KSCM_T_CONTINUATION;
kscm__fread_int(kscm, f, &tmpint);
obj->_object._cons._car = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
obj->_object._cons._cdr = kscm_get_object_address(kscm, tmpint);
break;
#ifdef KSCM_CONFIG_USE_STRUCTS
case KSCM_PERSIST_TABSTRACTION:
obj->_flag = KSCM_T_ABSTRACTION;
kscm__fread_int(kscm, f, &tmpint);
obj->_object._cons._car = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
obj->_object._cons._cdr = kscm_get_object_address(kscm, tmpint);
break;
case KSCM_PERSIST_TBUFFER:
obj->_flag = KSCM_T_BUFFER | KSCM_T_ATOM;
tmpint = kscm__fread_str(kscm, f, &tmpstr);
obj->_object._buffer._length = tmpint;
if (tmpint < 0) {
fprintf(stderr, "WTFERR4\n");
exit(-1);
return -1;
}
//fprintf(stderr, "Got str len %d '%s'\n", tmpint, tmpstr);
obj->_object._buffer._data = (unsigned char*) tmpstr; //kscm__store_string(kscm, tmpstr);
//free((void*)tmpstr);
break;
#endif
#ifdef KSCM_CONFIG_USE_FLOATS
case KSCM_PERSIST_TFLOAT64: {
obj->_flag = KSCM_T_FLOAT64 | KSCM_T_ATOM;
double tmp;
char* bytes = (char*)(void*)&tmp; //obj->_object._float64._dvalue;
kscm__fread_byte(kscm, f, &bytes[0]);
kscm__fread_byte(kscm, f, &bytes[1]);
kscm__fread_byte(kscm, f, &bytes[2]);
kscm__fread_byte(kscm, f, &bytes[3]);
kscm__fread_byte(kscm, f, &bytes[4]);
kscm__fread_byte(kscm, f, &bytes[5]);
kscm__fread_byte(kscm, f, &bytes[6]);
kscm__fread_byte(kscm, f, &bytes[7]);
obj->_object._float64._dvalue = tmp;
} break;
#endif
#ifdef KSCM_CONFIG_USE_STRUCTS
case KSCM_PERSIST_TOBJX:
obj->_flag = KSCM_T_OBJX;
kscm__fread_int(kscm, f, &tmpint);
obj->_object._objx._type = kscm_get_object_address(kscm, tmpint);
kscm__fread_int(kscm, f, &tmpint);
obj->_object._objx._count = tmpint;
obj->_object._objx._elements = (kscm_object_t*) calloc(sizeof(kscm_object_t), obj->_object._objx._count);
// TODO Check non-null (ideally check size is sane before attempting to allocate/fill)
for (i = 0; i < obj->_object._objx._count; i++) {
kscm__fread_int(kscm, f, &tmpint);
obj->_object._objx._elements[i] = kscm_get_object_address(kscm, tmpint);
}
break;
#endif
default:
fprintf(stderr, "Unknown object type #%d\n", typ);
exit(1);
if (1) return 0;
}
} while (objid != 0);
kscm->free_cell = kscm->NIL;
kscm->fcells = 0;
return 0; // Resumed
}
/* From ifdef KSCM_CONFIG_USE_PERSIST */
#endif
kscm_object_t kscm__opexe_7(kscm_t* kscm, register short op)
{
register kscm_object_t x, y, z;
char* str1;
char* str2;
char* str3;
register long v;
static long w;
switch (op) {
case KSCM_OP_STRCAT:
x = kscm__car(kscm, kscm->args);
y = kscm__cadr(kscm, kscm->args);
if (!kscm__isstring(kscm, x) || !kscm__isstring(kscm, y)) {
kscm__s_retbool(kscm, 0);
}
str1 = kscm__strvalue(kscm, x);
str2 = kscm__strvalue(kscm, y);
str3 = (char*)calloc(strlen(str1) + strlen(str2) + 1, 1);
if (str3 == NULL) {
kscm__s_retbool(kscm, 0);
}
strcat(str3, str1);
strcat(str3, str2);
z = kscm__mk_string(kscm, str3);
free(str3);
kscm__s_return(kscm, z);
case KSCM_OP_STRLEN:
x = kscm__car(kscm, kscm->args);
if (!kscm__isstring(kscm, x)) {
kscm__s_retbool(kscm, 0);
}
str1 = kscm__strvalue(kscm, x);
kscm__s_return(kscm, kscm__mk_number(kscm, strlen(str1)));
case KSCM_OP_STRGET:
x = kscm__car(kscm, kscm->args);
y = kscm__cadr(kscm, kscm->args);
if (!kscm__isstring(kscm, x) || !kscm__isnumber(kscm, y)) {
kscm__s_retbool(kscm, 0);
}
str1 = kscm__strvalue(kscm, x);
v = kscm__ivalue(kscm, y);
if (v < 0 || v >= strlen(str1)) {
kscm__s_retbool(kscm, 0);
}
kscm__s_return(kscm, kscm__mk_number(kscm, ((int)(str1[v])) & 0xFF));
#ifdef KSCM_CONFIG_USE_PERSIST
case KSCM_OP_SAVE_STATE:
x = kscm__car(kscm, kscm->args);
y = kscm__cadr(kscm, kscm->args);
str1 = kscm__strvalue(kscm, x);
str2 = kscm__strvalue(kscm, y);
if (kscm_save_state(kscm, str1, str2) == 0) {
kscm__s_return(kscm, kscm__mk_symbol(kscm, "saved"));
} else {
kscm__s_retbool(kscm, 0);
}
case KSCM_OP_RESUME_STATE:
x = kscm__car(kscm, kscm->args);
y = kscm__cadr(kscm, kscm->args);
str1 = kscm__strvalue(kscm, x);
str2 = kscm__strvalue(kscm, y);
if (kscm_resume_state(kscm, str1, str2) == 0) {
kscm__s_return(kscm, kscm__mk_symbol(kscm, "resumed"));
} else {
kscm__s_retbool(kscm, 0);
}
#endif
#ifdef KSCM_CONFIG_USE_STRUCTS
case KSCM_OP_BUFFER:
kscm__s_retbool(kscm, kscm__isbuffer(kscm, kscm__car(kscm, kscm->args)));
case KSCM_OP_BUFFER_NEW:
x = kscm__car(kscm, kscm->args);
if (kscm__isstring(kscm, x)) {
const char* strval = kscm__strvalue(kscm, x);
size_t slen = strlen(strval);
y = kscm__mk_buffer(kscm, slen);
size_t iter;
for (iter = 0; iter < slen; iter++) {
y->_object._buffer._data[iter] = strval[iter];
}
kscm__s_return(kscm, y);
} else if (!kscm__isnumber(kscm, x)) {
kscm__s_return(kscm, kscm->NIL);
}
kscm__s_return(kscm, kscm__mk_buffer(kscm, kscm__ivalue(kscm, x)));
case KSCM_OP_BUFFER_LEN:
x = kscm__car(kscm, kscm->args);
if (!kscm__isbuffer(kscm, x)) {
kscm__s_return(kscm, kscm->F);
}
kscm__s_return(kscm, kscm__mk_number(kscm, x->_object._buffer._length));
case KSCM_OP_BUFFER_GET:
x = kscm__car(kscm, kscm->args);
y = kscm__cadr(kscm, kscm->args);
if (!kscm__isbuffer(kscm, x) || !kscm__isnumber(kscm, y)) {
kscm__s_return(kscm, kscm->F);
}
v = kscm__ivalue(kscm, y);
if (v < 0 || v >= x->_object._buffer._length) {
kscm__s_return(kscm, kscm->F);
}
kscm__s_return(kscm, kscm__mk_number(kscm, ((long)(x->_object._buffer._data[v])) & 0xFF));
case KSCM_OP_BUFFER_SET:
x = kscm__car(kscm, kscm->args);
y = kscm__cadr(kscm, kscm->args);
z = kscm__caddr(kscm, kscm->args);
if (!kscm__isbuffer(kscm, x) || !kscm__isnumber(kscm, y) || !kscm__isnumber(kscm, z)) {
kscm__s_return(kscm, kscm->F);
}
v = kscm__ivalue(kscm, y);
if (v < 0 || v >= x->_object._buffer._length) {
kscm__s_return(kscm, kscm->F);
}
x->_object._buffer._data[v] = (unsigned char)kscm__ivalue(kscm, z);
kscm__s_return(kscm, kscm->T);
case KSCM_OP_BUFFER_LOAD:
kscm__s_return(kscm, kscm__mk_string(kscm, "TODO"));
case KSCM_OP_BUFFER_SAVE:
kscm__s_return(kscm, kscm__mk_string(kscm, "TODO"));
case KSCM_OP_ABSTRACTION:
kscm__s_retbool(kscm, kscm__isabstraction(kscm, kscm__car(kscm, kscm->args)));
case KSCM_OP_ABSTRACTION_NEW:
x = kscm__car(kscm, kscm->args);
y = kscm__cadr(kscm, kscm->args);
kscm__s_return(kscm, kscm__mk_abstraction(kscm, x, y));
case KSCM_OP_ABSTRACTION_TYPE:
x = kscm__car(kscm, kscm->args);
#ifdef KSCM_CONFIG_USE_OBJECTS
if (kscm__isobjx(kscm, x)) {
kscm__s_return(kscm, x->_object._objx._type);
}
#endif
if (!kscm__isabstraction(kscm, x)) {
kscm__s_retbool(kscm, 0);
}
kscm__s_return(kscm, kscm__car(kscm, x));
case KSCM_OP_ABSTRACTION_VALUE:
x = kscm__car(kscm, kscm->args);
if (!kscm__isabstraction(kscm, x)) {
kscm__s_retbool(kscm, 0);
}
kscm__s_return(kscm, kscm__cdr(kscm, x));
#endif
#ifdef KSCM_CONFIG_USE_OBJECTS
case KSCM_OP_OBJECT:
kscm__s_retbool(kscm, kscm__isobjx(kscm, kscm__car(kscm, kscm->args)));
case KSCM_OP_OBJECT_NEW:
x = kscm__car(kscm, kscm->args);
y = kscm__cadr(kscm, kscm->args);
if (!kscm__isnumber(kscm, y)) {
kscm__s_return(kscm, kscm->F);
}
kscm__s_return(kscm, kscm__mk_objx(kscm, x, kscm__ivalue(kscm, y)));
case KSCM_OP_OBJECT_LEN:
x = kscm__car(kscm, kscm->args);
if (!kscm__isobjx(kscm, x)) {
kscm__s_return(kscm, kscm->F);
}
kscm__s_return(kscm, kscm__mk_number(kscm, x->_object._objx._count));
case KSCM_OP_OBJECT_GET:
x = kscm__car(kscm, kscm->args);
y = kscm__cadr(kscm, kscm->args);
if (!kscm__isobjx(kscm, x) || !kscm__isnumber(kscm, y)) {
kscm__s_return(kscm, kscm->F);
}
v = kscm__ivalue(kscm, y);
if (v < 0 || v >= x->_object._objx._count) {
kscm__s_return(kscm, kscm->F);
}
kscm__s_return(kscm, x->_object._objx._elements[v]);
case KSCM_OP_OBJECT_SET:
x = kscm__car(kscm, kscm->args);
y = kscm__cadr(kscm, kscm->args);
z = kscm__caddr(kscm, kscm->args);
if (!kscm__isobjx(kscm, x) || !kscm__isnumber(kscm, y)) {
kscm__s_return(kscm, kscm->F);
}
v = kscm__ivalue(kscm, y);
if (v < 0 || v >= x->_object._objx._count) {
kscm__s_return(kscm, kscm->F);
}
x->_object._objx._elements[v] = z;
kscm__s_return(kscm, kscm->T);
case KSCM_OP_OBJECT_RETYPE:
x = kscm__car(kscm, kscm->args);
y = kscm__cadr(kscm, kscm->args);
if (!kscm__isobjx(kscm, x)) {
kscm__s_return(kscm, kscm->F);
}
x->_object._objx._type = y;
kscm__s_return(kscm, kscm->T);
#endif
case KSCM_OP_SYMBOL_TO_STRING:
#ifdef KSCM_CONFIG_USE_STRUCTS
/* We handle buffer->string in the same function if structs are enabled. */
if (kscm__isbuffer(kscm, kscm__car(kscm, kscm->args))) {
x = kscm__car(kscm, kscm->args);
char* tmp_buffer = (char*) calloc(x->_object._buffer._length, 1);
if (tmp_buffer == NULL) {
kscm__s_return(kscm, kscm->NIL);
}
size_t iter;
for (iter = 0; iter < x->_object._buffer._length; iter++) {
tmp_buffer[iter] = x->_object._buffer._data[iter];
}
/* Note: All the messaround above was only to keep the string-creation API consistent.
* It would be easy to optimise the buffer->string case by creating the string object manually.
*/
y = kscm__mk_string(kscm, tmp_buffer);
free(tmp_buffer);
kscm__s_return(kscm, y);
}
#endif
if (kscm__issymbol(kscm, kscm__car(kscm, kscm->args))) {
x = kscm__caar(kscm, kscm->args);
kscm__s_return(kscm, x);
}
else {
kscm__s_return(kscm, kscm->F);
}
default:
sprintf(kscm->strbuff, "%d is illegal operator", kscm->_operator);
kscm__error_0(kscm, kscm->strbuff);
}
return kscm->T; /* NOTREACHED */
}
kscm_object_t kscm__opexe_8(kscm_t* kscm, register short op)
{
register kscm_object_t x, y, z;
char* str1;
char* str2;
char* str3;
register long v;
static long w;
#ifdef KSCM_CONFIG_USE_CONSOLE
struct winsize ws;
int fd;
#endif
switch (op) {
#ifdef KSCM_CONFIG_USE_CONSOLE
case KSCM_OP_CONSOLE_MODE:
x = kscm__mk_string(kscm, ttyname(STDIN_FILENO));
kscm__s_return(kscm, x);
case KSCM_OP_CONSOLE_WIDTH:
case KSCM_OP_CONSOLE_HEIGHT:
str1 = ttyname(STDIN_FILENO); // NOTE: "/dev/tty" may work if this isn't available!
fd = open(str1, O_RDWR);
if (fd < 0) {
kscm__error_0(kscm, "Failed to open console device");
}
/* Get window size of terminal. */
if (ioctl(fd, TIOCGWINSZ, &ws) < 0) {
kscm__error_0(kscm, "Failed to get console info");
}
close(fd);
if (op == KSCM_OP_CONSOLE_WIDTH) {
kscm__s_return(kscm, kscm__mk_number(kscm, ws.ws_row));
} else {
kscm__s_return(kscm, kscm__mk_number(kscm, ws.ws_row));
}
#else
case KSCM_OP_CONSOLE_MODE:
kscm__s_return(kscm, kscm->F);
#endif
/*
kscm__eval_set(kscm, &kscm__opexe_8, KSCM_OP_CONSOLE_MODE);
kscm__eval_set(kscm, &kscm__opexe_8, KSCM_OP_CONSOLE_NEXT);
kscm__eval_set(kscm, &kscm__opexe_8, KSCM_OP_CONSOLE_POLL);
kscm__eval_set(kscm, &kscm__opexe_8, KSCM_OP_CONSOLE_WIDTH);
kscm__eval_set(kscm, &kscm__opexe_8, KSCM_OP_CONSOLE_HEIGHT);
*/
default:
sprintf(kscm->strbuff, "%d is illegal operator", kscm->_operator);
kscm__error_0(kscm, kscm->strbuff);
}
return kscm->T; /* NOTREACHED */
}
typedef kscm_object_t(*kscm_dispatchf_t)(kscm_t* kscm, register short op);
kscm_dispatchf_t kscm__shared_dispatch_table[256];
void kscm__eval_set(kscm_t* kscm, kscm_dispatchf_t func, int tag) {
kscm__shared_dispatch_table[tag] = func;
}
void kscm__eval_setup(kscm_t* kscm) {
if (kscm__shared_dispatch_table[KSCM_OP_LOAD] == &kscm__opexe_0) {
return;
}
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_LOAD);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_T0LVL);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_T1LVL);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_READ);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_VALUEPRINT);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_EVAL);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_E0ARGS);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_E1ARGS);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_APPLY);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_DOMACRO);
//
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_LAMBDA);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_QUOTE);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_DEF0);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_DEF1);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_BEGIN);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_IF0);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_IF1);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_SET0);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_SET1);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_LET0);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_LET1);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_LET2);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_LET0AST);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_LET1AST);
kscm__eval_set(kscm, &kscm__opexe_0, KSCM_OP_LET2AST);
//
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_LET0REC);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_LET1REC);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_LET2REC);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_COND0);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_COND1);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_DELAY);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_AND0);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_AND1);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_OR0);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_OR1);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_C0STREAM);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_C1STREAM);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_0MACRO);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_1MACRO);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_CASE0);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_CASE1);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_CASE2);
//
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_PEVAL);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_PAPPLY);
kscm__eval_set(kscm, &kscm__opexe_1, KSCM_OP_CONTINUATION);
//
kscm__eval_set(kscm, &kscm__opexe_2, KSCM_OP_ADD);
kscm__eval_set(kscm, &kscm__opexe_2, KSCM_OP_SUB);
kscm__eval_set(kscm, &kscm__opexe_2, KSCM_OP_MUL);
kscm__eval_set(kscm, &kscm__opexe_2, KSCM_OP_DIV);
kscm__eval_set(kscm, &kscm__opexe_2, KSCM_OP_REM);
kscm__eval_set(kscm, &kscm__opexe_2, KSCM_OP_CAR);
kscm__eval_set(kscm, &kscm__opexe_2, KSCM_OP_CDR);
kscm__eval_set(kscm, &kscm__opexe_2, KSCM_OP_CONS);
kscm__eval_set(kscm, &kscm__opexe_2, KSCM_OP_SETCAR);
kscm__eval_set(kscm, &kscm__opexe_2, KSCM_OP_SETCDR);
//
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_NOT);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_BOOL);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_NULL);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_ZEROP);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_POSP);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_NEGP);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_NEQ);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_LESS);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_GRE);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_LEQ);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_GEQ);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_SYMBOL);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_NUMBER);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_STRING);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_PROC);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_PAIR);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_EQ);
kscm__eval_set(kscm, &kscm__opexe_3, KSCM_OP_EQV);
//
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_FORCE);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_WRITE);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_DISPLAY);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_NEWLINE);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_ERR0);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_ERR1);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_REVERSE);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_APPEND);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_PUT);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_GET);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_QUIT);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_GC);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_GCVERB);
kscm__eval_set(kscm, &kscm__opexe_4, KSCM_OP_NEWSEGMENT);
//
kscm__eval_set(kscm, &kscm__opexe_5, KSCM_OP_RDSEXPR);
kscm__eval_set(kscm, &kscm__opexe_5, KSCM_OP_RDLIST);
kscm__eval_set(kscm, &kscm__opexe_5, KSCM_OP_RDDOT);
kscm__eval_set(kscm, &kscm__opexe_5, KSCM_OP_RDQUOTE);
kscm__eval_set(kscm, &kscm__opexe_5, KSCM_OP_RDQQUOTE);
kscm__eval_set(kscm, &kscm__opexe_5, KSCM_OP_RDUNQUOTE);
kscm__eval_set(kscm, &kscm__opexe_5, KSCM_OP_RDUQTSP);
kscm__eval_set(kscm, &kscm__opexe_5, KSCM_OP_P0LIST);
kscm__eval_set(kscm, &kscm__opexe_5, KSCM_OP_P1LIST);
//
kscm__eval_set(kscm, &kscm__opexe_6, KSCM_OP_LIST_LENGTH);
kscm__eval_set(kscm, &kscm__opexe_6, KSCM_OP_ASSQ);
kscm__eval_set(kscm, &kscm__opexe_6, KSCM_OP_PRINT_WIDTH);
kscm__eval_set(kscm, &kscm__opexe_6, KSCM_OP_P0_WIDTH);
kscm__eval_set(kscm, &kscm__opexe_6, KSCM_OP_P1_WIDTH);
kscm__eval_set(kscm, &kscm__opexe_6, KSCM_OP_GET_CLOSURE);
kscm__eval_set(kscm, &kscm__opexe_6, KSCM_OP_CLOSUREP);
//#ifdef KSCM_CONFIG_USE_MACRO
kscm__eval_set(kscm, &kscm__opexe_6, KSCM_OP_MACROP);
//#endif Removed ifdef to keep ordering consistent. -Zak.
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_STRCAT);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_STRLEN);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_STRGET);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_SAVE_STATE);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_RESUME_STATE);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_BUFFER);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_BUFFER_NEW);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_BUFFER_LEN);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_BUFFER_GET);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_BUFFER_SET);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_ABSTRACTION);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_ABSTRACTION_NEW);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_ABSTRACTION_TYPE);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_ABSTRACTION_VALUE);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_OBJECT);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_OBJECT_NEW);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_OBJECT_LEN);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_OBJECT_GET);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_OBJECT_SET);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_OBJECT_RETYPE);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_SYMBOL_TO_STRING);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_BUFFER_LOAD);
kscm__eval_set(kscm, &kscm__opexe_7, KSCM_OP_BUFFER_SAVE);
kscm__eval_set(kscm, &kscm__opexe_8, KSCM_OP_CONSOLE_MODE);
kscm__eval_set(kscm, &kscm__opexe_8, KSCM_OP_CONSOLE_NEXT);
kscm__eval_set(kscm, &kscm__opexe_8, KSCM_OP_CONSOLE_POLL);
kscm__eval_set(kscm, &kscm__opexe_8, KSCM_OP_CONSOLE_WIDTH);
kscm__eval_set(kscm, &kscm__opexe_8, KSCM_OP_CONSOLE_HEIGHT);
}
/* These and the commented-out parts of kscm__eval_cycle can be re-enabled if you need to make sure the interpreter is running.
int fixme_reccheck = 0;
int fixme_ops = 0;
*/
/* kernel of this intepreter */
kscm_object_t kscm__eval_cycle(kscm_t* kscm, register short op)
{
kscm__eval_setup(kscm);
/*fixme_reccheck++;
if (fixme_reccheck > 1) {
fprintf(stderr, "Warning reccheck=%d\n", fixme_reccheck);
}*/
kscm->_operator = op;
for (;;) {
kscm_object_t(*func)(kscm_t* kscm, register short op) = kscm__shared_dispatch_table[kscm->_operator];
if (func == NULL) {
fprintf(stderr, "Error! Opcode %d leads to NULL!\n", kscm->_operator);
exit(-1);
}
if (/*(*kscm__shared_dispatch_table[kscm->_operator])*/ func(kscm, kscm->_operator) == kscm->NIL) {
//fixme_reccheck--;
return kscm->NIL;
}
/*if ((fixme_ops % 1000) == 0) {
fprintf(stderr, "Just did op %d\n", fixme_ops);
}
fixme_ops++;*/
}
}
/* ========== Initialization of internal keywords ========== */
void kscm__mk_syntax(kscm_t* kscm, unsigned short op, const char *name)
{
kscm_object_t x;
x = kscm__cons(kscm, kscm__mk_string(kscm, name), kscm->NIL);
kscm__type(kscm, x) = (KSCM_T_SYNTAX | KSCM_T_SYMBOL);
kscm__syntaxnum(kscm, x) = op;
kscm->oblist = kscm__cons(kscm, x, kscm->oblist);
}
void kscm__mk_proc(kscm_t* kscm, unsigned short op, const char *name)
{
kscm_object_t x, y;
x = kscm__mk_symbol(kscm, name);
y = kscm__get_cell(kscm, kscm->NIL, kscm->NIL);
kscm__type(kscm, y) = (KSCM_T_PROC | KSCM_T_ATOM);
kscm__ivalue(kscm, y) = (long)op;
kscm__car(kscm, kscm->global_env) = kscm__cons(kscm, kscm__cons(kscm, x, y), kscm__car(kscm, kscm->global_env));
}
void kscm__init_vars_global(kscm_t* kscm)
{
kscm_object_t x;
/* init input/output file */
kscm->inputs[kscm->inputtop] = stdin;
kscm->outfp = stdout;
/* init kscm->NIL */
kscm__type(kscm, kscm->NIL) = (KSCM_T_ATOM | KSCM_MARK);
kscm__car(kscm, kscm->NIL) = kscm__cdr(kscm, kscm->NIL) = kscm->NIL;
/* init T */
kscm__type(kscm, kscm->T) = (KSCM_T_ATOM | KSCM_MARK);
kscm__car(kscm, kscm->T) = kscm__cdr(kscm, kscm->T) = kscm->T;
/* init F */
kscm__type(kscm, kscm->F) = (KSCM_T_ATOM | KSCM_MARK);
kscm__car(kscm, kscm->F) = kscm__cdr(kscm, kscm->F) = kscm->F;
/* init global_env */
kscm->global_env = kscm__cons(kscm, kscm->NIL, kscm->NIL);
/* init else */
x = kscm__mk_symbol(kscm, "else");
kscm__car(kscm, kscm->global_env) = kscm__cons(kscm, kscm__cons(kscm, x, kscm->T), kscm__car(kscm, kscm->global_env));
}
void kscm__init_syntax(kscm_t* kscm)
{
/* init syntax */
kscm__mk_syntax(kscm, KSCM_OP_LAMBDA, "lambda");
kscm__mk_syntax(kscm, KSCM_OP_QUOTE, "quote");
kscm__mk_syntax(kscm, KSCM_OP_DEF0, "define");
kscm__mk_syntax(kscm, KSCM_OP_IF0, "if");
kscm__mk_syntax(kscm, KSCM_OP_BEGIN, "begin");
kscm__mk_syntax(kscm, KSCM_OP_SET0, "set!");
kscm__mk_syntax(kscm, KSCM_OP_LET0, "let");
kscm__mk_syntax(kscm, KSCM_OP_LET0AST, "let*");
kscm__mk_syntax(kscm, KSCM_OP_LET0REC, "letrec");
kscm__mk_syntax(kscm, KSCM_OP_COND0, "cond");
kscm__mk_syntax(kscm, KSCM_OP_DELAY, "delay");
kscm__mk_syntax(kscm, KSCM_OP_AND0, "and");
kscm__mk_syntax(kscm, KSCM_OP_OR0, "or");
kscm__mk_syntax(kscm, KSCM_OP_C0STREAM, "cons-stream");
#ifdef KSCM_CONFIG_USE_MACRO
kscm__mk_syntax(kscm, KSCM_OP_0MACRO, "macro");
#endif
kscm__mk_syntax(kscm, KSCM_OP_CASE0, "case");
}
void kscm__init_procs(kscm_t* kscm)
{
/* init procedure */
kscm__mk_proc(kscm, KSCM_OP_PEVAL, "eval");
kscm__mk_proc(kscm, KSCM_OP_PAPPLY, "apply");
kscm__mk_proc(kscm, KSCM_OP_CONTINUATION, "call-with-current-continuation");
kscm__mk_proc(kscm, KSCM_OP_FORCE, "force");
kscm__mk_proc(kscm, KSCM_OP_CAR, "car");
kscm__mk_proc(kscm, KSCM_OP_CDR, "cdr");
kscm__mk_proc(kscm, KSCM_OP_CONS, "cons");
kscm__mk_proc(kscm, KSCM_OP_SETCAR, "set-car!");
kscm__mk_proc(kscm, KSCM_OP_SETCDR, "set-cdr!");
kscm__mk_proc(kscm, KSCM_OP_ADD, "+");
kscm__mk_proc(kscm, KSCM_OP_SUB, "-");
kscm__mk_proc(kscm, KSCM_OP_MUL, "*");
kscm__mk_proc(kscm, KSCM_OP_DIV, "/");
kscm__mk_proc(kscm, KSCM_OP_REM, "remainder");
kscm__mk_proc(kscm, KSCM_OP_NOT, "not");
kscm__mk_proc(kscm, KSCM_OP_BOOL, "boolean?");
kscm__mk_proc(kscm, KSCM_OP_SYMBOL, "symbol?");
kscm__mk_proc(kscm, KSCM_OP_NUMBER, "number?");
kscm__mk_proc(kscm, KSCM_OP_STRING, "string?");
kscm__mk_proc(kscm, KSCM_OP_PROC, "procedure?");
kscm__mk_proc(kscm, KSCM_OP_PAIR, "pair?");
kscm__mk_proc(kscm, KSCM_OP_EQV, "eqv?");
kscm__mk_proc(kscm, KSCM_OP_EQ, "eq?");
kscm__mk_proc(kscm, KSCM_OP_NULL, "null?");
kscm__mk_proc(kscm, KSCM_OP_ZEROP, "zero?");
kscm__mk_proc(kscm, KSCM_OP_POSP, "positive?");
kscm__mk_proc(kscm, KSCM_OP_NEGP, "negative?");
kscm__mk_proc(kscm, KSCM_OP_NEQ, "=");
kscm__mk_proc(kscm, KSCM_OP_LESS, "<");
kscm__mk_proc(kscm, KSCM_OP_GRE, ">");
kscm__mk_proc(kscm, KSCM_OP_LEQ, "<=");
kscm__mk_proc(kscm, KSCM_OP_GEQ, ">=");
kscm__mk_proc(kscm, KSCM_OP_READ, "read");
kscm__mk_proc(kscm, KSCM_OP_WRITE, "write");
kscm__mk_proc(kscm, KSCM_OP_DISPLAY, "display");
kscm__mk_proc(kscm, KSCM_OP_NEWLINE, "newline");
kscm__mk_proc(kscm, KSCM_OP_LOAD, "load");
kscm__mk_proc(kscm, KSCM_OP_ERR0, "error");
kscm__mk_proc(kscm, KSCM_OP_REVERSE, "reverse");
kscm__mk_proc(kscm, KSCM_OP_APPEND, "append");
kscm__mk_proc(kscm, KSCM_OP_PUT, "put");
kscm__mk_proc(kscm, KSCM_OP_GET, "get");
kscm__mk_proc(kscm, KSCM_OP_GC, "gc");
kscm__mk_proc(kscm, KSCM_OP_GCVERB, "gc-verbose");
kscm__mk_proc(kscm, KSCM_OP_NEWSEGMENT, "new-segment");
kscm__mk_proc(kscm, KSCM_OP_LIST_LENGTH, "list-length"); /* a.k */
kscm__mk_proc(kscm, KSCM_OP_ASSQ, "assq"); /* a.k */
kscm__mk_proc(kscm, KSCM_OP_PRINT_WIDTH, "print-width"); /* a.k */
kscm__mk_proc(kscm, KSCM_OP_GET_CLOSURE, "get-closure-code"); /* a.k */
kscm__mk_proc(kscm, KSCM_OP_CLOSUREP, "closure?"); /* a.k */
#ifdef KSCM_CONFIG_USE_MACRO
kscm__mk_proc(kscm, KSCM_OP_MACROP, "macro?"); /* a.k */
#endif
kscm__mk_proc(kscm, KSCM_OP_STRCAT, "string-cat");
kscm__mk_proc(kscm, KSCM_OP_STRLEN, "string-length");
kscm__mk_proc(kscm, KSCM_OP_STRGET, "string-get");
#ifdef KSCM_CONFIG_USE_PERSIST
kscm__mk_proc(kscm, KSCM_OP_SAVE_STATE, "save-state");
kscm__mk_proc(kscm, KSCM_OP_RESUME_STATE, "resume-state");
#endif
#ifdef KSCM_CONFIG_USE_STRUCTS
kscm__mk_proc(kscm, KSCM_OP_BUFFER, "buffer?");
kscm__mk_proc(kscm, KSCM_OP_BUFFER_NEW, "buffer-new");
kscm__mk_proc(kscm, KSCM_OP_BUFFER_LEN, "buffer-length");
kscm__mk_proc(kscm, KSCM_OP_BUFFER_GET, "buffer-get");
kscm__mk_proc(kscm, KSCM_OP_BUFFER_SET, "buffer-set!");
kscm__mk_proc(kscm, KSCM_OP_ABSTRACTION, "abstraction?");
kscm__mk_proc(kscm, KSCM_OP_ABSTRACTION_NEW, "abstraction-new");
kscm__mk_proc(kscm, KSCM_OP_ABSTRACTION_TYPE, "abstraction-type");
kscm__mk_proc(kscm, KSCM_OP_ABSTRACTION_VALUE, "abstraction-value");
kscm__mk_proc(kscm, KSCM_OP_BUFFER_LOAD, "buffer-load");
kscm__mk_proc(kscm, KSCM_OP_BUFFER_SAVE, "buffer-save");
kscm__mk_proc(kscm, KSCM_OP_CONSOLE_MODE, "console-mode");
kscm__mk_proc(kscm, KSCM_OP_CONSOLE_NEXT, "console-next");
kscm__mk_proc(kscm, KSCM_OP_CONSOLE_POLL, "console-poll");
kscm__mk_proc(kscm, KSCM_OP_CONSOLE_WIDTH, "console-width");
kscm__mk_proc(kscm, KSCM_OP_CONSOLE_HEIGHT, "console-height");
#endif
#ifdef KSCM_CONFIG_USE_OBJECTS
kscm__mk_proc(kscm, KSCM_OP_OBJECT, "object?");
kscm__mk_proc(kscm, KSCM_OP_OBJECT_NEW, "object-new");
kscm__mk_proc(kscm, KSCM_OP_OBJECT_LEN, "object-length");
kscm__mk_proc(kscm, KSCM_OP_OBJECT_GET, "object-get");
kscm__mk_proc(kscm, KSCM_OP_OBJECT_SET, "object-set!");
kscm__mk_proc(kscm, KSCM_OP_OBJECT_RETYPE, "object-retype!");
/* NOTE: There is no object-type function, the abstraction-type function handles all custom-typed values. */
#endif
kscm__mk_proc(kscm, KSCM_OP_SYMBOL_TO_STRING, "symbol->string");
kscm__mk_proc(kscm, KSCM_OP_QUIT, "quit");
}
/* initialize several globals */
void kscm__init_globals(kscm_t* kscm)
{
kscm__init_vars_global(kscm);
kscm__init_syntax(kscm);
kscm__init_procs(kscm);
/* intialization of global pointers to special symbols */
kscm->LAMBDA = kscm__mk_symbol(kscm, "lambda");
kscm->QUOTE = kscm__mk_symbol(kscm, "quote");
#ifdef KSCM_CONFIG_USE_QQUOTE
kscm->QQUOTE = kscm__mk_symbol(kscm, "quasiquote");
kscm->UNQUOTE = kscm__mk_symbol(kscm, "unquote");
kscm->UNQUOTESP = kscm__mk_symbol(kscm, "unquote-splicing");
#endif
}
/* ========== Error ========== */
void kscm__fatal_error(kscm_t* kscm, const char *fmt, const char *a, const char *b, const char *c)
{
fprintf(stderr, "Fatal error: ");
fprintf(stderr, fmt, a, b, c);
fprintf(stderr, "\n");
exit(1);
}
#ifdef KSCM_CONFIG_USE_SETJMP
void kscm__error(kscm_t* kscm, const char *fmt, const char *a, const char *b, const char *c)
{
fprintf(stderr, "Error: ");
fprintf(stderr, fmt, a, b, c);
fprintf(stderr, "\n");
kscm__resetinput(kscm);
longjmp(kscm->error_jmp, KSCM_OP_T0LVL);
}
#endif
/* ========== Main ========== */
#ifdef CMDLINE
int main(int argc, char **argv)
#else
int main()
#endif
{
short i;
short op = (short)KSCM_OP_LOAD;
#ifdef CMDLINE
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-e") == 0) {
all_errors_fatal = 1;
}
else if (strcmp(argv[i], "-q") == 0) {
quiet = 1;
}
}
#endif
kscm_t* kscm = (kscm_t*) calloc(1, sizeof(kscm_t));
kscm->cell_seg = calloc(KSCM_CONFIG_CELL_NSEGMENT, sizeof(kscm_object_t));
kscm->gcstate = calloc(4000, sizeof(kscm_gcstate_t));
kscm->gcstate_max = 4000;
if (!kscm->quiet)
printf(KSCM_CONFIG_BANNER);
kscm__init_scheme(kscm);
kscm->args = kscm__cons(kscm, kscm__mk_string(kscm, KSCM_CONFIG_INITFILE), kscm->NIL);
#ifdef KSCM_CONFIG_USE_SETJMP
op = setjmp(kscm->error_jmp);
#endif
kscm__eval_cycle(kscm, op);
exit(0);
}
#ifdef KSCM_PLUSPLUS
}
#endif