5603 lines
107 KiB
C
5603 lines
107 KiB
C
/*
|
|
* LISP9 Interpreter
|
|
* Nils M Holm, 2018,2019
|
|
* In the public domain
|
|
*
|
|
* If your country does not have a concept like the public
|
|
* domain, the Creative Common Zero (CC0) licence applies,
|
|
* see https://creativecommons.org/publicdomain/zero/1.0/
|
|
*/
|
|
|
|
#define VERSION "20190812"
|
|
|
|
#ifdef unix
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <signal.h>
|
|
#include <setjmp.h>
|
|
#define bye(x) exit((x)? EXIT_FAILURE: EXIT_SUCCESS)
|
|
#endif
|
|
|
|
#ifdef plan9
|
|
#include <u.h>
|
|
#include <libc.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <ape/limits.h>
|
|
#include <ape/signal.h>
|
|
#define bye(x) exits((x)? "error": NULL)
|
|
#define ptrdiff_t vlong
|
|
#endif
|
|
|
|
#ifdef native
|
|
#include "kern/u.h"
|
|
#include "kern/kern.h"
|
|
#define bye(x) reboot()
|
|
#define NULL nil
|
|
#define FILE int //There are no files but we need pointers for data streams
|
|
#endif
|
|
|
|
/*
|
|
* Tunable parameters
|
|
*/
|
|
|
|
#define IMAGEFILE "ls9.image"
|
|
#define IMAGESRC "ls9.ls9"
|
|
|
|
#define NNODES 262144
|
|
#define NVCELLS 262144
|
|
#define NPORTS 20
|
|
#define TOKLEN 80
|
|
#define CHUNKSIZE 1024
|
|
#define MXMAX 2000
|
|
#define NTRACE 10
|
|
#define PRDEPTH 1024
|
|
|
|
/*
|
|
* Basic data types
|
|
*/
|
|
|
|
#define cell int
|
|
#define byte unsigned char
|
|
#define uint unsigned int
|
|
|
|
/*
|
|
* Special Objects
|
|
*/
|
|
|
|
#define specialp(x) ((x) < 0)
|
|
#define NIL (-1)
|
|
#define TRUE (-2)
|
|
#define EOFMARK (-3)
|
|
#define UNDEF (-4)
|
|
#define RPAREN (-5)
|
|
#define DOT (-6)
|
|
|
|
/*
|
|
* Memory pools
|
|
*/
|
|
|
|
cell *Car = NULL,
|
|
*Cdr = NULL;
|
|
byte *Tag = NULL;
|
|
|
|
cell *Vectors = NULL;
|
|
|
|
cell Freelist = NIL;
|
|
cell Freevec = 0;
|
|
|
|
#define ATOM_TAG 0x01 /* Atom, CAR = type, CDR = next */
|
|
#define MARK_TAG 0x02 /* Mark */
|
|
#define TRAV_TAG 0x04 /* Traversal */
|
|
#define VECTOR_TAG 0x08 /* Vector, CAR = type, CDR = content */
|
|
#define PORT_TAG 0x10 /* Atom is an I/O port (with ATOM_TAG) */
|
|
#define USED_TAG 0x20 /* Port: used flag */
|
|
#define LOCK_TAG 0x40 /* Port: locked (do not close) */
|
|
#define CONST_TAG 0x80 /* Node is immutable */
|
|
|
|
#define tag(n) (Tag[n])
|
|
|
|
#define car(x) (Car[x])
|
|
#define cdr(x) (Cdr[x])
|
|
#define caar(x) (Car[Car[x]])
|
|
#define cadr(x) (Car[Cdr[x]])
|
|
#define cdar(x) (Cdr[Car[x]])
|
|
#define cddr(x) (Cdr[Cdr[x]])
|
|
#define caaar(x) (Car[Car[Car[x]]])
|
|
#define caadr(x) (Car[Car[Cdr[x]]])
|
|
#define cadar(x) (Car[Cdr[Car[x]]])
|
|
#define caddr(x) (Car[Cdr[Cdr[x]]])
|
|
#define cdaar(x) (Cdr[Car[Car[x]]])
|
|
#define cdadr(x) (Cdr[Car[Cdr[x]]])
|
|
#define cddar(x) (Cdr[Cdr[Car[x]]])
|
|
#define cdddr(x) (Cdr[Cdr[Cdr[x]]])
|
|
#define caaaar(x) (Car[Car[Car[Car[x]]]])
|
|
#define caaadr(x) (Car[Car[Car[Cdr[x]]]])
|
|
#define caadar(x) (Car[Car[Cdr[Car[x]]]])
|
|
#define caaddr(x) (Car[Car[Cdr[Cdr[x]]]])
|
|
#define cadaar(x) (Car[Cdr[Car[Car[x]]]])
|
|
#define cadadr(x) (Car[Cdr[Car[Cdr[x]]]])
|
|
#define caddar(x) (Car[Cdr[Cdr[Car[x]]]])
|
|
#define cadddr(x) (Car[Cdr[Cdr[Cdr[x]]]])
|
|
#define cdaaar(x) (Cdr[Car[Car[Car[x]]]])
|
|
#define cdaadr(x) (Cdr[Car[Car[Cdr[x]]]])
|
|
#define cdadar(x) (Cdr[Car[Cdr[Car[x]]]])
|
|
#define cdaddr(x) (Cdr[Car[Cdr[Cdr[x]]]])
|
|
#define cddaar(x) (Cdr[Cdr[Car[Car[x]]]])
|
|
#define cddadr(x) (Cdr[Cdr[Car[Cdr[x]]]])
|
|
#define cdddar(x) (Cdr[Cdr[Cdr[Car[x]]]])
|
|
#define cddddr(x) (Cdr[Cdr[Cdr[Cdr[x]]]])
|
|
|
|
/*
|
|
* Tagged data types
|
|
*/
|
|
|
|
#define T_BYTECODE (-10)
|
|
#define T_CATCHTAG (-11)
|
|
#define T_CHAR (-12)
|
|
#define T_CLOSURE (-13)
|
|
#define T_FIXNUM (-14)
|
|
#define T_INPORT (-15)
|
|
#define T_OUTPORT (-16)
|
|
#define T_STRING (-17)
|
|
#define T_SYMBOL (-18)
|
|
#define T_VECTOR (-19)
|
|
|
|
/*
|
|
* Basic constructors
|
|
*/
|
|
|
|
#define cons(a, d) cons3((a), (d), 0)
|
|
#define mkatom(a, d) cons3((a), (d), ATOM_TAG)
|
|
|
|
/*
|
|
* Accessors
|
|
*/
|
|
|
|
#define portno(n) (cadr(n))
|
|
#define string(n) ((byte *) &Vectors[Cdr[n]])
|
|
#define stringlen(n) (Vectors[Cdr[n] - 1])
|
|
#define symname(n) (string(n))
|
|
#define symlen(n) (stringlen(n))
|
|
#define vector(n) (&Vectors[Cdr[n]])
|
|
#define veclink(n) (Vectors[Cdr[n] - 2])
|
|
#define vecndx(n) veclink(n)
|
|
#define vecsize(k) (2 + ((k) + sizeof(cell)-1) / sizeof(cell))
|
|
#define veclen(n) (vecsize(stringlen(n)) - 2)
|
|
|
|
/*
|
|
* Type predicates
|
|
*/
|
|
|
|
#define charp(n) \
|
|
(!specialp(n) && (tag(n) & ATOM_TAG) && T_CHAR == car(n))
|
|
|
|
#define closurep(n) \
|
|
(!specialp(n) && (tag(n) & ATOM_TAG) && T_CLOSURE == car(n))
|
|
|
|
#define ctagp(n) \
|
|
(!specialp(n) && (tag(n) & ATOM_TAG) && T_CATCHTAG == car(n))
|
|
|
|
#define eofp(n) (EOFMARK == (n))
|
|
|
|
#define fixp(n) \
|
|
(!specialp(n) && (tag(n) & ATOM_TAG) && T_FIXNUM == car(n))
|
|
|
|
#define inportp(n) \
|
|
(!specialp(n) && (tag(n) & ATOM_TAG) && \
|
|
(tag(n) & PORT_TAG) && T_INPORT == car(n))
|
|
|
|
#define outportp(n) \
|
|
(!specialp(n) && (tag(n) & ATOM_TAG) && \
|
|
(tag(n) & PORT_TAG) && T_OUTPORT == car(n))
|
|
|
|
#define stringp(n) \
|
|
(!specialp(n) && (tag(n) & VECTOR_TAG) && T_STRING == car(n))
|
|
|
|
#define symbolp(n) \
|
|
(!specialp(n) && (tag(n) & VECTOR_TAG) && T_SYMBOL == car(n))
|
|
|
|
#define vectorp(n) \
|
|
(!specialp(n) && (tag(n) & VECTOR_TAG) && T_VECTOR == car(n))
|
|
|
|
#define atomp(n) \
|
|
(specialp(n) || (tag(n) & ATOM_TAG) || (tag(n) & VECTOR_TAG))
|
|
|
|
#define pairp(x) (!atomp(x))
|
|
|
|
#define listp(x) (NIL == (x) || pairp(x))
|
|
|
|
#define constp(n) \
|
|
(!specialp(n) && (tag(n) & CONST_TAG))
|
|
|
|
/*
|
|
* Abstract machine opcodes
|
|
*/
|
|
|
|
enum { OP_ILL, OP_APPLIS, OP_APPLIST, OP_APPLY, OP_TAILAPP, OP_QUOTE,
|
|
OP_ARG, OP_REF, OP_PUSH, OP_PUSHTRUE, OP_PUSHVAL, OP_POP,
|
|
OP_DROP, OP_JMP, OP_BRF, OP_BRT, OP_HALT, OP_CATCHSTAR,
|
|
OP_THROWSTAR, OP_CLOSURE, OP_MKENV, OP_PROPENV, OP_CPREF,
|
|
OP_CPARG, OP_ENTER, OP_ENTCOL, OP_RETURN, OP_SETARG, OP_SETREF,
|
|
OP_MACRO,
|
|
|
|
OP_ABS, OP_ALPHAC, OP_ATOM, OP_BITOP, OP_CAAR, OP_CADR, OP_CAR,
|
|
OP_CDAR, OP_CDDR, OP_CDR, OP_CEQUAL, OP_CGRTR, OP_CGTEQ,
|
|
OP_CHAR, OP_CHARP, OP_CHARVAL, OP_CLESS, OP_CLOSE_PORT,
|
|
OP_CLTEQ, OP_CMDLINE, OP_CONC, OP_CONS, OP_CONSTP, OP_CTAGP,
|
|
OP_DELETE, OP_DIV, OP_DOWNCASE, OP_DUMP_IMAGE, OP_EOFP, OP_EQ,
|
|
OP_EQUAL, OP_ERROR, OP_ERROR2, OP_ERRPORT, OP_EVAL, OP_EXISTSP,
|
|
OP_FIXP, OP_FLUSH, OP_FORMAT, OP_FUNP, OP_GC, OP_GENSYM,
|
|
OP_GRTR, OP_GTEQ, OP_INPORT, OP_INPORTP, OP_LESS, OP_LISTSTR,
|
|
OP_LISTVEC, OP_LOAD, OP_LOWERC, OP_LTEQ, OP_MAX, OP_MIN,
|
|
OP_MINUS, OP_MKSTR, OP_MKVEC, OP_MX, OP_MX1, OP_NCONC,
|
|
OP_NEGATE, OP_NRECONC, OP_NULL, OP_NUMERIC, OP_NUMSTR,
|
|
OP_OBTAB, OP_OPEN_INFILE, OP_OPEN_OUTFILE, OP_OUTPORT,
|
|
OP_OUTPORTP, OP_PAIR, OP_PEEKC, OP_PLUS, OP_PRIN, OP_PRINC,
|
|
OP_QUIT, OP_READ, OP_READC, OP_RECONC, OP_REM, OP_RENAME,
|
|
OP_SCONC, OP_SEQUAL, OP_SETCAR, OP_SETCDR, OP_SET_INPORT,
|
|
OP_SET_OUTPORT, OP_SFILL, OP_SGRTR, OP_SGTEQ, OP_SIEQUAL,
|
|
OP_SIGRTR, OP_SIGTEQ, OP_SILESS, OP_SILTEQ, OP_SLESS, OP_SLTEQ,
|
|
OP_SREF, OP_SSET, OP_SSIZE, OP_STRINGP, OP_STRLIST, OP_STRNUM,
|
|
OP_SUBSTR, OP_SUBVEC, OP_SYMBOL, OP_SYMBOLP, OP_SYMNAME,
|
|
OP_SYMTAB, OP_SYSCMD, OP_TIMES, OP_UNTAG, OP_UPCASE, OP_UPPERC,
|
|
OP_VCONC, OP_VECLIST, OP_VECTORP, OP_VFILL, OP_VREF, OP_VSET,
|
|
OP_VSIZE, OP_WHITEC, OP_WRITEC };
|
|
|
|
/*
|
|
* I/O functions
|
|
*/
|
|
|
|
void prints(char *s);
|
|
void prin(cell x);
|
|
|
|
#define printb(s) prints((char *) s)
|
|
#define nl() prints("\n")
|
|
|
|
int set_outport(int port);
|
|
|
|
/*
|
|
* Error reporting and handling
|
|
*/
|
|
|
|
int Trace[NTRACE];
|
|
int Tp = 0;
|
|
|
|
void clrtrace(void) {
|
|
int i;
|
|
|
|
for (i=0; i<NTRACE; i++) Trace[i] = -1;
|
|
}
|
|
|
|
int gottrace(void) {
|
|
int i;
|
|
|
|
for (i=0; i<NTRACE; i++)
|
|
if (Trace[i] != -1) return 1;
|
|
return 0;
|
|
}
|
|
|
|
int Plimit = 0;
|
|
|
|
int Line = 1;
|
|
cell Files = NIL;
|
|
|
|
cell Symbols;
|
|
|
|
char *ntoa(int x, int r);
|
|
|
|
void report(char *s, cell x) {
|
|
int i, j, o;
|
|
|
|
o = set_outport(2);
|
|
prints("*** error: ");
|
|
prints(s);
|
|
if (x != UNDEF) {
|
|
prints(": ");
|
|
Plimit = 100;
|
|
prin(x);
|
|
Plimit = 0;
|
|
}
|
|
nl();
|
|
if (Files != NIL) {
|
|
prints("*** file: ");
|
|
printb(string(car(Files)));
|
|
prints(", line: ");
|
|
prints(ntoa(Line, 10));
|
|
nl();
|
|
}
|
|
if (gottrace()) {
|
|
prints("*** trace:");
|
|
i = Tp;
|
|
for (j=0; j<NTRACE; j++) {
|
|
if (i >= NTRACE) i = 0;
|
|
if (Trace[i] != -1) {
|
|
prints(" ");
|
|
printb(symname(vector(Symbols)[Trace[i]]));
|
|
}
|
|
i++;
|
|
}
|
|
nl();
|
|
}
|
|
set_outport(o);
|
|
}
|
|
|
|
jmp_buf Restart;
|
|
jmp_buf Errtag;
|
|
cell Handler = NIL;
|
|
|
|
cell Glob;
|
|
cell S_errtag, S_errval;
|
|
|
|
int assq(cell x, cell a);
|
|
void bindset(cell v, cell a);
|
|
cell mkstr(char *s, int k);
|
|
|
|
void error(char *s, cell x) {
|
|
cell n;
|
|
|
|
n = assq(S_errtag, Glob);
|
|
Handler = (NIL == n)? NIL: cadr(n);
|
|
if (Handler != NIL) {
|
|
n = assq(S_errval, Glob);
|
|
if (n != NIL && cadr(n) == Handler)
|
|
bindset(S_errval, mkstr(s, strlen(s)));
|
|
longjmp(Errtag, 1);
|
|
}
|
|
report(s, x);
|
|
longjmp(Restart, 1);
|
|
}
|
|
|
|
void expect(char *who, char *what, cell got) {
|
|
char b[100];
|
|
|
|
sprintf(b, "%s: expected %s", who, what);
|
|
error(b, got);
|
|
}
|
|
|
|
void fatal(char *s) {
|
|
fprintf(stderr, "*** fatal error: ");
|
|
fprintf(stderr, "%s\n", s);
|
|
bye(1);
|
|
}
|
|
|
|
/*
|
|
* Low-level input/output
|
|
*/
|
|
|
|
FILE *Ports[NPORTS];
|
|
char Port_flags[NPORTS];
|
|
|
|
int Inport = 0,
|
|
Outport = 1,
|
|
Errport = 2;
|
|
|
|
cell Outstr = NIL;
|
|
int Outmax = 0;
|
|
int Outptr = 0;
|
|
|
|
char *Instr = NULL;
|
|
char Rejected = -1;
|
|
|
|
int readc(void) {
|
|
int c;
|
|
|
|
if (Instr != NULL) {
|
|
if (Rejected > -1) {
|
|
c = Rejected;
|
|
Rejected = -1;
|
|
return c;
|
|
}
|
|
if (0 == *Instr) {
|
|
return EOF;
|
|
}
|
|
else {
|
|
return *Instr++;
|
|
}
|
|
}
|
|
else {
|
|
if (NULL == Ports[Inport])
|
|
fatal("readc: input port is not open");
|
|
return getc(Ports[Inport]);
|
|
}
|
|
}
|
|
|
|
void rejectc(int c) {
|
|
if (Instr != NULL) {
|
|
Rejected = c;
|
|
}
|
|
else {
|
|
ungetc(c, Ports[Inport]);
|
|
}
|
|
}
|
|
|
|
cell mkport(int p, cell t);
|
|
|
|
void flush(void) {
|
|
if (fflush(Ports[Outport]))
|
|
error("file write error, port",
|
|
mkport(Outport, T_OUTPORT));
|
|
}
|
|
|
|
void blockwrite(char *s, int k) {
|
|
cell n;
|
|
|
|
if (1 == Plimit) return;
|
|
if (Outstr != NIL) {
|
|
while (Outptr + k >= Outmax) {
|
|
n = mkstr(NULL, Outmax+1000);
|
|
memcpy(string(n), string(Outstr), Outptr);
|
|
Outmax += 1000;
|
|
Outstr = n;
|
|
}
|
|
memcpy(&string(Outstr)[Outptr], s, k);
|
|
Outptr += k;
|
|
string(Outstr)[Outptr] = 0;
|
|
return;
|
|
}
|
|
if (NULL == Ports[Outport])
|
|
fatal("blockwrite: output port is not open");
|
|
if (fwrite(s, 1, k, Ports[Outport]) != k)
|
|
error("file write error, port",
|
|
mkport(Outport, T_OUTPORT));
|
|
if ((1 == Outport || 2 == Outport) && '\n' == s[k-1])
|
|
flush();
|
|
if (Plimit) {
|
|
Plimit -= k;
|
|
if (Plimit < 1) Plimit = 1;
|
|
}
|
|
}
|
|
|
|
void writec(int c) {
|
|
char b[1];
|
|
|
|
b[0] = c;
|
|
blockwrite(b, 1);
|
|
}
|
|
|
|
void prints(char *s) {
|
|
blockwrite(s, strlen(s));
|
|
}
|
|
|
|
/*
|
|
* Memory management
|
|
*/
|
|
|
|
void alloc_nodepool(void) {
|
|
Car = malloc(sizeof(cell) * NNODES);
|
|
Cdr = malloc(sizeof(cell) * NNODES);
|
|
Tag = malloc(NNODES);
|
|
if (NULL == Car || NULL == Cdr || NULL == Tag)
|
|
fatal("alloc_nodepool: out of physical memory");
|
|
memset(Car, 0, sizeof(cell) * NNODES);
|
|
memset(Cdr, 0, sizeof(cell) * NNODES);
|
|
memset(Tag, 0, NNODES);
|
|
}
|
|
|
|
void alloc_vecpool(void) {
|
|
Vectors = malloc(sizeof(cell) * NVCELLS);
|
|
if (NULL == Vectors)
|
|
fatal("alloc_vecpool: out of physical memory");
|
|
memset(Vectors, 0, sizeof(cell) * NVCELLS);
|
|
}
|
|
|
|
#define OBFREE 0
|
|
#define OBALLOC 1
|
|
#define OBUSED 2
|
|
|
|
#define ISIZE0 1
|
|
#define ISIZE1 3
|
|
#define ISIZE2 5
|
|
|
|
#define fetcharg(a, i) (((a)[i] << 8) | (a)[(i)+1])
|
|
|
|
cell Obarray, Obmap;
|
|
|
|
void marklit(cell p) {
|
|
int i, k, op;
|
|
byte *v, *m;
|
|
|
|
k = stringlen(p);
|
|
v = string(p);
|
|
m = string(Obmap);
|
|
for (i=0; i<k; ) {
|
|
op = v[i];
|
|
if (OP_QUOTE == op) {
|
|
m[fetcharg(v, i+1)] = OBUSED;
|
|
i += ISIZE1;
|
|
}
|
|
else if (OP_ARG == op || OP_PUSHVAL == op || OP_JMP == op ||
|
|
OP_BRF == op || OP_BRT == op || OP_CLOSURE == op ||
|
|
OP_MKENV == op || OP_ENTER == op || OP_ENTCOL == op ||
|
|
OP_SETARG == op || OP_SETREF == op || OP_MACRO == op)
|
|
{
|
|
i += ISIZE1;
|
|
}
|
|
else if (OP_REF == op || OP_CPARG == op || OP_CPREF == op) {
|
|
i += ISIZE2;
|
|
}
|
|
else {
|
|
i += ISIZE0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Mark nodes which can be accessed through N.
|
|
* Using modified Deutsch/Schorr/Waite pointer reversal algorithm.
|
|
* S0: M==0, T==0, unvisited, process CAR (vectors: process 1st slot);
|
|
* S1: M==1, T==1, CAR visited, process CDR (vectors: process next slot);
|
|
* S2: M==1, T==0, completely visited, return to parent.
|
|
*/
|
|
|
|
void mark(cell n) {
|
|
cell x, parent, *v;
|
|
int i;
|
|
|
|
parent = NIL;
|
|
while (1) {
|
|
if (specialp(n) || (tag(n) & MARK_TAG)) {
|
|
if (NIL == parent)
|
|
break;
|
|
if (tag(parent) & VECTOR_TAG) { /* S1 --> S1|done */
|
|
i = vecndx(parent);
|
|
v = vector(parent);
|
|
if (tag(parent) & TRAV_TAG &&
|
|
i+1 < veclen(parent)
|
|
) { /* S1 --> S1 */
|
|
x = v[i+1];
|
|
v[i+1] = v[i];
|
|
v[i] = n;
|
|
n = x;
|
|
vecndx(parent) = i+1;
|
|
}
|
|
else { /* S1 --> done */
|
|
x = parent;
|
|
parent = v[i];
|
|
v[i] = n;
|
|
n = x;
|
|
veclink(n) = n;
|
|
}
|
|
}
|
|
else if (tag(parent) & TRAV_TAG) { /* S1 --> S2 */
|
|
x = cdr(parent);
|
|
cdr(parent) = car(parent);
|
|
car(parent) = n;
|
|
tag(parent) &= ~TRAV_TAG;
|
|
n = x;
|
|
}
|
|
else { /* S2 --> done */
|
|
x = parent;
|
|
parent = cdr(x);
|
|
cdr(x) = n;
|
|
n = x;
|
|
}
|
|
}
|
|
else if (tag(n) & VECTOR_TAG) { /* S0 --> S1 */
|
|
tag(n) |= MARK_TAG;
|
|
if (T_VECTOR == car(n) && veclen(n) != 0) {
|
|
tag(n) |= TRAV_TAG;
|
|
vecndx(n) = 0;
|
|
v = vector(n);
|
|
x = v[0];
|
|
v[0] = parent;
|
|
parent = n;
|
|
n = x;
|
|
}
|
|
else {
|
|
veclink(n) = n;
|
|
}
|
|
}
|
|
else if (tag(n) & ATOM_TAG) { /* S0 --> S2 */
|
|
if (cdr(n) != NIL) {
|
|
if (T_BYTECODE == car(n)) {
|
|
marklit(cdr(n));
|
|
}
|
|
else if (T_INPORT == car(n) ||
|
|
T_OUTPORT == car(n)
|
|
)
|
|
Port_flags[portno(n)] |= USED_TAG;
|
|
}
|
|
x = cdr(n);
|
|
cdr(n) = parent;
|
|
parent = n;
|
|
n = x;
|
|
tag(parent) |= MARK_TAG;
|
|
}
|
|
else { /* S0 --> S1 */
|
|
x = car(n);
|
|
car(n) = parent;
|
|
tag(n) |= MARK_TAG;
|
|
parent = n;
|
|
n = x;
|
|
tag(parent) |= TRAV_TAG;
|
|
}
|
|
}
|
|
}
|
|
|
|
int GC_verbose = 0;
|
|
cell *GC_roots[];
|
|
cell Rts;
|
|
int Sp;
|
|
|
|
int gc(void) {
|
|
int i, n, k, sk;
|
|
char buf[100];
|
|
cell *a;
|
|
byte *m;
|
|
|
|
for (i=0; i<NPORTS; i++) {
|
|
if (Port_flags[i] & LOCK_TAG)
|
|
Port_flags[i] |= USED_TAG;
|
|
else if (i == Inport || i == Outport)
|
|
Port_flags[i] |= USED_TAG;
|
|
else
|
|
Port_flags[i] &= ~USED_TAG;
|
|
}
|
|
if (Rts != NIL) {
|
|
sk = stringlen(Rts);
|
|
stringlen(Rts) = (1 + Sp) * sizeof(cell);
|
|
}
|
|
for (i=0; GC_roots[i] != NULL; i++) {
|
|
mark(*GC_roots[i]);
|
|
}
|
|
if (Rts != NIL) {
|
|
stringlen(Rts) = sk;
|
|
}
|
|
k = 0;
|
|
Freelist = NIL;
|
|
for (i=0; i<NNODES; i++) {
|
|
if (!(tag(i) & MARK_TAG)) {
|
|
cdr(i) = Freelist;
|
|
Freelist = i;
|
|
k++;
|
|
}
|
|
else {
|
|
tag(i) &= ~MARK_TAG;
|
|
}
|
|
}
|
|
for (i=0; i<NPORTS; i++) {
|
|
if (!(Port_flags[i] & USED_TAG) && Ports[i] != NULL) {
|
|
fclose(Ports[i]);
|
|
Ports[i] = NULL;
|
|
}
|
|
}
|
|
n = NIL == Obarray? 0: veclen(Obarray);
|
|
a = NIL == Obarray? NULL: vector(Obarray);
|
|
m = NIL == Obmap? NULL: string(Obmap);
|
|
for (i=0; i<n; i++) {
|
|
if (OBUSED == m[i]) {
|
|
m[i] = OBALLOC;
|
|
}
|
|
else {
|
|
m[i] = OBFREE;
|
|
a[i] = NIL;
|
|
}
|
|
}
|
|
if (GC_verbose) {
|
|
sprintf(buf, "GC: %d nodes reclaimed", k);
|
|
prints(buf); nl();
|
|
flush();
|
|
}
|
|
return k;
|
|
}
|
|
|
|
cell Tmp_car = NIL,
|
|
Tmp_cdr = NIL;
|
|
|
|
cell cons3(cell pcar, cell pcdr, int ptag) {
|
|
cell n;
|
|
int k;
|
|
|
|
if (NIL == Freelist) {
|
|
if (0 == (ptag & ~CONST_TAG))
|
|
Tmp_car = pcar;
|
|
if (!(ptag & VECTOR_TAG))
|
|
Tmp_cdr = pcdr;
|
|
k = gc();
|
|
if (k < NNODES / 2) {
|
|
/* memory low! */
|
|
}
|
|
Tmp_car = Tmp_cdr = NIL;
|
|
if (NIL == Freelist)
|
|
error("cons3: out of nodes", UNDEF);
|
|
}
|
|
n = Freelist;
|
|
Freelist = cdr(Freelist);
|
|
car(n) = pcar;
|
|
cdr(n) = pcdr;
|
|
tag(n) = ptag;
|
|
return n;
|
|
}
|
|
|
|
#define RAW_VECLINK 0
|
|
#define RAW_VECSIZE 1
|
|
#define RAW_VECDATA 2
|
|
|
|
void unmark_vecs(void) {
|
|
int p, k, link;
|
|
|
|
p = 0;
|
|
while (p < Freevec) {
|
|
link = p;
|
|
k = Vectors[p + RAW_VECSIZE];
|
|
p += vecsize(k);
|
|
Vectors[link] = NIL;
|
|
}
|
|
}
|
|
|
|
int gcv(void) {
|
|
int v, k, to, from;
|
|
char buf[100];
|
|
|
|
unmark_vecs();
|
|
gc(); /* re-mark live vectors */
|
|
to = from = 0;
|
|
while (from < Freevec) {
|
|
v = Vectors[from + RAW_VECSIZE];
|
|
k = vecsize(v);
|
|
if (Vectors[from + RAW_VECLINK] != NIL) {
|
|
if (to != from) {
|
|
memmove(&Vectors[to], &Vectors[from],
|
|
k * sizeof(cell));
|
|
cdr(Vectors[to + RAW_VECLINK]) =
|
|
to + RAW_VECDATA;
|
|
}
|
|
to += k;
|
|
}
|
|
from += k;
|
|
}
|
|
k = Freevec - to;
|
|
if (GC_verbose) {
|
|
sprintf(buf, "GCV: %d cells reclaimed", k);
|
|
prints(buf); nl();
|
|
flush();
|
|
}
|
|
Freevec = to;
|
|
return k;
|
|
}
|
|
|
|
cell newvec(cell type, int size) {
|
|
cell n;
|
|
int v, wsize;
|
|
|
|
wsize = vecsize(size);
|
|
if (Freevec + wsize >= NVCELLS) {
|
|
gcv();
|
|
if (Freevec + wsize >= NVCELLS)
|
|
error("newvec: out of vector space", UNDEF);
|
|
}
|
|
v = Freevec;
|
|
Freevec += wsize;
|
|
n = cons3(type, v + RAW_VECDATA, VECTOR_TAG);
|
|
Vectors[v + RAW_VECLINK] = n;
|
|
Vectors[v + RAW_VECSIZE] = size;
|
|
return n;
|
|
}
|
|
|
|
cell Protected = NIL;
|
|
cell Tmp = NIL;
|
|
|
|
#define protect(n) (Protected = cons((n), Protected))
|
|
|
|
cell unprot(int k) {
|
|
cell n = NIL; /*LINT*/
|
|
|
|
while (k) {
|
|
if (NIL == Protected)
|
|
error("unprot: stack underflow", UNDEF);
|
|
n = car(Protected);
|
|
Protected = cdr(Protected);
|
|
k--;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
/*
|
|
* High-level data types
|
|
*/
|
|
|
|
#define mkfix(n) mkatom(T_FIXNUM, mkatom((n), NIL))
|
|
|
|
#define fixval(n) (cadr(n))
|
|
|
|
#define add_ovfl(a,b) \
|
|
((((b) > 0) && ((a) > INT_MAX - (b))) || \
|
|
(((b) < 0) && ((a) < INT_MIN - (b))))
|
|
|
|
#define sub_ovfl(a,b) \
|
|
((((b) < 0) && ((a) > INT_MAX + (b))) || \
|
|
(((b) > 0) && ((a) < INT_MIN + (b))))
|
|
|
|
#define mkchar(c) mkatom(T_CHAR, mkatom((c) & 0xff, NIL))
|
|
|
|
#define charval(n) (cadr(n))
|
|
|
|
cell Nullstr = NIL;
|
|
|
|
cell mkstr(char *s, int k) {
|
|
cell n;
|
|
|
|
if (0 == k) return Nullstr;
|
|
n = newvec(T_STRING, k+1);
|
|
if (NULL == s) {
|
|
memset(string(n), 0, k+1);
|
|
}
|
|
else {
|
|
memcpy(string(n), s, k);
|
|
string(n)[k] = 0;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
cell Nullvec = NIL;
|
|
|
|
cell mkvec(int k) {
|
|
cell n, *v;
|
|
int i;
|
|
|
|
if (0 == k) return Nullvec;
|
|
n = newvec(T_VECTOR, k * sizeof(cell));
|
|
v = vector(n);
|
|
for (i=0; i<k; i++) v[i] = NIL;
|
|
return n;
|
|
}
|
|
|
|
cell mkport(int portnum, cell type) {
|
|
cell n;
|
|
int pf;
|
|
|
|
pf = Port_flags[portnum];
|
|
Port_flags[portnum] |= LOCK_TAG;
|
|
n = mkatom(portnum, NIL);
|
|
n = cons3(type, n, ATOM_TAG|PORT_TAG);
|
|
Port_flags[portnum] = pf;
|
|
return n;
|
|
}
|
|
|
|
int htsize(int n) {
|
|
if (n < 47) return 47;
|
|
if (n < 97) return 97;
|
|
if (n < 199) return 199;
|
|
if (n < 499) return 499;
|
|
if (n < 997) return 997;
|
|
if (n < 9973) return 9973;
|
|
if (n < 19997) return 19997;
|
|
return 39989;
|
|
}
|
|
|
|
cell mkht(int k) {
|
|
cell n;
|
|
|
|
n = mkfix(0); /* mutable, can't use Zero */
|
|
protect(n);
|
|
n = cons(n, mkvec(htsize(k)));
|
|
unprot(1);
|
|
return n;
|
|
}
|
|
|
|
#define htlen(d) veclen(cdr(d))
|
|
#define htelts(d) fixval(car(d))
|
|
#define htdata(d) cdr(d)
|
|
#define htslots(d) vector(cdr(d))
|
|
|
|
uint hash(byte *s, uint k) {
|
|
uint h = 0xabcd;
|
|
|
|
while (*s) h = ((h << 5) + h) ^ *s++;
|
|
return h % k;
|
|
}
|
|
|
|
uint obhash(cell x, uint k) {
|
|
if (specialp(x))
|
|
return abs(x) % k;
|
|
if (symbolp(x))
|
|
return hash(symname(x), k);
|
|
if (fixp(x))
|
|
return abs(fixval(x)) % k;
|
|
if (charp(x))
|
|
return charval(x) % k;
|
|
if (stringp(x))
|
|
return hash(string(x), k);
|
|
return 0;
|
|
}
|
|
|
|
int match(cell a, cell b) {
|
|
int k;
|
|
|
|
if (a == b) {
|
|
return 1;
|
|
}
|
|
if (fixp(a) && fixp(b)) {
|
|
return fixval(a) == fixval(b);
|
|
}
|
|
if (charp(a) && charp(b)) {
|
|
return charval(a) == charval(b);
|
|
}
|
|
if (symbolp(a) && symbolp(b)) {
|
|
k = symlen(a);
|
|
if (symlen(b) != k) return 0;
|
|
return memcmp(symname(a), symname(b), k) == 0;
|
|
}
|
|
if (stringp(a) && stringp(b)) {
|
|
k = stringlen(a);
|
|
if (stringlen(b) != k) return 0;
|
|
return memcmp(string(a), string(b), k) == 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void htgrow(cell d) {
|
|
int nk, i, h, k;
|
|
cell nd, e, n;
|
|
|
|
k = htlen(d);
|
|
nk = 1 + htlen(d);
|
|
nd = mkht(nk);
|
|
protect(nd);
|
|
nk = htlen(nd);
|
|
for (i = 0; i < k; i++) {
|
|
for (e = htslots(d)[i]; e != NIL; e = cdr(e)) {
|
|
h = obhash(caar(e), nk);
|
|
n = cons(car(e), htslots(nd)[h]);
|
|
htslots(nd)[h] = n;
|
|
}
|
|
}
|
|
htdata(d) = htdata(nd);
|
|
unprot(1);
|
|
}
|
|
|
|
int htlookup(cell d, cell k) {
|
|
cell x;
|
|
int h;
|
|
|
|
h = obhash(k, htlen(d));
|
|
x = htslots(d)[h];
|
|
while (x != NIL) {
|
|
if (match(caar(x), k)) return car(x);
|
|
x = cdr(x);
|
|
}
|
|
return UNDEF;
|
|
}
|
|
|
|
void htadd(cell d, cell k, cell v) {
|
|
cell e;
|
|
int h;
|
|
|
|
Tmp = k;
|
|
protect(v);
|
|
protect(k);
|
|
Tmp = NIL;
|
|
if (htelts(d) >= htlen(d))
|
|
htgrow(d);
|
|
h = obhash(k, htlen(d));
|
|
e = cons(k, v);
|
|
e = cons(e, htslots(d)[h]);
|
|
htslots(d)[h] = e;
|
|
htelts(d)++;
|
|
unprot(2);
|
|
}
|
|
|
|
cell htrem(cell d, cell k) {
|
|
cell *x, *v;
|
|
int h;
|
|
|
|
h = obhash(k, htlen(d));
|
|
v = htslots(d);
|
|
x = &v[h];
|
|
while (*x != NIL) {
|
|
if (match(caar(*x), k)) {
|
|
*x = cdr(*x);
|
|
htelts(d)--;
|
|
break;
|
|
}
|
|
x = &cdr(*x);
|
|
}
|
|
return d;
|
|
}
|
|
|
|
cell Symhash = NIL;
|
|
cell Symbols = NIL;
|
|
int Symptr = 0;
|
|
|
|
cell mksym(char *s, int k) {
|
|
cell n;
|
|
|
|
n = newvec(T_SYMBOL, k+1);
|
|
strcpy((char *) symname(n), s);
|
|
return n;
|
|
}
|
|
|
|
cell findsym(char *s) {
|
|
cell y;
|
|
|
|
y = mksym(s, strlen(s));
|
|
y = htlookup(Symhash, y);
|
|
if (y != UNDEF) return car(y);
|
|
return NIL;
|
|
}
|
|
|
|
cell intern(cell y) {
|
|
cell n, *vn, *vs;
|
|
int i, k;
|
|
|
|
protect(y);
|
|
htadd(Symhash, y, mkfix(Symptr));
|
|
unprot(1);
|
|
k = veclen(Symbols);
|
|
if (Symptr >= k) {
|
|
n = mkvec(k + CHUNKSIZE);
|
|
vs = vector(Symbols);
|
|
vn = vector(n);
|
|
for (i=0; i<k; i++) vn[i] = vs[i];
|
|
Symbols = n;
|
|
}
|
|
vector(Symbols)[Symptr] = y;
|
|
Symptr++;
|
|
return y;
|
|
}
|
|
|
|
cell symref(char *s) {
|
|
cell y, new;
|
|
|
|
y = findsym(s);
|
|
if (y != NIL) return y;
|
|
new = mksym(s, strlen(s));
|
|
return intern(new);
|
|
}
|
|
|
|
/*
|
|
* Some useful list functions
|
|
*/
|
|
|
|
cell reconc(cell n, cell m) {
|
|
while (n != NIL) {
|
|
if (atomp(n)) error("reconc: dotted list", n);
|
|
m = cons(car(n), m);
|
|
n = cdr(n);
|
|
}
|
|
return m;
|
|
}
|
|
|
|
#define reverse(n) reconc((n), NIL)
|
|
|
|
cell nreconc(cell n, cell m) {
|
|
cell h;
|
|
|
|
while (n != NIL) {
|
|
if (atomp(n)) error("nreconc: dotted list", n);
|
|
h = cdr(n);
|
|
cdr(n) = m;
|
|
m = n;
|
|
n = h;
|
|
}
|
|
return m;
|
|
}
|
|
|
|
#define nreverse(n) nreconc((n), NIL)
|
|
|
|
cell conc(cell a, cell b) {
|
|
cell n;
|
|
|
|
a = reverse(a);
|
|
protect(a);
|
|
n = b;
|
|
while (a != NIL) {
|
|
n = cons(car(a), n);
|
|
a = cdr(a);
|
|
}
|
|
unprot(1);
|
|
return n;
|
|
}
|
|
|
|
cell nconc(cell a, cell b) {
|
|
cell n;
|
|
|
|
n = a;
|
|
if (NIL == a) return b;
|
|
while (cdr(a) != NIL) a = cdr(a);
|
|
cdr(a) = b;
|
|
return n;
|
|
}
|
|
|
|
/*
|
|
* High-level port I/O
|
|
*/
|
|
|
|
int newport(void) {
|
|
int i, n;
|
|
|
|
for (n=0; n<2; n++) {
|
|
for (i=0; i<NPORTS; i++) {
|
|
if (NULL == Ports[i])
|
|
return i;
|
|
}
|
|
if (0 == n) gc();
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int open_inport(char *path) {
|
|
int i;
|
|
|
|
i = newport();
|
|
if (i < 0) return -1;
|
|
Ports[i] = fopen(path, "r");
|
|
if (NULL == Ports[i]) return -1;
|
|
return i;
|
|
}
|
|
|
|
int open_outport(char *path, int append) {
|
|
int i;
|
|
|
|
i = newport();
|
|
if (i < 0) return -1;
|
|
Ports[i] = fopen(path, append? "a": "w");
|
|
if (NULL == Ports[i]) return -1;
|
|
return i;
|
|
}
|
|
|
|
cell set_inport(cell port) {
|
|
cell p = Inport;
|
|
|
|
Inport = port;
|
|
return p;
|
|
}
|
|
|
|
int set_outport(int port) {
|
|
int p = Outport;
|
|
|
|
Outport = port;
|
|
return p;
|
|
}
|
|
|
|
void close_port(int port) {
|
|
if (port < 0 || port >= NPORTS)
|
|
return;
|
|
if (NULL == Ports[port]) {
|
|
Port_flags[port] = 0;
|
|
return;
|
|
}
|
|
fclose(Ports[port]);
|
|
Ports[port] = NULL;
|
|
Port_flags[port] = 0;
|
|
}
|
|
|
|
void reset_stdports(void) {
|
|
clearerr(stdin);
|
|
clearerr(stdout);
|
|
clearerr(stderr);
|
|
Inport = 0;
|
|
Outport = 1;
|
|
Errport = 2;
|
|
}
|
|
|
|
int lock_port(int port) {
|
|
if (port < 0 || port >= NPORTS)
|
|
return -1;
|
|
Port_flags[port] |= LOCK_TAG;
|
|
return 0;
|
|
}
|
|
|
|
int unlock_port(int port) {
|
|
if (port < 0 || port >= NPORTS)
|
|
return -1;
|
|
Port_flags[port] &= ~LOCK_TAG;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Global environment
|
|
*/
|
|
|
|
cell Glob = NIL;
|
|
|
|
void bindnew(cell v, cell a) {
|
|
cell n;
|
|
|
|
n = cons(a, NIL);
|
|
n = cons(v, n);
|
|
Glob = cons(n, Glob);
|
|
}
|
|
|
|
int assq(cell x, cell a) {
|
|
for (; a != NIL; a = cdr(a))
|
|
if (caar(a) == x) return car(a);
|
|
return NIL;
|
|
}
|
|
|
|
void bindset(cell v, cell a) {
|
|
cell b;
|
|
|
|
b = assq(v, Glob);
|
|
if (b != NIL) cadr(b) = a;
|
|
}
|
|
|
|
/*
|
|
* Reader
|
|
*/
|
|
|
|
cell S_apply, S_def, S_defmac, S_defun, S_errtag,
|
|
S_errval, S_if, S_ifstar, S_imagefile, S_labels, S_lambda,
|
|
S_macro, S_prog, S_quiet, S_quote, S_qquote, S_starstar,
|
|
S_splice, S_setq, S_start, S_unquote;
|
|
|
|
cell P_abs, P_alphac, P_atom, P_bitop, P_caar, P_cadr, P_car,
|
|
P_catchstar, P_cdar, P_cddr, P_cdr, P_cequal, P_cgrtr, P_cgteq,
|
|
P_char, P_charp, P_charval, P_cless, P_close_port, P_clteq,
|
|
P_cmdline, P_conc, P_cons, P_constp, P_ctagp, P_delete, P_div,
|
|
P_downcase, P_dump_image, P_eofp, P_eq, P_equal, P_gc, P_error,
|
|
P_errport, P_eval, P_existsp, P_fixp, P_flush, P_format, P_funp,
|
|
P_gensym, P_grtr, P_gteq, P_inport, P_inportp, P_less,
|
|
P_liststr, P_listvec, P_load, P_lowerc, P_lteq, P_max, P_min,
|
|
P_minus, P_mkstr, P_mkvec, P_mx, P_mx1, P_nconc, P_nreconc,
|
|
P_not, P_null, P_numeric, P_numstr, P_obtab, P_open_infile,
|
|
P_open_outfile, P_outport, P_outportp, P_pair, P_peekc, P_plus,
|
|
P_prin, P_princ, P_quit, P_read, P_readc, P_reconc, P_rem,
|
|
P_rename, P_sconc, P_sequal, P_set_inport, P_set_outport,
|
|
P_setcar, P_setcdr, P_sfill, P_sgrtr, P_sgteq, P_siequal,
|
|
P_sigrtr, P_sigteq, P_siless, P_silteq, P_sless, P_slteq,
|
|
P_sref, P_sset, P_ssize, P_stringp, P_strlist, P_strnum,
|
|
P_substr, P_subvec, P_symbol, P_symbolp, P_symname, P_symtab,
|
|
P_syscmd, P_throwstar, P_times, P_untag, P_upcase, P_upperc,
|
|
P_veclist, P_vconc, P_vectorp, P_vfill, P_vref, P_vset, P_vsize,
|
|
P_whitec, P_writec;
|
|
|
|
volatile int Intr;
|
|
|
|
int Inlist = 0;
|
|
int Quoting = 0;
|
|
|
|
#define octalp(c) \
|
|
('0' == (c) || '1' == (c) || '2' == (c) || '3' == (c) || \
|
|
'4' == (c) || '5' == (c) || '6' == (c) || '7' == (c))
|
|
|
|
int octchar(char *s) {
|
|
int v = 0;
|
|
|
|
if (!octalp(*s)) return -1;
|
|
while (octalp(*s)) {
|
|
v = 8*v + *s - '0';
|
|
s++;
|
|
}
|
|
return (*s || v > 255)? -1: v;
|
|
}
|
|
|
|
#define symbolic(c) \
|
|
(isalpha(c) || isdigit(c) || (c && strchr("!$%^&*-/_+=~.?<>:", c)))
|
|
|
|
#define LP '('
|
|
#define RP ')'
|
|
|
|
int strcmp_ci(char *s1, char *s2) {
|
|
int c1, c2;
|
|
|
|
while (1) {
|
|
c1 = tolower((int) *s1++);
|
|
c2 = tolower((int) *s2++);
|
|
if (!c1 || !c2 || c1 != c2)
|
|
break;
|
|
}
|
|
return c1-c2;
|
|
}
|
|
|
|
char *Readerr = NULL;
|
|
|
|
void rderror(char *s, cell x) {
|
|
if (NULL == Instr) error(s, x);
|
|
Readerr = s;
|
|
}
|
|
|
|
cell rdchar(void) {
|
|
char name[TOKLEN+1];
|
|
int i, c, v;
|
|
|
|
c = readc();
|
|
name[0] = c;
|
|
c = readc();
|
|
for (i=1; i<TOKLEN; i++) {
|
|
if (Intr || Readerr) return NIL;
|
|
if (!isalpha(c) && !isdigit(c)) break;
|
|
name[i] = c;
|
|
c = readc();
|
|
}
|
|
name[i] = 0;
|
|
rejectc(c);
|
|
if (TOKLEN == i)
|
|
rderror("char name too long",
|
|
mkstr(name, strlen(name)));
|
|
if (!strcmp_ci(name, "ht")) return mkchar(9);
|
|
if (!strcmp_ci(name, "nl")) return mkchar(10);
|
|
if (!strcmp_ci(name, "sp")) return mkchar(' ');
|
|
v = octchar(&name[1]);
|
|
if ('\\' == *name && v >= 0) return mkchar(v);
|
|
if (i != 1) rderror("bad character name",
|
|
mkstr(name, strlen(name)));
|
|
return mkchar(name[0]);
|
|
}
|
|
|
|
cell xread2(void);
|
|
|
|
cell rdlist(void) {
|
|
cell n, a, p;
|
|
cell new;
|
|
static char badpair[] = "malformed pair";
|
|
|
|
Inlist++;
|
|
n = xread2();
|
|
if (RPAREN == n) {
|
|
Inlist--;
|
|
return NIL;
|
|
}
|
|
p = NIL;
|
|
a = cons3(n, NIL, CONST_TAG);
|
|
protect(a);
|
|
while (n != RPAREN) {
|
|
if (Intr || Readerr) {
|
|
unprot(1);
|
|
return NIL;
|
|
}
|
|
if (EOFMARK == n) {
|
|
unprot(1);
|
|
rderror("missing ')'", UNDEF);
|
|
return NIL;
|
|
}
|
|
else if (DOT == n) {
|
|
if (NIL == p) {
|
|
unprot(1);
|
|
rderror(badpair, UNDEF);
|
|
return NIL;
|
|
}
|
|
n = xread2();
|
|
cdr(p) = n;
|
|
if (RPAREN == n || xread2() != RPAREN) {
|
|
unprot(1);
|
|
rderror(badpair, UNDEF);
|
|
return NIL;
|
|
}
|
|
Inlist--;
|
|
return unprot(1);
|
|
}
|
|
car(a) = n;
|
|
p = a;
|
|
n = xread2();
|
|
if (n != RPAREN) {
|
|
Tmp = n;
|
|
new = cons3(NIL, NIL, CONST_TAG);
|
|
Tmp = NIL;
|
|
cdr(a) = new;
|
|
a = cdr(a);
|
|
}
|
|
}
|
|
Inlist--;
|
|
return unprot(1);
|
|
}
|
|
|
|
cell listvec(cell x, int veclit);
|
|
|
|
cell rdvec(void) {
|
|
return listvec(rdlist(), 1);
|
|
}
|
|
|
|
int pos(int p, char *s) {
|
|
int i;
|
|
|
|
i = 0;
|
|
for (; *s; s++) {
|
|
if (p == *s) return i;
|
|
i++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
cell scanfix(char *s, int r, int of) {
|
|
int v, g, i;
|
|
char *p;
|
|
char d[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
|
|
g = 1;
|
|
p = s;
|
|
if ('+' == *p) {
|
|
p++;
|
|
}
|
|
else if ('-' == *p) {
|
|
p++;
|
|
g = -1;
|
|
}
|
|
v = 0;
|
|
while (*p) {
|
|
i = pos(tolower(*p), d);
|
|
if (i < 0 || i >= r) return NIL;
|
|
if ( v > INT_MAX/r ||
|
|
(v > 0 && add_ovfl(v*r, i)) ||
|
|
(v < 0 && sub_ovfl(v*r, i)))
|
|
{
|
|
if (!of) return NIL;
|
|
rderror("fixnum too big", mkstr(s, strlen(s)));
|
|
}
|
|
else if (v < 0)
|
|
v = v*r - i;
|
|
else
|
|
v = v*r + i;
|
|
p++;
|
|
if (g) v *= g;
|
|
g = 0;
|
|
}
|
|
if (g) return NIL;
|
|
return mkfix(v);
|
|
}
|
|
|
|
cell rdsymfix(int c, int r, int sym) {
|
|
char name[TOKLEN+1];
|
|
int i;
|
|
cell n;
|
|
|
|
for (i=0; i<TOKLEN; i++) {
|
|
if (!symbolic(c)) break;
|
|
name[i] = tolower(c);
|
|
c = readc();
|
|
}
|
|
name[i] = 0;
|
|
rejectc(c);
|
|
if (TOKLEN == i) rderror("symbol or fixnum too long",
|
|
mkstr(name, strlen(name)));
|
|
n = scanfix(name, r, 1);
|
|
if (n != NIL) return n;
|
|
if (!sym) rderror("invalid digits after #radixR",
|
|
mkstr(name, strlen(name)));
|
|
if ('t' == name[0] && 0 == name[1])
|
|
return TRUE;
|
|
if (!strcmp(name, "nil"))
|
|
return NIL;
|
|
return symref(name);
|
|
}
|
|
|
|
cell rdfix(int c) {
|
|
int r;
|
|
|
|
r = 0;
|
|
while (isdigit(c)) {
|
|
r = r*10 + c - '0';
|
|
c = readc();
|
|
}
|
|
if (c != 'r') rderror("'R' expected after #radix", UNDEF);
|
|
if (r < 2 || r > 36) rderror("bad radix in #radixR", mkfix(r));
|
|
c = readc();
|
|
return rdsymfix(c, r, 0);
|
|
}
|
|
|
|
cell rdstr(void) {
|
|
char name[TOKLEN+1];
|
|
int i, j, c, u, v;
|
|
cell n;
|
|
|
|
c = readc();
|
|
u = 0;
|
|
for (i=0; i<TOKLEN; i++) {
|
|
if (Intr || Readerr) return NIL;
|
|
if ('"' == c) break;
|
|
if ('\n' == c) Line++;
|
|
if (EOF == c) rderror("EOF in string", UNDEF);
|
|
if ('\\' == c) {
|
|
c = readc();
|
|
if ('\\' == c || '"' == c) {
|
|
/**/
|
|
}
|
|
else if ('t' == c) {
|
|
c = '\t';
|
|
}
|
|
else if ('n' == c) {
|
|
c = '\n';
|
|
}
|
|
else if (octalp(c)) {
|
|
v = 0;
|
|
j = 0;
|
|
while (j < 3 && octalp(c)) {
|
|
v = v * 8 + c-'0';
|
|
c = readc();
|
|
j++;
|
|
}
|
|
rejectc(c);
|
|
if (v > 255) rderror("invalid char", mkfix(v));
|
|
c = v;
|
|
}
|
|
else if (0 == u) {
|
|
u = c;
|
|
}
|
|
}
|
|
name[i] = c;
|
|
c = readc();
|
|
}
|
|
name[i] = 0;
|
|
if (u) rderror("unknown slash sequence", mkchar(u));
|
|
if (i >= TOKLEN) rderror("string too long", mkstr(name, i));
|
|
if (u) return NIL;
|
|
n = mkstr(name, i);
|
|
tag(n) |= CONST_TAG;
|
|
return n;
|
|
}
|
|
|
|
cell rdquote(cell q) {
|
|
cell n;
|
|
|
|
Quoting++;
|
|
n = xread2();
|
|
Quoting--;
|
|
return cons(q, cons(n, NIL));
|
|
}
|
|
|
|
cell xread2(void) {
|
|
int c;
|
|
|
|
c = readc();
|
|
while (1) {
|
|
while (' ' == c || '\t' == c || '\n' == c || '\r' == c) {
|
|
if (Intr || Readerr) return NIL;
|
|
if ('\n' == c) Line++;
|
|
c = readc();
|
|
}
|
|
if (c != ';') break;
|
|
while (c != '\n' && c != EOF)
|
|
c = readc();
|
|
}
|
|
if (Intr || Readerr) return NIL;
|
|
if (EOF == c) {
|
|
return EOFMARK;
|
|
}
|
|
else if ('#' == c) {
|
|
c = readc();
|
|
if ('\\' == c) return rdchar();
|
|
else if (LP == c) return rdvec();
|
|
else if (isdigit(c)) return rdfix(c);
|
|
else rderror("bad # syntax", mkchar(c));
|
|
}
|
|
else if ('"' == c) {
|
|
return rdstr();
|
|
}
|
|
else if (LP == c) {
|
|
return rdlist();
|
|
}
|
|
else if (RP == c) {
|
|
if (!Inlist) rderror("unexpected ')'", UNDEF);
|
|
return RPAREN;
|
|
}
|
|
else if ('\'' == c) {
|
|
return rdquote(S_quote);
|
|
}
|
|
else if ('`' == c || '@' == c) {
|
|
return rdquote(S_qquote);
|
|
}
|
|
else if (',' == c) {
|
|
c = readc();
|
|
if ('@' == c) return rdquote(S_splice);
|
|
rejectc(c);
|
|
return rdquote(S_unquote);
|
|
}
|
|
else if ('.' == c) {
|
|
if (!Inlist) rderror("unexpected '.'", UNDEF);
|
|
return DOT;
|
|
}
|
|
else {
|
|
return rdsymfix(c, 10, 1);
|
|
}
|
|
/*
|
|
else {
|
|
rderror("funny input character, code", mkfix(c));
|
|
}
|
|
*/
|
|
return NIL;
|
|
}
|
|
|
|
cell xread(void) {
|
|
cell x;
|
|
|
|
Inlist = 0;
|
|
Quoting = 0;
|
|
Readerr = NULL;
|
|
x = xread2();
|
|
if (Intr) error("aborted", UNDEF);
|
|
return x;
|
|
}
|
|
|
|
/*
|
|
* Printer
|
|
*/
|
|
|
|
char *ntoa(int x, int r) {
|
|
static char buf[200];
|
|
int i = 0, neg;
|
|
char *p = &buf[sizeof(buf)-1];
|
|
char d[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
|
|
neg = x<0;
|
|
*p = 0;
|
|
while (x || 0 == i) {
|
|
i++;
|
|
p--;
|
|
*p = d[abs(x % r)];
|
|
x = x / r;
|
|
}
|
|
if (neg) {
|
|
p--;
|
|
*p = '-';
|
|
}
|
|
return p;
|
|
}
|
|
|
|
void prchar(int sl, cell x) {
|
|
if (sl) {
|
|
prints("#\\");
|
|
if (9 == charval(x)) prints("ht");
|
|
else if (10 == charval(x)) prints("nl");
|
|
else if (' ' == charval(x)) prints("sp");
|
|
else if (charval(x) < 32 || charval(x) > 126) {
|
|
prints("\\");
|
|
prints(ntoa(fixval(x), 8));
|
|
}
|
|
else writec(charval(x));
|
|
}
|
|
else {
|
|
writec(charval(x));
|
|
}
|
|
}
|
|
|
|
void prfix(cell x) {
|
|
prints(ntoa(fixval(x), 10));
|
|
}
|
|
|
|
void prstr(int sl, cell x) {
|
|
int i, c;
|
|
|
|
if (sl) {
|
|
writec('"');
|
|
for (i=0; i<stringlen(x)-1; i++) {
|
|
c = (byte) string(x)[i];
|
|
if ('"' == c)
|
|
prints("\\\"");
|
|
else if ('\\' == c)
|
|
prints("\\\\");
|
|
else if (10 == c)
|
|
prints("\\n");
|
|
else if (c < ' ' || c > 126) {
|
|
writec('\\');
|
|
if (octalp(string(x)[i+1])) {
|
|
if (c < 100) writec('0');
|
|
if (c < 10) writec('0');
|
|
}
|
|
prints(ntoa(c, 8));
|
|
}
|
|
else
|
|
writec(c);
|
|
}
|
|
writec('"');
|
|
}
|
|
else {
|
|
printb(string(x));
|
|
}
|
|
}
|
|
|
|
void prex(int sl, cell x, int d);
|
|
|
|
void prlist(int sl, cell x, int d) {
|
|
writec(LP);
|
|
while (x != NIL && Plimit != 1) {
|
|
prex(sl, car(x), d+1);
|
|
x = cdr(x);
|
|
if (x != NIL) {
|
|
writec(' ');
|
|
if (atomp(x)) {
|
|
prints(". ");
|
|
prex(sl, x, d+1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
writec(RP);
|
|
}
|
|
|
|
void prvec(int sl, cell x, int d) {
|
|
int i;
|
|
|
|
prints("#(");
|
|
for (i=0; i<veclen(x); i++) {
|
|
prex(sl, vector(x)[i], d+1);
|
|
if (i < veclen(x)-1) writec(' ');
|
|
}
|
|
writec(')');
|
|
}
|
|
|
|
void prport(int out, cell x) {
|
|
prints("#<");
|
|
prints(out? "out": "in");
|
|
prints("port ");
|
|
prints(ntoa(portno(x), 10));
|
|
prints(">");
|
|
}
|
|
|
|
void pruspec(cell x) {
|
|
prints("#<special object ");
|
|
prints(ntoa(x, 10));
|
|
prints(">");
|
|
}
|
|
|
|
void pruatom(cell x) {
|
|
prints("#<atom ");
|
|
prints(ntoa(car(x), 10));
|
|
prints(">");
|
|
}
|
|
|
|
#define quoted(x, q) \
|
|
(car(x) == (q) && cdr(x) != NIL && NIL == cddr(x))
|
|
|
|
void prquote(int sl, cell x, int d) {
|
|
if (car(x) == S_quote) writec('\'');
|
|
else if (car(x) == S_qquote) writec('@');
|
|
else if (car(x) == S_unquote) writec(',');
|
|
else if (car(x) == S_splice) prints(",@");
|
|
prex(sl, cadr(x), d);
|
|
}
|
|
|
|
void prex(int sl, cell x, int d) {
|
|
if (d > PRDEPTH) {
|
|
prints("\n");
|
|
error("prin: nesting too deep", UNDEF);
|
|
}
|
|
if (Intr) {
|
|
Intr = 0;
|
|
error("interrupted", UNDEF);
|
|
}
|
|
if (NIL == x) prints("nil");
|
|
else if (TRUE == x) prints("t");
|
|
else if (EOFMARK == x) prints("#<eof>");
|
|
else if (UNDEF == x) prints("#<undef>");
|
|
else if (charp(x)) prchar(sl, x);
|
|
else if (fixp(x)) prfix(x);
|
|
else if (symbolp(x)) printb(symname(x));
|
|
else if (stringp(x)) prstr(sl, x);
|
|
else if (vectorp(x)) prvec(sl, x, d);
|
|
else if (closurep(x)) prints("#<function>");
|
|
else if (ctagp(x)) prints("#<catch tag>");
|
|
else if (inportp(x)) prport(0, x);
|
|
else if (outportp(x)) prport(1, x);
|
|
else if (specialp(x)) pruspec(x);
|
|
else if (atomp(x)) pruatom(x);
|
|
else if (quoted(x, S_quote)) prquote(sl, x, d);
|
|
else if (quoted(x, S_qquote)) prquote(sl, x, d);
|
|
else if (quoted(x, S_unquote)) prquote(sl, x, d);
|
|
else if (quoted(x, S_splice)) prquote(sl, x, d);
|
|
else prlist(sl, x, d);
|
|
}
|
|
|
|
void xprint(int sl, cell x) {
|
|
prex(sl, x, 0);
|
|
if (1 == Plimit) {
|
|
Plimit = 0;
|
|
prints("...");
|
|
}
|
|
}
|
|
|
|
void prin(cell x) { xprint(1, x); }
|
|
|
|
void princ(cell x) { xprint(0, x); }
|
|
|
|
void print1(cell x) { prin(x); nl(); } /* blame plan9's print() function */
|
|
|
|
/*
|
|
* Syntax checker
|
|
*/
|
|
|
|
int length(cell n) {
|
|
int k;
|
|
|
|
for (k = 0; n != NIL; n = cdr(n))
|
|
k++;
|
|
return k;
|
|
}
|
|
|
|
void ckargs(cell x, int min, int max) {
|
|
int k;
|
|
char buf[100];
|
|
|
|
k = length(x)-1;
|
|
if (k < min || (k > max && max >= 0)) {
|
|
sprintf(buf, "%s: wrong number of arguments",
|
|
symname(car(x)));
|
|
error(buf, x);
|
|
}
|
|
}
|
|
|
|
int syncheck(cell x, int top);
|
|
|
|
int ckseq(cell x, int top) {
|
|
for (; pairp(x); x = cdr(x))
|
|
syncheck(car(x), top);
|
|
return 0;
|
|
}
|
|
|
|
int ckapply(cell x) {
|
|
ckargs(x, 2, -1);
|
|
return 0;
|
|
}
|
|
|
|
int ckdef(cell x, int top) {
|
|
ckargs(x, 2, 2);
|
|
if (!symbolp(cadr(x)))
|
|
error("def: expected symbol", cadr(x));
|
|
if (!top) error("def: must be at top level", x);
|
|
return syncheck(caddr(x), 0);
|
|
}
|
|
|
|
int ckif(cell x) {
|
|
ckargs(x, 2, 3);
|
|
return ckseq(cdr(x), 0);
|
|
}
|
|
|
|
int ckifstar(cell x) {
|
|
ckargs(x, 2, 2);
|
|
return ckseq(cdr(x), 0);
|
|
}
|
|
|
|
int symlistp(cell x) {
|
|
cell p;
|
|
|
|
for (p = x; pairp(p); p = cdr(p)) {
|
|
if (!symbolp(car(p)))
|
|
return 0;
|
|
}
|
|
return symbolp(p) || NIL == p;
|
|
}
|
|
|
|
int memq(cell x, cell a) {
|
|
for (; a != NIL; a = cdr(a))
|
|
if (car(a) == x) return a;
|
|
return NIL;
|
|
}
|
|
|
|
int uniqlistp(cell x) {
|
|
if (NIL == x) return 1;
|
|
while (cdr(x) != NIL) {
|
|
if (memq(car(x), cdr(x)) != NIL)
|
|
return 0;
|
|
x = cdr(x);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
cell flatargs(cell a) {
|
|
cell n;
|
|
|
|
protect(n = NIL);
|
|
while (pairp(a)) {
|
|
n = cons(car(a), n);
|
|
car(Protected) = n;
|
|
a = cdr(a);
|
|
}
|
|
if (a != NIL) n = cons(a, n);
|
|
unprot(1);
|
|
return nreverse(n);
|
|
}
|
|
|
|
int cklambda(cell x) {
|
|
ckargs(x, 2, -1);
|
|
if (!symlistp(cadr(x)))
|
|
error("lambda: invalid formals", cadr(x));
|
|
if (!uniqlistp(flatargs(cadr(x))))
|
|
error("lambda: duplicate formal", cadr(x));
|
|
return ckseq(cddr(x), 0);
|
|
}
|
|
|
|
int ckmacro(cell x, int top) {
|
|
ckargs(x, 2, 2);
|
|
if (!symbolp(cadr(x)))
|
|
error("macro: expected symbol", cadr(x));
|
|
if (!top) error("macro: must be at top level", x);
|
|
return syncheck(caddr(x), 0);
|
|
}
|
|
|
|
int ckprog(cell x, int top) {
|
|
return ckseq(cdr(x), top);
|
|
}
|
|
|
|
int ckquote(cell x) {
|
|
ckargs(x, 1, 1);
|
|
return 0;
|
|
}
|
|
|
|
int cksetq(cell x) {
|
|
ckargs(x, 2, 2);
|
|
if (!symbolp(cadr(x)))
|
|
error("setq: expected symbol", cadr(x));
|
|
return ckseq(cddr(x), 0);
|
|
}
|
|
|
|
int syncheck(cell x, int top) {
|
|
cell p;
|
|
|
|
if (atomp(x)) return 0;
|
|
for (p = x; pairp(p); p = cdr(p))
|
|
;
|
|
if (p != NIL)
|
|
error("dotted list in program", x);
|
|
if (car(x) == S_apply) return ckapply(x);
|
|
if (car(x) == S_def) return ckdef(x, top);
|
|
if (car(x) == S_if) return ckif(x);
|
|
if (car(x) == S_ifstar) return ckifstar(x);
|
|
if (car(x) == S_lambda) return cklambda(x);
|
|
if (car(x) == S_macro) return ckmacro(x, top);
|
|
if (car(x) == S_prog) return ckprog(x, top);
|
|
if (car(x) == S_quote) return ckquote(x);
|
|
if (car(x) == S_setq) return cksetq(x);
|
|
return ckseq(x, top);
|
|
}
|
|
|
|
/*
|
|
* Compiler, closure conversion
|
|
*/
|
|
|
|
cell set_union(cell a, cell b) {
|
|
cell n;
|
|
|
|
a = reverse(a);
|
|
protect(a);
|
|
protect(n = b);
|
|
while (pairp(a)) {
|
|
if (memq(car(a), b) == NIL)
|
|
n = cons(car(a), n);
|
|
car(Protected) = n;
|
|
a = cdr(a);
|
|
}
|
|
if (a != NIL && memq(a, b) == NIL)
|
|
n = cons(a, n);
|
|
unprot(2);
|
|
return n;
|
|
}
|
|
|
|
int subrp(cell x);
|
|
|
|
cell freevars(cell x, cell e) {
|
|
cell n, u, a;
|
|
int lam;
|
|
|
|
lam = 0;
|
|
if (memq(x, e) != NIL) {
|
|
return NIL;
|
|
}
|
|
else if (symbolp(x)) {
|
|
return cons(x, NIL);
|
|
}
|
|
else if (!pairp(x)) {
|
|
return NIL;
|
|
}
|
|
else if (car(x) == S_quote) {
|
|
return NIL;
|
|
}
|
|
else if (car(x) == S_apply ||
|
|
car(x) == S_prog ||
|
|
car(x) == S_if ||
|
|
car(x) == S_ifstar ||
|
|
car(x) == S_setq
|
|
) {
|
|
x = cdr(x);
|
|
}
|
|
else if (car(x) == S_def ||
|
|
car(x) == S_macro
|
|
) {
|
|
x = cddr(x);
|
|
}
|
|
else if (subrp(car(x))) {
|
|
x = cdr(x);
|
|
}
|
|
else if (car(x) == S_lambda) {
|
|
protect(e);
|
|
a = flatargs(cadr(x));
|
|
protect(a);
|
|
n = set_union(a, e);
|
|
protect(n);
|
|
e = n;
|
|
x = cddr(x);
|
|
lam = 1;
|
|
}
|
|
protect(u = NIL);
|
|
while (pairp(x)) {
|
|
n = freevars(car(x), e);
|
|
protect(n);
|
|
u = set_union(u, n);
|
|
unprot(1);;
|
|
car(Protected) = u;
|
|
x = cdr(x);
|
|
}
|
|
n = unprot(1);
|
|
if (lam) e = unprot(3);
|
|
return n;
|
|
}
|
|
|
|
int posq(cell x, cell a) {
|
|
int n;
|
|
|
|
n = 0;
|
|
for (; a != NIL; a = cdr(a)) {
|
|
if (car(a) == x) return n;
|
|
n++;
|
|
}
|
|
return NIL;
|
|
}
|
|
|
|
cell I_a, I_e;
|
|
|
|
cell initmap(cell fv, cell e, cell a) {
|
|
cell m, n, p;
|
|
int i, j;
|
|
|
|
protect(m = NIL);
|
|
i = 0;
|
|
while (fv != NIL) {
|
|
p = cons(car(fv), NIL);
|
|
protect(p);
|
|
n = mkfix(i);
|
|
p = cons(n, p);
|
|
car(Protected) = p;
|
|
if ((j = posq(car(fv), a)) != NIL) {
|
|
n = mkfix(j);
|
|
p = cons(n, p);
|
|
unprot(1);
|
|
p = cons(I_a, p);
|
|
}
|
|
else if ((j = posq(car(fv), e)) != NIL) {
|
|
n = mkfix(j);
|
|
p = cons(n, p);
|
|
unprot(1);
|
|
p = cons(I_e, p);
|
|
}
|
|
else {
|
|
error("undefined symbol", car(fv));
|
|
}
|
|
m = cons(p, m);
|
|
car(Protected) = m;
|
|
i++;
|
|
fv = cdr(fv);
|
|
}
|
|
return nreverse(unprot(1));
|
|
}
|
|
|
|
cell lastpair(cell x) {
|
|
if (NIL == x) return NIL;
|
|
while (cdr(x) != NIL)
|
|
x = cdr(x);
|
|
return x;
|
|
}
|
|
|
|
cell Env = NIL,
|
|
Envp = NIL;
|
|
|
|
void newvar(cell x) {
|
|
cell n;
|
|
|
|
if (memq(x, Env) != NIL) return;
|
|
if (NIL == Envp) Envp = lastpair(Env);
|
|
n = cons(x, NIL);
|
|
cdr(Envp) = n;
|
|
Envp = n;
|
|
}
|
|
|
|
void newvars(cell x) {
|
|
while (x != NIL) {
|
|
newvar(car(x));
|
|
x = cdr(x);
|
|
}
|
|
}
|
|
|
|
cell cconv(cell x, cell e, cell a);
|
|
|
|
cell mapconv(cell x, cell e, cell a) {
|
|
cell n, new;
|
|
|
|
protect(n = NIL);
|
|
while (pairp(x)) {
|
|
new = cconv(car(x), e, a);
|
|
n = cons(new, n);
|
|
car(Protected) = n;
|
|
x = cdr(x);
|
|
}
|
|
return nreverse(unprot(1));
|
|
}
|
|
|
|
cell I_closure;
|
|
|
|
cell lamconv(cell x, cell e, cell a) {
|
|
cell cl, fv, args, m;
|
|
|
|
fv = freevars(x, NIL);
|
|
protect(fv);
|
|
newvars(fv);
|
|
args = flatargs(cadr(x));
|
|
protect(args);
|
|
m = initmap(fv, e, a);
|
|
protect(m);
|
|
cl = mapconv(cddr(x), fv, args);
|
|
cl = cons(m, cl);
|
|
cl = cons(cadr(x), cl);
|
|
cl = cons(I_closure, cl);
|
|
unprot(3);
|
|
return cl;
|
|
}
|
|
|
|
int contains(cell a, cell x) {
|
|
if (a == x) return 1;
|
|
if (pairp(a) && (contains(car(a), x) || contains(cdr(a), x)))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int liftable(cell x) {
|
|
return !contains(x, S_setq);
|
|
}
|
|
|
|
cell liftnames(cell m) {
|
|
#define name cadddr
|
|
cell a, n;
|
|
|
|
protect(a = NIL);
|
|
while (m != NIL) {
|
|
if (caar(m) == I_a) {
|
|
n = name(car(m));
|
|
a = cons(n, a);
|
|
car(Protected) = a;
|
|
}
|
|
m = cdr(m);
|
|
}
|
|
return nreverse(unprot(1));
|
|
#undef name
|
|
}
|
|
|
|
cell I_arg, I_ref;
|
|
|
|
cell liftargs(cell m) {
|
|
#define source cadr
|
|
cell a, n;
|
|
|
|
protect(a = NIL);
|
|
while (m != NIL) {
|
|
if (caar(m) == I_a) {
|
|
n = source(car(m));
|
|
n = cons(n, NIL);
|
|
n = cons(caar(m) == I_a? I_arg: I_ref, n);
|
|
a = cons(n, a);
|
|
car(Protected) = a;
|
|
}
|
|
m = cdr(m);
|
|
}
|
|
return nreverse(unprot(1));
|
|
#undef source
|
|
}
|
|
|
|
cell appconv(cell x, cell e, cell a) {
|
|
cell fn, as, fv, fnargs, m, n, lv, vars, cv;
|
|
|
|
fn = car(x);
|
|
as = cdr(x);
|
|
fv = freevars(fn, NIL);
|
|
protect(fv);
|
|
fnargs = flatargs(cadr(fn));
|
|
protect(fnargs);
|
|
newvars(fv);
|
|
m = initmap(fv, e, a);
|
|
protect(m);
|
|
as = mapconv(as, e, a);
|
|
protect(as);
|
|
n = liftargs(m);
|
|
as = nconc(n, as);
|
|
car(Protected) = as;
|
|
lv = liftnames(m);
|
|
protect(lv);
|
|
vars = conc(lv, cadr(fn));
|
|
protect(vars);
|
|
cv = set_union(lv, fnargs);
|
|
cadr(Protected) = cv;
|
|
fn = mapconv(cddr(fn), e, cv);
|
|
fn = cons(NIL, fn);
|
|
fn = cons(vars, fn);
|
|
fn = cons(I_closure, fn);
|
|
unprot(6);
|
|
return cons(fn, as);
|
|
}
|
|
|
|
cell defconv(cell x, cell e, cell a) {
|
|
cell n, m;
|
|
|
|
newvar(cadr(x));
|
|
n = cons(cconv(caddr(x), e, a), NIL);
|
|
protect(n);
|
|
m = mkfix(posq(cadr(x), e));
|
|
protect(m);
|
|
m = cons(I_ref, cons(m, cons(cadr(x), NIL)));
|
|
unprot(2);
|
|
return cons(S_setq, cons(m, n));
|
|
}
|
|
|
|
cell cconv(cell x, cell e, cell a) {
|
|
int n;
|
|
|
|
if ( pairp(x) &&
|
|
(S_apply == car(x) ||
|
|
S_if == car(x) ||
|
|
S_ifstar == car(x) ||
|
|
S_prog == car(x) ||
|
|
S_setq == car(x) ||
|
|
subrp(car(x))))
|
|
{
|
|
return cons(car(x), mapconv(cdr(x), e, a));
|
|
}
|
|
if ((n = posq(x, a)) != NIL) {
|
|
return cons(I_arg, cons(mkfix(n), NIL));
|
|
}
|
|
if ((n = posq(x, e)) != NIL) {
|
|
Tmp = mkfix(n);
|
|
n = cons(I_ref, cons(Tmp, cons(x, NIL)));
|
|
Tmp = NIL;
|
|
return n;
|
|
}
|
|
if (symbolp(x)) {
|
|
error("undefined symbol", x);
|
|
return NIL;
|
|
}
|
|
if (atomp(x)) {
|
|
return x;
|
|
}
|
|
if (S_quote == car(x)) {
|
|
return x;
|
|
}
|
|
if ( pairp(car(x)) &&
|
|
S_lambda == caar(x) &&
|
|
liftable(car(x)))
|
|
{
|
|
return appconv(x, e, a);
|
|
}
|
|
if (S_lambda == car(x)) {
|
|
return lamconv(x, e, a);
|
|
}
|
|
if (S_def == car(x)) {
|
|
return defconv(x, e, a);
|
|
}
|
|
if (S_macro == car(x)) {
|
|
return cons(car(x),
|
|
cons(cadr(x),
|
|
mapconv(cddr(x), e, a)));
|
|
}
|
|
return mapconv(x, e, a);
|
|
}
|
|
|
|
cell carof(cell a) {
|
|
cell n;
|
|
|
|
protect(n = NIL);
|
|
while (a != NIL) {
|
|
n = cons(caar(a), n);
|
|
car(Protected) = n;
|
|
a = cdr(a);
|
|
}
|
|
unprot(1);
|
|
return nreverse(n);
|
|
}
|
|
|
|
cell zipenv(cell vs, cell oe) {
|
|
cell n, b;
|
|
|
|
protect(n = NIL);
|
|
while (vs != NIL) {
|
|
if (NIL == oe) {
|
|
b = cons(car(vs), cons(UNDEF, NIL));
|
|
}
|
|
else {
|
|
b = car(oe);
|
|
oe = cdr(oe);
|
|
}
|
|
n = cons(b, n);
|
|
car(Protected) = n;
|
|
vs = cdr(vs);
|
|
}
|
|
return nreverse(unprot(1));
|
|
}
|
|
|
|
cell clsconv(cell x) {
|
|
cell n;
|
|
|
|
Env = carof(Glob);
|
|
Envp = NIL;
|
|
if (NIL == Env) Env = cons(UNDEF, NIL);
|
|
n = cconv(x, Env, NIL);
|
|
protect(n);
|
|
Glob = zipenv(Env, Glob);
|
|
return unprot(1);
|
|
}
|
|
|
|
/*
|
|
* Compiler, literal pool
|
|
*/
|
|
|
|
cell Obhash = NIL,
|
|
Obarray = NIL,
|
|
Obmap = NIL;
|
|
int Obptr = 0;
|
|
|
|
int obslot(void) {
|
|
int i, j, k, m;
|
|
byte *s;
|
|
cell n;
|
|
|
|
for (m = 0; m < 2; m++) {
|
|
for (j = 0; j < 2; j++) {
|
|
k = veclen(Obarray);
|
|
s = string(Obmap);
|
|
for (i=0; i<k; i++) {
|
|
if (OBFREE == s[Obptr]) {
|
|
s[Obptr] = OBALLOC;
|
|
return Obptr;
|
|
}
|
|
Obptr++;
|
|
if (Obptr >= k) Obptr = 0;
|
|
}
|
|
if (0 == j) gc();
|
|
}
|
|
if (k + CHUNKSIZE >= 64 * 1024) break;
|
|
n = mkvec(k + CHUNKSIZE);
|
|
memcpy(vector(n), vector(Obarray), k * sizeof(cell));
|
|
Obarray = n;
|
|
n = mkstr(NULL, k + CHUNKSIZE);
|
|
memset(string(n), OBFREE, k+CHUNKSIZE);
|
|
memcpy(string(n), string(Obmap), k);
|
|
Obmap = n;
|
|
}
|
|
error("out of object space", UNDEF);
|
|
return -1;
|
|
}
|
|
|
|
int obindex(cell x) {
|
|
cell n;
|
|
int i;
|
|
|
|
if (pairp(x) || vectorp(x) || closurep(x))
|
|
return obslot();
|
|
n = htlookup(Obhash, x);
|
|
if (n != UNDEF) {
|
|
i = fixval(cdr(n));
|
|
if ( string(Obmap)[i] != OBFREE &&
|
|
match(x, vector(Obarray)[i])
|
|
)
|
|
return i;
|
|
htrem(Obhash, x);
|
|
}
|
|
i = obslot();
|
|
htadd(Obhash, x, mkfix(i));
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
* Compiler, code generator
|
|
*/
|
|
|
|
cell Emitbuf = NIL;
|
|
int Here = 0;
|
|
|
|
void emit(int x) {
|
|
cell n;
|
|
byte *vp, *vn;
|
|
int i, k;
|
|
|
|
if (Here >= stringlen(cdr(Emitbuf))) {
|
|
protect(x);
|
|
k = stringlen(cdr(Emitbuf));
|
|
n = mkstr(NULL, CHUNKSIZE + k);
|
|
vp = string(cdr(Emitbuf));
|
|
vn = string(n);
|
|
for (i = 0; i < k; i++) vn[i] = vp[i];
|
|
cdr(Emitbuf) = n;
|
|
unprot(1);
|
|
}
|
|
string(cdr(Emitbuf))[Here] = x;
|
|
Here++;
|
|
}
|
|
|
|
#define emitop(op) emit(op)
|
|
|
|
void emitarg(int i) {
|
|
if (i < 0 || i > 65535)
|
|
error("bytecode argument out of range", mkfix(i));
|
|
emit(i >> 8);
|
|
emit(i & 255);
|
|
}
|
|
|
|
void emitq(cell x) {
|
|
int i;
|
|
|
|
i = obindex(x);
|
|
vector(Obarray)[i] = x;
|
|
emitop(OP_QUOTE);
|
|
emitarg(i);
|
|
}
|
|
|
|
void patch(int a, int n) {
|
|
if (n < 0 || n > 65535)
|
|
error("bytecode argument out of range", mkfix(n));
|
|
string(cdr(Emitbuf))[a] = n >> 8;
|
|
string(cdr(Emitbuf))[a+1] = n & 255;
|
|
}
|
|
|
|
cell Cts = NIL;
|
|
|
|
#define cpushval(x) (Cts = cons(mkfix(x), Cts))
|
|
|
|
cell cpopval(void) {
|
|
cell n;
|
|
|
|
if (NIL == Cts)
|
|
error("oops: compile stack underflow", UNDEF);
|
|
n = car(Cts);
|
|
Cts = cdr(Cts);
|
|
return fixval(n);
|
|
}
|
|
|
|
void swap(void) {
|
|
cell x;
|
|
|
|
if (NIL == Cts || NIL == cdr(Cts))
|
|
error("oops: compile stack underflow", UNDEF);
|
|
x = car(Cts);
|
|
car(Cts) = cadr(Cts);
|
|
cadr(Cts) = x;
|
|
}
|
|
|
|
int subr0(cell x) {
|
|
if (x == P_cmdline) return OP_CMDLINE;
|
|
if (x == P_errport) return OP_ERRPORT;
|
|
if (x == P_gc) return OP_GC;
|
|
if (x == P_gensym) return OP_GENSYM;
|
|
if (x == P_inport) return OP_INPORT;
|
|
if (x == P_obtab) return OP_OBTAB;
|
|
if (x == P_outport) return OP_OUTPORT;
|
|
if (x == P_quit) return OP_QUIT;
|
|
if (x == P_symtab) return OP_SYMTAB;
|
|
return -1;
|
|
}
|
|
|
|
int subr1(cell x) {
|
|
if (x == P_abs) return OP_ABS;
|
|
if (x == P_alphac) return OP_ALPHAC;
|
|
if (x == P_atom) return OP_ATOM;
|
|
if (x == P_caar) return OP_CAAR;
|
|
if (x == P_cadr) return OP_CADR;
|
|
if (x == P_car) return OP_CAR;
|
|
if (x == P_catchstar) return OP_CATCHSTAR;
|
|
if (x == P_cdar) return OP_CDAR;
|
|
if (x == P_cddr) return OP_CDDR;
|
|
if (x == P_cdr) return OP_CDR;
|
|
if (x == P_char) return OP_CHAR;
|
|
if (x == P_charp) return OP_CHARP;
|
|
if (x == P_charval) return OP_CHARVAL;
|
|
if (x == P_close_port) return OP_CLOSE_PORT;
|
|
if (x == P_constp) return OP_CONSTP;
|
|
if (x == P_ctagp) return OP_CTAGP;
|
|
if (x == P_delete) return OP_DELETE;
|
|
if (x == P_dump_image) return OP_DUMP_IMAGE;
|
|
if (x == P_downcase) return OP_DOWNCASE;
|
|
if (x == P_dump_image) return OP_DUMP_IMAGE;
|
|
if (x == P_eofp) return OP_EOFP;
|
|
if (x == P_eval) return OP_EVAL;
|
|
if (x == P_existsp) return OP_EXISTSP;
|
|
if (x == P_fixp) return OP_FIXP;
|
|
if (x == P_flush) return OP_FLUSH;
|
|
if (x == P_format) return OP_FORMAT;
|
|
if (x == P_funp) return OP_FUNP;
|
|
if (x == P_inportp) return OP_INPORTP;
|
|
if (x == P_liststr) return OP_LISTSTR;
|
|
if (x == P_listvec) return OP_LISTVEC;
|
|
if (x == P_load) return OP_LOAD;
|
|
if (x == P_lowerc) return OP_LOWERC;
|
|
if (x == P_mx) return OP_MX;
|
|
if (x == P_mx1) return OP_MX1;
|
|
if (x == P_not) return OP_NULL;
|
|
if (x == P_null) return OP_NULL;
|
|
if (x == P_numeric) return OP_NUMERIC;
|
|
if (x == P_open_infile) return OP_OPEN_INFILE;
|
|
if (x == P_outportp) return OP_OUTPORTP;
|
|
if (x == P_pair) return OP_PAIR;
|
|
if (x == P_set_inport) return OP_SET_INPORT;
|
|
if (x == P_set_outport) return OP_SET_OUTPORT;
|
|
if (x == P_ssize) return OP_SSIZE;
|
|
if (x == P_stringp) return OP_STRINGP;
|
|
if (x == P_strlist) return OP_STRLIST;
|
|
if (x == P_symbol) return OP_SYMBOL;
|
|
if (x == P_symbolp) return OP_SYMBOLP;
|
|
if (x == P_symname) return OP_SYMNAME;
|
|
if (x == P_syscmd) return OP_SYSCMD;
|
|
if (x == P_untag) return OP_UNTAG;
|
|
if (x == P_upcase) return OP_UPCASE;
|
|
if (x == P_upperc) return OP_UPPERC;
|
|
if (x == P_veclist) return OP_VECLIST;
|
|
if (x == P_vectorp) return OP_VECTORP;
|
|
if (x == P_vsize) return OP_VSIZE;
|
|
if (x == P_whitec) return OP_WHITEC;
|
|
return -1;
|
|
}
|
|
|
|
int subr2(cell x) {
|
|
if (x == P_cons) return OP_CONS;
|
|
if (x == P_div) return OP_DIV;
|
|
if (x == P_eq) return OP_EQ;
|
|
if (x == P_nreconc) return OP_NRECONC;
|
|
if (x == P_reconc) return OP_RECONC;
|
|
if (x == P_rem) return OP_REM;
|
|
if (x == P_rename) return OP_RENAME;
|
|
if (x == P_sless) return OP_SLESS;
|
|
if (x == P_slteq) return OP_SLTEQ;
|
|
if (x == P_sequal) return OP_SEQUAL;
|
|
if (x == P_sgrtr) return OP_SGRTR;
|
|
if (x == P_sgteq) return OP_SGTEQ;
|
|
if (x == P_setcar) return OP_SETCAR;
|
|
if (x == P_setcdr) return OP_SETCDR;
|
|
if (x == P_sfill) return OP_SFILL;
|
|
if (x == P_siless) return OP_SILESS;
|
|
if (x == P_silteq) return OP_SILTEQ;
|
|
if (x == P_siequal) return OP_SIEQUAL;
|
|
if (x == P_sigrtr) return OP_SIGRTR;
|
|
if (x == P_sigteq) return OP_SIGTEQ;
|
|
if (x == P_sref) return OP_SREF;
|
|
if (x == P_throwstar) return OP_THROWSTAR;
|
|
if (x == P_vfill) return OP_VFILL;
|
|
if (x == P_vref) return OP_VREF;
|
|
return -1;
|
|
}
|
|
|
|
int subr3(cell x) {
|
|
if (x == P_sset) return OP_SSET;
|
|
if (x == P_substr) return OP_SUBSTR;
|
|
if (x == P_subvec) return OP_SUBVEC;
|
|
if (x == P_vset) return OP_VSET;
|
|
return -1;
|
|
}
|
|
|
|
int osubr0(cell x) {
|
|
if (x == P_peekc) return OP_PEEKC;
|
|
if (x == P_read) return OP_READ;
|
|
if (x == P_readc) return OP_READC;
|
|
return -1;
|
|
}
|
|
|
|
int osubr1(cell x) {
|
|
if (x == P_error) return OP_ERROR;
|
|
if (x == P_mkstr) return OP_MKSTR;
|
|
if (x == P_mkvec) return OP_MKVEC;
|
|
if (x == P_numstr) return OP_NUMSTR;
|
|
if (x == P_open_outfile) return OP_OPEN_OUTFILE;
|
|
if (x == P_prin) return OP_PRIN;
|
|
if (x == P_princ) return OP_PRINC;
|
|
if (x == P_strnum) return OP_STRNUM;
|
|
if (x == P_writec) return OP_WRITEC;
|
|
return -1;
|
|
}
|
|
|
|
int lsubr0(cell x) {
|
|
if (x == P_times) return OP_TIMES;
|
|
if (x == P_plus) return OP_PLUS;
|
|
if (x == P_conc) return OP_CONC;
|
|
if (x == P_nconc) return OP_NCONC;
|
|
if (x == P_sconc) return OP_SCONC;
|
|
if (x == P_vconc) return OP_VCONC;
|
|
return -1;
|
|
}
|
|
|
|
int lsubr1(cell x) {
|
|
if (x == P_bitop) return OP_BITOP;
|
|
if (x == P_max) return OP_MAX;
|
|
if (x == P_min) return OP_MIN;
|
|
if (x == P_minus) return OP_MINUS;
|
|
if (x == P_less) return OP_LESS;
|
|
if (x == P_lteq) return OP_LTEQ;
|
|
if (x == P_equal) return OP_EQUAL;
|
|
if (x == P_grtr) return OP_GRTR;
|
|
if (x == P_gteq) return OP_GTEQ;
|
|
if (x == P_cless) return OP_CLESS;
|
|
if (x == P_clteq) return OP_CLTEQ;
|
|
if (x == P_cequal) return OP_CEQUAL;
|
|
if (x == P_cgrtr) return OP_CGRTR;
|
|
if (x == P_cgteq) return OP_CGTEQ;
|
|
return -1;
|
|
}
|
|
|
|
int subrp(cell x) {
|
|
return subr0(x) >= 0 ||
|
|
subr1(x) >= 0 ||
|
|
subr2(x) >= 0 ||
|
|
subr3(x) >= 0 ||
|
|
osubr0(x) >= 0 ||
|
|
osubr1(x) >= 0 ||
|
|
lsubr0(x) >= 0 ||
|
|
lsubr1(x) >= 0;
|
|
}
|
|
|
|
void compexpr(cell x, int t);
|
|
|
|
void compprog(cell x, int t) {
|
|
x = cdr(x);
|
|
if (NIL == x) {
|
|
emitq(NIL);
|
|
return;
|
|
}
|
|
while (cdr(x) != NIL) {
|
|
compexpr(car(x), 0);
|
|
x = cdr(x);
|
|
}
|
|
compexpr(car(x), t);
|
|
}
|
|
|
|
void compsetq(cell x) {
|
|
compexpr(caddr(x), 0);
|
|
if (caadr(x) == I_ref) {
|
|
emitop(OP_SETREF);
|
|
emitarg(fixval(cadadr(x)));
|
|
}
|
|
else if (caadr(x) == I_arg) {
|
|
emitop(OP_SETARG);
|
|
emitarg(fixval(cadadr(x)));
|
|
}
|
|
else {
|
|
error("oops: unknown location in setq", x);
|
|
}
|
|
}
|
|
|
|
void compif(cell x, int t, int star) {
|
|
compexpr(cadr(x), 0);
|
|
emitop(star? OP_BRT: OP_BRF);
|
|
cpushval(Here);
|
|
emitarg(0);
|
|
compexpr(caddr(x), t);
|
|
if (cdddr(x) != NIL) {
|
|
emitop(OP_JMP);
|
|
cpushval(Here);
|
|
emitarg(0);
|
|
swap();
|
|
patch(cpopval(), Here);
|
|
compexpr(cadddr(x), t);
|
|
}
|
|
patch(cpopval(), Here);
|
|
}
|
|
|
|
void setupenv(cell m) {
|
|
while (m != NIL) {
|
|
if (caar(m) == I_e)
|
|
emitop(OP_CPREF);
|
|
else if (caar(m) == I_a)
|
|
emitop(OP_CPARG);
|
|
else
|
|
error("oops: unknown location in closure", m);
|
|
emitarg(fixval(cadar(m)));
|
|
emitarg(fixval(caddar(m)));
|
|
m = cdr(m);
|
|
}
|
|
}
|
|
|
|
cell dottedp(cell x) {
|
|
while (pairp(x)) x = cdr(x);
|
|
return x != NIL;
|
|
}
|
|
|
|
void compcls(cell x) {
|
|
int a, na;
|
|
cell b, m;
|
|
|
|
emitop(OP_JMP);
|
|
cpushval(Here);
|
|
emitarg(0);
|
|
a = Here;
|
|
na = length(flatargs(cadr(x)));
|
|
if (dottedp(cadr(x))) {
|
|
emitop(OP_ENTCOL);
|
|
emitarg(na-1);
|
|
}
|
|
else {
|
|
emitop(OP_ENTER);
|
|
emitarg(na);
|
|
}
|
|
b = cons(S_prog, cdddr(x));
|
|
protect(b);
|
|
compexpr(b, 1);
|
|
unprot(1);
|
|
emitop(OP_RETURN);
|
|
patch(cpopval(), Here);
|
|
m = caddr(x);
|
|
if (m != NIL) {
|
|
emitop(OP_MKENV);
|
|
emitarg(length(m));
|
|
setupenv(m);
|
|
}
|
|
else {
|
|
emitop(OP_PROPENV);
|
|
}
|
|
emitop(OP_CLOSURE);
|
|
emitarg(a);
|
|
}
|
|
|
|
void compapply(cell x, int t) {
|
|
cell xs;
|
|
|
|
xs = reverse(cddr(x));
|
|
protect(xs);
|
|
compexpr(car(xs), 0);
|
|
for (xs = cdr(xs); xs != NIL; xs = cdr(xs)) {
|
|
emitop(OP_PUSH);
|
|
compexpr(car(xs), 0);
|
|
emitop(OP_CONS);
|
|
}
|
|
emitop(OP_PUSH);
|
|
unprot(1);
|
|
compexpr(cadr(x), 0);
|
|
emitop(t? OP_APPLIST: OP_APPLIS);
|
|
}
|
|
|
|
void compapp(cell x, int t) {
|
|
cell xs;
|
|
|
|
xs = reverse(cdr(x));
|
|
protect(xs);
|
|
while (xs != NIL) {
|
|
compexpr(car(xs), 0);
|
|
emitop(OP_PUSH);
|
|
xs = cdr(xs);
|
|
}
|
|
unprot(1);
|
|
emitop(OP_PUSHVAL);
|
|
emitarg(length(cdr(x)));
|
|
compexpr(car(x), 0);
|
|
emitop(t? OP_TAILAPP: OP_APPLY);
|
|
}
|
|
|
|
void compsubr0(cell x, int op) {
|
|
ckargs(x, 0, 0);
|
|
emitop(op);
|
|
}
|
|
|
|
void compsubr1(cell x, int op) {
|
|
ckargs(x, 1, 1);
|
|
compexpr(cadr(x), 0);
|
|
emitop(op);
|
|
if (OP_CATCHSTAR == op) emitop(OP_APPLY);
|
|
}
|
|
|
|
void compsubr2(cell x, int op) {
|
|
ckargs(x, 2, 2);
|
|
compexpr(caddr(x), 0);
|
|
emitop(OP_PUSH);
|
|
compexpr(cadr(x), 0);
|
|
emitop(op);
|
|
}
|
|
|
|
void compsubr3(cell x, int op) {
|
|
ckargs(x, 3, 3);
|
|
compexpr(cadddr(x), 0);
|
|
emitop(OP_PUSH);
|
|
compexpr(caddr(x), 0);
|
|
emitop(OP_PUSH);
|
|
compexpr(cadr(x), 0);
|
|
emitop(op);
|
|
}
|
|
|
|
void composubr0(cell x, int op) {
|
|
ckargs(x, 0, 1);
|
|
if (NIL == cdr(x))
|
|
emitop(OP_INPORT);
|
|
else
|
|
compexpr(cadr(x), 0);
|
|
emitop(op);
|
|
}
|
|
|
|
cell Blank = NIL;
|
|
cell Zero = NIL;
|
|
cell One = NIL;
|
|
cell Ten = NIL;
|
|
|
|
void composubr1(cell x, int op) {
|
|
ckargs(x, 1, 2);
|
|
if (NIL == cddr(x)) {
|
|
if (OP_ERROR == op) {
|
|
/**/
|
|
}
|
|
else if (OP_MKSTR == op) {
|
|
emitq(Blank);
|
|
}
|
|
else if (OP_MKVEC == op) {
|
|
emitq(NIL);
|
|
}
|
|
else if (OP_OPEN_OUTFILE == op) {
|
|
emitq(NIL);
|
|
}
|
|
else if (OP_NUMSTR == op || OP_STRNUM == op) {
|
|
emitq(Ten);
|
|
}
|
|
else if (OP_WRITEC == op ||
|
|
OP_PRIN == op ||
|
|
OP_PRINC == op)
|
|
{
|
|
emitop(OP_OUTPORT);
|
|
}
|
|
}
|
|
else {
|
|
if (OP_ERROR == op) op = OP_ERROR2;
|
|
compexpr(caddr(x), 0);
|
|
}
|
|
emitop(OP_PUSH);
|
|
compexpr(cadr(x), 0);
|
|
emitop(op);
|
|
}
|
|
|
|
void complsubr0(cell x, int op) {
|
|
if (NIL == cdr(x)) {
|
|
if (OP_PLUS == op)
|
|
emitq(Zero);
|
|
else if (OP_TIMES == op)
|
|
emitq(One);
|
|
else if (OP_VCONC == op)
|
|
emitq(Nullvec);
|
|
else if (OP_SCONC == op)
|
|
emitq(Nullstr);
|
|
else if (OP_CONC == op)
|
|
emitq(NIL);
|
|
else if (OP_NCONC == op)
|
|
emitq(NIL);
|
|
}
|
|
else if (NIL == cddr(x)) {
|
|
compexpr(cadr(x), 0);
|
|
}
|
|
else if (OP_CONC == op || OP_SCONC == op ||
|
|
OP_VCONC == op || OP_NCONC == op)
|
|
{
|
|
x = reverse(cdr(x));
|
|
protect(x);
|
|
emitq(NIL);
|
|
while (x != NIL) {
|
|
emitop(OP_PUSH);
|
|
compexpr(car(x), 0);
|
|
emitop(OP_CONS);
|
|
x = cdr(x);
|
|
}
|
|
unprot(1);
|
|
emitop(op);
|
|
}
|
|
else {
|
|
x = cdr(x);
|
|
protect(x);
|
|
compexpr(car(x), 0);
|
|
x = cdr(x);
|
|
while (x != NIL) {
|
|
emitop(OP_PUSH);
|
|
compexpr(car(x), 0);
|
|
emitop(op);
|
|
x = cdr(x);
|
|
}
|
|
unprot(1);
|
|
}
|
|
}
|
|
|
|
void compbitop(cell x) {
|
|
if (NIL == cddr(x) || NIL == cdddr(x))
|
|
error("bitop: too few arguments", cdr(x));
|
|
compexpr(cadr(x), 0);
|
|
emitop(OP_PUSH);
|
|
x = cddr(x);
|
|
compexpr(car(x), 0);
|
|
for (x = cdr(x); x != NIL; x = cdr(x)) {
|
|
emitop(OP_PUSH);
|
|
compexpr(car(x), 0);
|
|
emitop(OP_BITOP);
|
|
}
|
|
emitop(OP_DROP);
|
|
}
|
|
|
|
void complsubr1(cell x, int op) {
|
|
ckargs(x, 1, -1);
|
|
if (OP_BITOP == op) {
|
|
compbitop(x);
|
|
return;
|
|
}
|
|
if (NIL == cddr(x)) {
|
|
if (OP_MIN == op || OP_MAX == op) {
|
|
compexpr(cadr(x), 0);
|
|
}
|
|
else if (OP_MINUS == op) {
|
|
compexpr(cadr(x), 0);
|
|
emitop(OP_NEGATE);
|
|
}
|
|
else {
|
|
emitq(TRUE);
|
|
}
|
|
}
|
|
else {
|
|
if (op != OP_MINUS && op != OP_MIN && op != OP_MAX) {
|
|
emitop(OP_PUSHTRUE);
|
|
}
|
|
x = cdr(x);
|
|
compexpr(car(x), 0);
|
|
for (x = cdr(x); x != NIL; x = cdr(x)) {
|
|
emitop(OP_PUSH);
|
|
compexpr(car(x), 0);
|
|
emitop(op);
|
|
}
|
|
if (op != OP_MINUS && op != OP_MIN && op != OP_MAX)
|
|
emitop(OP_POP);
|
|
}
|
|
}
|
|
|
|
void compexpr(cell x, int t) {
|
|
int op;
|
|
cell y;
|
|
|
|
if (atomp(x)) {
|
|
emitq(x);
|
|
}
|
|
else if (car(x) == S_quote) {
|
|
emitq(cadr(x));
|
|
}
|
|
else if (car(x) == I_arg) {
|
|
emitop(OP_ARG);
|
|
emitarg(fixval(cadr(x)));
|
|
}
|
|
else if (car(x) == I_ref) {
|
|
emitop(OP_REF);
|
|
emitarg(fixval(cadr(x)));
|
|
y = htlookup(Symhash, caddr(x));
|
|
if (UNDEF == y)
|
|
emitarg(0);
|
|
else
|
|
emitarg(fixval(cdr(y)));
|
|
}
|
|
else if (car(x) == S_if) {
|
|
compif(x, t, 0);
|
|
}
|
|
else if (car(x) == S_ifstar) {
|
|
compif(x, t, 1);
|
|
}
|
|
else if (car(x) == I_closure) {
|
|
compcls(x);
|
|
}
|
|
else if (car(x) == S_prog) {
|
|
compprog(x, t);
|
|
}
|
|
else if (car(x) == S_setq) {
|
|
compsetq(x);
|
|
}
|
|
else if (car(x) == S_apply) {
|
|
compapply(x, t);
|
|
}
|
|
else if (car(x) == S_macro) {
|
|
compexpr(caddr(x), 0);
|
|
emitop(OP_MACRO);
|
|
y = htlookup(Symhash, cadr(x));
|
|
if (UNDEF == y) error("oops: unknown name in MACRO", cadr(x));
|
|
emitarg(fixval(cdr(y)));
|
|
}
|
|
else if ((op = subr0(car(x))) >= 0) {
|
|
compsubr0(x, op);
|
|
}
|
|
else if ((op = subr1(car(x))) >= 0) {
|
|
compsubr1(x, op);
|
|
}
|
|
else if ((op = subr2(car(x))) >= 0) {
|
|
compsubr2(x, op);
|
|
}
|
|
else if ((op = subr3(car(x))) >= 0) {
|
|
compsubr3(x, op);
|
|
}
|
|
else if ((op = osubr0(car(x))) >= 0) {
|
|
composubr0(x, op);
|
|
}
|
|
else if ((op = osubr1(car(x))) >= 0) {
|
|
composubr1(x, op);
|
|
}
|
|
else if ((op = lsubr0(car(x))) >= 0) {
|
|
complsubr0(x, op);
|
|
}
|
|
else if ((op = lsubr1(car(x))) >= 0) {
|
|
complsubr1(x, op);
|
|
}
|
|
else { /* application */
|
|
compapp(x, t);
|
|
}
|
|
}
|
|
|
|
cell subprog(cell x, int k) {
|
|
cell n;
|
|
byte *sx, *sn;
|
|
int i, j;
|
|
|
|
n = mkstr(NULL, k);
|
|
sx = string(x);
|
|
sn = string(n);
|
|
j = 0;
|
|
for (i=0; i<k; i++) {
|
|
sn[j] = sx[i];
|
|
j++;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
cell compile(cell x) {
|
|
cell n;
|
|
|
|
Emitbuf = mkatom(T_BYTECODE, mkstr(NULL, CHUNKSIZE));
|
|
Here = 0;
|
|
Cts = NIL;
|
|
compexpr(x, 0);
|
|
emitop(OP_HALT);
|
|
n = mkatom(T_BYTECODE, subprog(cdr(Emitbuf), Here));
|
|
Emitbuf = NIL;
|
|
return n;
|
|
}
|
|
|
|
/*
|
|
* Macro expander
|
|
*/
|
|
|
|
cell Macros = NIL;
|
|
|
|
void newmacro(int id, cell fn) {
|
|
cell n, name;
|
|
|
|
if (!closurep(fn)) expect("macro", "closure", fn);
|
|
name = vector(Symbols)[id];
|
|
n = assq(name, Macros);
|
|
if (NIL == n) {
|
|
n = cons(name, fn);
|
|
Macros = cons(n, Macros);
|
|
}
|
|
else {
|
|
cdr(n) = fn;
|
|
}
|
|
}
|
|
|
|
cell expand(cell x, int r);
|
|
|
|
cell mapexp(cell x, int r) {
|
|
cell p, n, new;
|
|
|
|
protect(x);
|
|
protect(n = NIL);
|
|
p = x;
|
|
while (pairp(p)) {
|
|
new = expand(car(p), r);
|
|
n = cons(new, n);
|
|
car(Protected) = n;
|
|
p = cdr(p);
|
|
}
|
|
if (p != NIL) error("dotted list in program", x);
|
|
n = nreverse(unprot(1));
|
|
unprot(1);
|
|
return n;
|
|
}
|
|
|
|
cell zip(cell a, cell b) {
|
|
cell n, p;
|
|
|
|
protect(n = NIL);
|
|
while (a != NIL && b != NIL) {
|
|
p = cons(car(a), car(b));
|
|
n = cons(p, n);
|
|
car(Protected) = n;
|
|
a = cdr(a);
|
|
b = cdr(b);
|
|
}
|
|
unprot(1);
|
|
return nreverse(n);
|
|
}
|
|
|
|
cell expanddef(cell x);
|
|
|
|
cell expandbody(cell x) {
|
|
cell n, vs, as;
|
|
|
|
protect(vs = NIL);
|
|
protect(as = NIL);
|
|
while ( pairp(x) &&
|
|
pairp(car(x)) &&
|
|
(caar(x) == S_def ||
|
|
caar(x) == S_defun))
|
|
{
|
|
if (caar(x) == S_def) {
|
|
n = car(x);
|
|
vs = cons(cadr(n), vs);
|
|
cadr(Protected) = vs;
|
|
n = cons(caddr(n), NIL);
|
|
as = cons(n, as);
|
|
car(Protected) = as;
|
|
}
|
|
else {
|
|
n = expanddef(car(x));
|
|
protect(n);
|
|
vs = cons(cadr(n), vs);
|
|
caddr(Protected) = vs;
|
|
n = cons(caddr(n), NIL);
|
|
as = cons(n, as);
|
|
cadr(Protected) = as;
|
|
unprot(1);
|
|
}
|
|
x = cdr(x);
|
|
}
|
|
if (NIL == vs) {
|
|
unprot(2);
|
|
return x;
|
|
}
|
|
as = car(Protected) = nreverse(as);
|
|
vs = cadr(Protected) = nreverse(vs);
|
|
n = cons(zip(vs, as), x);
|
|
n = cons(S_labels, n);
|
|
n = cons(n, NIL);
|
|
unprot(2);
|
|
return n;
|
|
}
|
|
|
|
cell expanddef(cell x) {
|
|
char b[100];
|
|
cell n;
|
|
|
|
if (!pairp(cadr(x))) {
|
|
sprintf(b, "%s: expected signature", symname(car(x)));
|
|
error(b, cadr(x));
|
|
}
|
|
n = cons(cdadr(x), expandbody(cddr(x)));
|
|
n = cons(S_lambda, n);
|
|
n = cons(n, NIL);
|
|
n = cons(caadr(x), n);
|
|
n = cons(car(x) == S_defun? S_def: S_macro, n);
|
|
return n;
|
|
}
|
|
|
|
volatile int Mxlev = 0;
|
|
|
|
cell eval(cell x, int r);
|
|
|
|
cell expand(cell x, int r) {
|
|
cell n, m;
|
|
|
|
if (Mxlev < 0) error("interrupted", UNDEF);
|
|
if (Mxlev > MXMAX)
|
|
error("too many levels of macro expansion", UNDEF);
|
|
if (atomp(x)) {
|
|
return x;
|
|
}
|
|
if (car(x) == S_quote) {
|
|
return x;
|
|
}
|
|
Mxlev++;
|
|
if (car(x) == S_lambda) {
|
|
protect(x);
|
|
n = mapexp(cddr(x), r);
|
|
n = cons(cadr(x), n);
|
|
n = cons(car(x), n);
|
|
unprot(1);
|
|
Mxlev--;
|
|
return n;
|
|
}
|
|
if (car(x) == S_defun || car(x) == S_defmac) {
|
|
protect(x);
|
|
x = expanddef(x);
|
|
car(Protected) = x;
|
|
x = expand(x, r);
|
|
unprot(1);
|
|
Mxlev--;
|
|
return x;
|
|
}
|
|
if ( symbolp(car(x)) &&
|
|
(m = assq(car(x), Macros)) != NIL)
|
|
{
|
|
protect(x);
|
|
n = cons(cdr(x), NIL);
|
|
n = cons(S_quote, n);
|
|
n = cons(n, NIL);
|
|
n = cons(cdr(m), n);
|
|
n = cons(S_apply, n);
|
|
x = eval(n, 1);
|
|
car(Protected) = x;
|
|
if (r) x = expand(x, r);
|
|
unprot(1);
|
|
Mxlev--;
|
|
return x;
|
|
}
|
|
x = mapexp(x, r);
|
|
Mxlev--;
|
|
return x;
|
|
}
|
|
|
|
/*
|
|
* Inline functions, arithmetics
|
|
*/
|
|
|
|
void fixover(char *who, cell x, cell y) {
|
|
char b[100];
|
|
|
|
sprintf(b, "%s: fixnum overflow", who);
|
|
error(b, cons(x, cons(y, NIL)));
|
|
}
|
|
|
|
cell add(cell x, cell y) {
|
|
if (!fixp(x)) expect("+", "fixnum", x);
|
|
if (!fixp(y)) expect("+", "fixnum", y);
|
|
if (add_ovfl(fixval(x), fixval(y))) fixover("+", x, y);
|
|
return mkfix(fixval(x) + fixval(y));
|
|
}
|
|
|
|
cell xsub(cell x, cell y) {
|
|
if (!fixp(x)) expect("-", "fixnum", x);
|
|
if (!fixp(y)) expect("-", "fixnum", y);
|
|
if (sub_ovfl(fixval(y), fixval(x))) fixover("+", y, x);
|
|
return mkfix(fixval(y) - fixval(x));
|
|
}
|
|
|
|
cell mul(cell x, cell y) {
|
|
int a, b;
|
|
|
|
if (!fixp(x)) expect("*", "fixnum", x);
|
|
if (!fixp(y)) expect("*", "fixnum", y);
|
|
a = fixval(x);
|
|
b = fixval(y);
|
|
/*
|
|
* Overflow of a*b is undefined, sooo
|
|
*/
|
|
/* Shortcuts, also protect later division */
|
|
if (0 == a || 0 == b) return Zero;
|
|
if (1 == a) return y;
|
|
if (1 == b) return x;
|
|
/* abs(INT_MIN) is undefined using two's complement, so */
|
|
if (INT_MIN == a || INT_MIN == b) fixover("*", x, y);
|
|
/* Catch the rest */
|
|
/* Bug: result may not be INT_MIN */
|
|
if (abs(a) > INT_MAX / abs(b)) fixover("*", x, y);
|
|
return mkfix(a * b);
|
|
}
|
|
|
|
cell intdiv(cell x, cell y) {
|
|
if (!fixp(x)) expect("div", "fixnum", x);
|
|
if (!fixp(y)) expect("div", "fixnum", y);
|
|
if (0 == fixval(y)) error("div: divide by zero", UNDEF);
|
|
return mkfix(fixval(x) / fixval(y));
|
|
}
|
|
|
|
cell intrem(cell x, cell y) {
|
|
if (!fixp(x)) expect("rem", "fixnum", x);
|
|
if (!fixp(y)) expect("rem", "fixnum", y);
|
|
if (0 == fixval(y)) error("rem: divide by zero", UNDEF);
|
|
return mkfix(fixval(x) % fixval(y));
|
|
}
|
|
|
|
#define stackset(n,v) (vector(Rts)[n] = (v))
|
|
|
|
void grtr(cell x, cell y) {
|
|
if (!fixp(x)) expect(">", "fixnum", x);
|
|
if (!fixp(y)) expect(">", "fixnum", y);
|
|
if (fixval(y) <= fixval(x)) stackset(Sp-1, NIL);
|
|
}
|
|
|
|
void gteq(cell x, cell y) {
|
|
if (!fixp(x)) expect(">=", "fixnum", x);
|
|
if (!fixp(y)) expect(">=", "fixnum", y);
|
|
if (fixval(y) < fixval(x)) stackset(Sp-1, NIL);
|
|
}
|
|
|
|
void less(cell x, cell y) {
|
|
if (!fixp(x)) expect("<", "fixnum", x);
|
|
if (!fixp(y)) expect("<", "fixnum", y);
|
|
if (fixval(y) >= fixval(x)) stackset(Sp-1, NIL);
|
|
}
|
|
|
|
void lteq(cell x, cell y) {
|
|
if (!fixp(x)) expect("<=", "fixnum", x);
|
|
if (!fixp(y)) expect("<=", "fixnum", y);
|
|
if (fixval(y) > fixval(x)) stackset(Sp-1, NIL);
|
|
}
|
|
|
|
void equal(cell x, cell y) {
|
|
if (!fixp(x)) expect("=", "fixnum", x);
|
|
if (!fixp(y)) expect("=", "fixnum", y);
|
|
if (fixval(y) != fixval(x)) stackset(Sp-1, NIL);
|
|
}
|
|
|
|
cell bitop(cell x, cell y, cell o) {
|
|
uint op, a, b;
|
|
int i;
|
|
|
|
if (!fixp(o)) expect("bitop", "fixnum", o);
|
|
if (!fixp(x)) expect("bitop", "fixnum", x);
|
|
if (!fixp(y)) expect("bitop", "fixnum", y);
|
|
op = fixval(o);
|
|
b = fixval(x);
|
|
a = i = fixval(y);
|
|
switch (op) {
|
|
case 0: a = 0; break;
|
|
case 1: a = a & b; break;
|
|
case 2: a = a & ~b; break;
|
|
case 3: /* a = a; */ break;
|
|
case 4: a = ~a & b; break;
|
|
case 5: a = b; break;
|
|
case 6: a = a ^ b; break;
|
|
case 7: a = a | b; break;
|
|
case 8: a = ~(a | b); break;
|
|
case 9: a = ~(a ^ b); break;
|
|
case 10: a = ~b; break;
|
|
case 11: a = a | ~b; break;
|
|
case 12: a = ~a; break;
|
|
case 13: a = ~a | b; break;
|
|
case 14: a = ~(a & b); break;
|
|
case 15: a = ~0; break;
|
|
case 16: a = a << b; break;
|
|
case 17: a = i >> b; break;
|
|
case 18: a = a >> b; break;
|
|
default: error("bitop: invalid opcode", o);
|
|
break;
|
|
}
|
|
return mkfix(a);
|
|
}
|
|
|
|
/*
|
|
* Inline functions, characters
|
|
*/
|
|
|
|
void cless(cell x, cell y) {
|
|
if (!charp(x)) expect("c<", "char", x);
|
|
if (!charp(y)) expect("c<", "char", y);
|
|
if (charval(y) >= charval(x)) stackset(Sp-1, NIL);
|
|
}
|
|
|
|
void clteq(cell x, cell y) {
|
|
if (!charp(x)) expect("c<=", "char", x);
|
|
if (!charp(y)) expect("c<=", "char", y);
|
|
if (charval(y) > charval(x)) stackset(Sp-1, NIL);
|
|
}
|
|
|
|
void cequal(cell x, cell y) {
|
|
if (!charp(x)) expect("c=", "char", x);
|
|
if (!charp(y)) expect("c=", "char", y);
|
|
if (charval(y) != charval(x)) stackset(Sp-1, NIL);
|
|
}
|
|
|
|
void cgrtr(cell x, cell y) {
|
|
if (!charp(x)) expect("c>", "char", x);
|
|
if (!charp(y)) expect("c>", "char", y);
|
|
if (charval(y) <= charval(x)) stackset(Sp-1, NIL);
|
|
}
|
|
|
|
void cgteq(cell x, cell y) {
|
|
if (!charp(x)) expect("c>=", "char", x);
|
|
if (!charp(y)) expect("c>=", "char", y);
|
|
if (charval(y) < charval(x)) stackset(Sp-1, NIL);
|
|
}
|
|
|
|
#define whitespc(c) \
|
|
(' ' == (c) || \
|
|
'\t' == (c) || \
|
|
'\n' == (c) || \
|
|
'\r' == (c) || \
|
|
'\f' == (c))
|
|
|
|
/*
|
|
* Inline functions, strings
|
|
*/
|
|
|
|
int scomp(cell x, cell y) {
|
|
int kx, ky;
|
|
|
|
kx = stringlen(x);
|
|
ky = stringlen(y);
|
|
if (kx == ky) return memcmp(string(x), string(y), kx);
|
|
return memcmp(string(x), string(y), 1+(kx<ky? kx: ky));
|
|
}
|
|
|
|
int memcmp_ci(char *a, char *b, int k) {
|
|
int i, d;
|
|
|
|
for (i=0; i<k; i++) {
|
|
d = tolower(a[i]) - tolower(b[i]);
|
|
if (d) return d;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int scomp_ci(cell x, cell y) {
|
|
int kx, ky;
|
|
|
|
kx = stringlen(x);
|
|
ky = stringlen(y);
|
|
if (kx == ky)
|
|
return memcmp_ci((char *) string(x),
|
|
(char *) string(y), kx);
|
|
return memcmp_ci((char *) string(x), (char *) string(y),
|
|
1+(kx<ky? kx: ky));
|
|
}
|
|
|
|
cell sless(cell x, cell y) {
|
|
if (!string(x)) expect("s<", "string", x);
|
|
if (!string(y)) expect("s<", "string", y);
|
|
return scomp(x, y) < 0? TRUE: NIL;
|
|
}
|
|
|
|
cell slteq(cell x, cell y) {
|
|
if (!string(x)) expect("s<=", "string", x);
|
|
if (!string(y)) expect("s<=", "string", y);
|
|
return scomp(x, y) <= 0? TRUE: NIL;
|
|
}
|
|
|
|
cell sequal(cell x, cell y) {
|
|
if (!string(x)) expect("s=", "string", x);
|
|
if (!string(y)) expect("s=", "string", y);
|
|
if (stringlen(x) != stringlen(y)) return NIL;
|
|
return scomp(x, y) == 0? TRUE: NIL;
|
|
}
|
|
|
|
cell sgrtr(cell x, cell y) {
|
|
if (!string(x)) expect("s>", "string", x);
|
|
if (!string(y)) expect("s>", "string", y);
|
|
return scomp(x, y) > 0? TRUE: NIL;
|
|
}
|
|
|
|
cell sgteq(cell x, cell y) {
|
|
if (!string(x)) expect("s>=", "string", x);
|
|
if (!string(y)) expect("s>=", "string", y);
|
|
return scomp(x, y) >= 0? TRUE: NIL;
|
|
}
|
|
|
|
cell siless(cell x, cell y) {
|
|
if (!string(x)) expect("si<", "string", x);
|
|
if (!string(y)) expect("si<", "string", y);
|
|
return scomp_ci(x, y) < 0? TRUE: NIL;
|
|
}
|
|
|
|
cell silteq(cell x, cell y) {
|
|
if (!string(x)) expect("si<=", "string", x);
|
|
if (!string(y)) expect("si<=", "string", y);
|
|
return scomp_ci(x, y) <= 0? TRUE: NIL;
|
|
}
|
|
|
|
cell siequal(cell x, cell y) {
|
|
if (!string(x)) expect("si=", "string", x);
|
|
if (!string(y)) expect("si=", "string", y);
|
|
if (stringlen(x) != stringlen(y)) return NIL;
|
|
return scomp_ci(x, y) == 0? TRUE: NIL;
|
|
}
|
|
|
|
cell sigrtr(cell x, cell y) {
|
|
if (!string(x)) expect("si>", "string", x);
|
|
if (!string(y)) expect("si>", "string", y);
|
|
return scomp_ci(x, y) > 0? TRUE: NIL;
|
|
}
|
|
|
|
cell sigteq(cell x, cell y) {
|
|
if (!string(x)) expect("si>=", "string", x);
|
|
if (!string(y)) expect("si>=", "string", y);
|
|
return scomp_ci(x, y) >= 0? TRUE: NIL;
|
|
}
|
|
|
|
cell b_mkstr(cell x, cell a) {
|
|
cell n;
|
|
int i, c, k;
|
|
byte *s;
|
|
|
|
if (!fixp(x)) expect("mkstr", "fixnum", x);
|
|
if (!charp(a)) expect("mkstr", "char", a);
|
|
c = charval(a);
|
|
k = fixval(x);
|
|
n = mkstr(NULL, k);
|
|
s = string(n);
|
|
for (i=0; i<k; i++) s[i] = c;
|
|
return n;
|
|
}
|
|
|
|
cell sconc(cell x) {
|
|
cell p, n;
|
|
int k, m;
|
|
byte *s;
|
|
|
|
k = 0;
|
|
for (p = x; p != NIL; p = cdr(p)) {
|
|
if (!stringp(car(p)))
|
|
expect("sconc", "string", car(p));
|
|
k += stringlen(car(p))-1;
|
|
}
|
|
n = mkstr(NULL, k);
|
|
s = string(n);
|
|
k = 0;
|
|
for (p = x; p != NIL; p = cdr(p)) {
|
|
m = stringlen(car(p));
|
|
memcpy(&s[k], string(car(p)), m);
|
|
k += m-1;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
cell sref(cell s, cell n) {
|
|
int i;
|
|
|
|
if (!stringp(s)) expect("sref", "string", s);
|
|
if (!fixp(n)) expect("sref", "fixnum", n);
|
|
i = fixval(n);
|
|
if (i < 0 || i >= stringlen(s)-1)
|
|
error("sref: index out of range", n);
|
|
return mkchar(string(s)[i]);
|
|
}
|
|
|
|
void sset(cell s, cell n, cell r) {
|
|
int i;
|
|
|
|
if (!stringp(s)) expect("sset", "string", s);
|
|
if (constp(s)) error("sset: immutable", s);
|
|
if (!fixp(n)) expect("sset", "fixnum", n);
|
|
if (!charp(r)) expect("sset", "char", r);
|
|
i = fixval(n);
|
|
if (i < 0 || i >= stringlen(s)-1)
|
|
error("sset: index out of range", n);
|
|
string(s)[i] = charval(r);
|
|
}
|
|
|
|
cell substr(cell s, cell n0, cell n1) {
|
|
int k, k0, k1, i, j;
|
|
cell n;
|
|
byte *s0, *s1;
|
|
|
|
if (!stringp(s)) expect("substr", "string", s);
|
|
if (!fixp(n0)) expect("substr", "fixnum", n0);
|
|
if (!fixp(n1)) expect("substr", "fixnum", n1);
|
|
k0 = fixval(n0);
|
|
k1 = fixval(n1);
|
|
if (k0 < 0 || k1 < 0 || k0 > k1 || k1 >= stringlen(s))
|
|
error("substr: invalid range", cons(n0, cons(n1, NIL)));
|
|
k = k1-k0;
|
|
n = mkstr(NULL, k);
|
|
j = 0;
|
|
s0 = string(s);
|
|
s1 = string(n);
|
|
for (i=k0; i<k1; i++) {
|
|
s1[j] = s0[i];
|
|
j++;
|
|
}
|
|
s1[j] = 0;
|
|
return n;
|
|
}
|
|
|
|
void sfill(cell x, cell a) {
|
|
int c, i, k;
|
|
byte *s;
|
|
|
|
if (!stringp(x)) expect("sfill", "string", x);
|
|
if (constp(x)) error("sfill: immutable", x);
|
|
if (!charp(a)) expect("sfill", "char", a);
|
|
c = charval(a);
|
|
k = stringlen(x)-1;
|
|
s = string(x);
|
|
for (i=0; i<k; i++) s[i] = c;
|
|
}
|
|
|
|
/*
|
|
* Inline functions, vectors
|
|
*/
|
|
|
|
cell b_mkvec(cell x, cell a) {
|
|
cell n;
|
|
int i, k;
|
|
cell *v;
|
|
|
|
if (!fixp(x)) expect("mkvec", "fixnum", x);
|
|
k = fixval(x);
|
|
n = mkvec(k);
|
|
v = vector(n);
|
|
for (i=0; i<k; i++) v[i] = a;
|
|
return n;
|
|
}
|
|
|
|
cell vconc(cell x) {
|
|
cell p, n, *v;
|
|
int k, m;
|
|
|
|
k = 0;
|
|
for (p = x; p != NIL; p = cdr(p)) {
|
|
if (!vectorp(car(p)))
|
|
expect("vconc", "vector", car(p));
|
|
k += veclen(car(p));
|
|
}
|
|
n = mkvec(k);
|
|
v = vector(n);
|
|
k = 0;
|
|
for (p = x; p != NIL; p = cdr(p)) {
|
|
m = veclen(car(p));
|
|
memcpy(&v[k], vector(car(p)), m*sizeof(cell));
|
|
k += m;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
cell vref(cell x, cell n) {
|
|
int i;
|
|
|
|
if (!vectorp(x)) expect("vref", "vector", x);
|
|
if (!fixp(n)) expect("vref", "fixnum", n);
|
|
i = fixval(n);
|
|
if (i < 0 || i >= veclen(x))
|
|
error("vref: index out of range", n);
|
|
return vector(x)[i];
|
|
}
|
|
|
|
void vfill(cell x, cell a) {
|
|
int i, k;
|
|
cell *v;
|
|
|
|
if (!vectorp(x)) expect("vfill", "vector", x);
|
|
if (constp(x)) error("vfill: immutable", x);
|
|
k = veclen(x);
|
|
v = vector(x);
|
|
for (i=0; i<k; i++) v[i] = a;
|
|
}
|
|
|
|
void vset(cell v, cell n, cell r) {
|
|
int i;
|
|
|
|
if (!vectorp(v)) expect("vset", "vector", v);
|
|
if (constp(v)) error("vset: immutable", v);
|
|
if (!fixp(n)) expect("vset", "fixnum", n);
|
|
i = fixval(n);
|
|
if (i < 0 || i >= veclen(v))
|
|
error("vset: index out of range", n);
|
|
vector(v)[i] = r;
|
|
}
|
|
|
|
cell subvec(cell v, cell n0, cell n1) {
|
|
int k, k0, k1, i, j;
|
|
cell n;
|
|
cell *v0, *v1;
|
|
|
|
if (!vectorp(v)) expect("subvec", "vector", v);
|
|
if (!fixp(n0)) expect("subvec", "fixnum", n0);
|
|
if (!fixp(n1)) expect("subvec", "fixnum", n1);
|
|
k0 = fixval(n0);
|
|
k1 = fixval(n1);
|
|
if (k0 < 0 || k1 < 0 || k0 > k1 || k1 > veclen(v))
|
|
error("subvec: invalid range", cons(n0, cons(n1, NIL)));
|
|
k = k1-k0;
|
|
n = mkvec(k);
|
|
j = 0;
|
|
v0 = vector(v);
|
|
v1 = vector(n);
|
|
for (i=k0; i<k1; i++) {
|
|
v1[j] = v0[i];
|
|
j++;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
/*
|
|
* Inline functions, file I/O
|
|
*/
|
|
|
|
cell existsp(char *s) {
|
|
FILE *f;
|
|
|
|
f = fopen(s, "r");
|
|
if (f != NULL) fclose(f);
|
|
return NULL == f? NIL: TRUE;
|
|
}
|
|
|
|
cell openfile(cell x, int mode) {
|
|
int p;
|
|
|
|
switch (mode) {
|
|
case 0:
|
|
p = open_inport((char *) string(x));
|
|
break;
|
|
case 1:
|
|
p = open_outport((char *) string(x), 0);
|
|
break;
|
|
case 2:
|
|
p = open_outport((char *) string(x), 1);
|
|
break;
|
|
}
|
|
if (p < 0) {
|
|
if (0 == mode)
|
|
error("open-infile: cannot open", x);
|
|
else
|
|
error("open-outfile: cannot open", x);
|
|
}
|
|
return mkport(p, 0 == mode? T_INPORT: T_OUTPORT);
|
|
}
|
|
|
|
cell b_readc(cell p, int rej) {
|
|
int pp, c;
|
|
|
|
pp = Inport;
|
|
if (p != pp) set_inport(p);
|
|
c = readc();
|
|
if (rej) rejectc(c);
|
|
if (p != pp) set_inport(pp);
|
|
if (EOF == c) return EOFMARK;
|
|
return mkchar(c);
|
|
}
|
|
|
|
cell b_read(cell ps) {
|
|
int pp;
|
|
cell n;
|
|
|
|
if (stringp(ps)) {
|
|
Instr = (char *) string(ps);
|
|
Rejected = -1;
|
|
n = xread();
|
|
Instr = NULL;
|
|
if (Readerr) return mkstr(Readerr, strlen(Readerr));
|
|
return cons(n, NIL);
|
|
}
|
|
ps = portno(ps);
|
|
pp = Inport;
|
|
if (ps != pp) set_inport(ps);
|
|
n = xread();
|
|
if (ps != pp) set_inport(pp);
|
|
return n;
|
|
}
|
|
|
|
void b_prin(cell x, int p, int sl) {
|
|
int pp;
|
|
|
|
pp = Outport;
|
|
if (p != pp) set_outport(p);
|
|
prex(sl, x, 0);
|
|
if (p != pp) set_outport(pp);
|
|
}
|
|
|
|
cell format(cell x) {
|
|
cell n;
|
|
|
|
Outstr = mkstr(NULL, 1000);
|
|
Outmax = 1000;
|
|
Outptr = 0;
|
|
prex(1, x, 0);
|
|
n = mkstr(NULL, Outptr);
|
|
memcpy(string(n), string(Outstr), Outptr+1);
|
|
Outstr = NIL;
|
|
return n;
|
|
}
|
|
|
|
void b_writec(int c, cell p) {
|
|
int pp;
|
|
|
|
pp = Outport;
|
|
if (p != pp) set_outport(p);
|
|
writec(c);
|
|
if (p != pp) set_outport(pp);
|
|
}
|
|
|
|
void b_rename(int old, int new) {
|
|
if (!stringp(old)) expect("rename", "string", old);
|
|
if (!stringp(new)) expect("rename", "string", new);
|
|
#ifdef unix
|
|
if (rename((char *) string(old), (char *) string(new)) < 0)
|
|
error("rename: cannot rename",
|
|
cons(old, cons(new, NIL)));
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Inline functions, lists
|
|
*/
|
|
|
|
cell lconc(cell x) {
|
|
cell p, q, n, m;
|
|
int k;
|
|
|
|
if (NIL == cdr(x)) return car(x);
|
|
protect(n = cons(NIL, NIL));
|
|
k = 0;
|
|
for (p = x; cdr(p) != NIL; p = cdr(p)) {
|
|
if (NIL == car(p)) continue;
|
|
for (q = car(p); q != NIL; q = cdr(q)) {
|
|
if (!pairp(q))
|
|
expect("conc", "list", car(p));
|
|
if (k != 0) {
|
|
m = cons(NIL, NIL);
|
|
cdr(n) = m;
|
|
n = cdr(n);
|
|
}
|
|
car(n) = car(q);
|
|
k++;
|
|
}
|
|
}
|
|
m = unprot(1);
|
|
if (0 == k) return car(p);
|
|
cdr(n) = car(p);
|
|
return m;
|
|
}
|
|
|
|
cell nlconc(cell x) {
|
|
cell p, q;
|
|
|
|
while (pairp(cdr(x)) && NIL == car(x)) x = cdr(x);
|
|
if (NIL == cdr(x)) return car(x);
|
|
for (p = x; cdr(p) != NIL; p = cdr(p)) {
|
|
if (NIL == car(p)) continue;
|
|
if (constp(car(p))) error("nconc: immutable", car(p));
|
|
for (q = car(p); cdr(q) != NIL; q = cdr(q)) {
|
|
if (!pairp(q))
|
|
expect("nconc", "list", car(p));
|
|
}
|
|
while (pairp(cdr(p)) && NIL == cadr(p))
|
|
p = cdr(p);
|
|
if (NIL == cdr(p)) break;
|
|
cdr(q) = cadr(p);
|
|
}
|
|
return car(x);
|
|
}
|
|
|
|
/*
|
|
* Inline functions, type conversion
|
|
*/
|
|
|
|
cell b_symbol(cell x) {
|
|
cell y, n, k;
|
|
|
|
y = findsym((char *) string(x));
|
|
if (y != NIL) return y;
|
|
/*
|
|
* Cannot pass content to mksym(), because
|
|
* string(x) may move during GC.
|
|
*/
|
|
k = stringlen(x);
|
|
n = mksym("", k-1);
|
|
memcpy(symname(n), string(x), k);
|
|
return intern(n);
|
|
}
|
|
|
|
cell b_symname(cell x) {
|
|
cell n, k;
|
|
|
|
/*
|
|
* Cannot pass name to mkstr(), because
|
|
* symname(x) may move during GC.
|
|
*/
|
|
k = symlen(x);
|
|
n = mkstr(NULL, k-1);
|
|
Tag[n] |= CONST_TAG;
|
|
memcpy(string(n), symname(x), k);
|
|
return n;
|
|
}
|
|
|
|
cell liststr(cell x) {
|
|
cell n, v;
|
|
int k;
|
|
byte *s;
|
|
|
|
k = 0;
|
|
for (n = x; n != NIL; n = cdr(n))
|
|
k++;
|
|
v = mkstr(NULL, k);
|
|
s = string(v);
|
|
for (n = x; n != NIL; n = cdr(n)) {
|
|
if (atomp(n)) error("liststr: dotted list", x);
|
|
if (!charp(car(n))) expect("liststr", "char", car(n));
|
|
*s = charval(car(n));
|
|
s++;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
cell listvec(cell x, int veclit) {
|
|
cell n, v;
|
|
int k;
|
|
cell *p;
|
|
char *msg;
|
|
|
|
msg = veclit? "vector literal contains a dot":
|
|
"listvec: dotted list";
|
|
k = 0;
|
|
for (n = x; n != NIL; n = cdr(n))
|
|
k++;
|
|
if (0 == k) return Nullvec;
|
|
v = mkvec(k);
|
|
if (veclit) tag(v) |= CONST_TAG;
|
|
p = vector(v);
|
|
for (n = x; n != NIL; n = cdr(n)) {
|
|
if (atomp(n)) error(msg, x);
|
|
*p = car(n);
|
|
p++;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
cell strlist(cell x) {
|
|
cell a, new;
|
|
int k, i;
|
|
|
|
k = stringlen(x)-1;
|
|
if (0 == k) return NIL;
|
|
protect(a = cons(NIL, NIL));
|
|
for (i=0; i<k; i++) {
|
|
new = mkchar(string(x)[i]);
|
|
car(a) = new;
|
|
if (i < k-1) {
|
|
new = cons(NIL, NIL);
|
|
cdr(a) = new;
|
|
a = cdr(a);
|
|
}
|
|
}
|
|
return unprot(1);
|
|
}
|
|
|
|
cell veclist(cell x) {
|
|
cell a, new;
|
|
int k, i;
|
|
|
|
k = veclen(x);
|
|
if (0 == k) return NIL;
|
|
protect(a = cons(NIL, NIL));
|
|
for (i=0; i<k; i++) {
|
|
car(a) = vector(x)[i];
|
|
if (i < k-1) {
|
|
new = cons(NIL, NIL);
|
|
cdr(a) = new;
|
|
a = cdr(a);
|
|
}
|
|
}
|
|
return unprot(1);
|
|
}
|
|
|
|
cell numstr(cell x, int r) {
|
|
char *p;
|
|
|
|
if (r < 2 || r > 36)
|
|
error("numstr: bad radix", mkfix(r));
|
|
p = ntoa(fixval(x), r);
|
|
return mkstr(p, strlen(p));
|
|
}
|
|
|
|
cell strnum(char *s, int r) {
|
|
if (r < 2 || r > 36)
|
|
error("strnum: bad radix", mkfix(r));
|
|
return scanfix(s, r, 0);
|
|
}
|
|
|
|
/*
|
|
* Inline functions, LOAD
|
|
*/
|
|
|
|
void begin_rec(void);
|
|
void end_rec(void);
|
|
|
|
void loadfile(char *s) {
|
|
int ldport, rdport, oline;
|
|
cell x;
|
|
|
|
ldport = open_inport(s);
|
|
if (ldport < 0)
|
|
error("load: cannot open file",
|
|
mkstr(s, strlen(s)));
|
|
lock_port(ldport);
|
|
rdport = Inport;
|
|
oline = Line;
|
|
Files = cons(mkstr(s, strlen(s)), Files);
|
|
Line = 1;
|
|
begin_rec();
|
|
for (;;) {
|
|
set_inport(ldport);
|
|
x = xread();
|
|
set_inport(rdport);
|
|
if (EOFMARK == x) break;
|
|
eval(x, 0);
|
|
}
|
|
end_rec();
|
|
Files = cdr(Files);
|
|
Line = oline;
|
|
close_port(ldport);
|
|
}
|
|
|
|
void load(cell x) {
|
|
char path[TOKLEN+1];
|
|
|
|
if (!stringp(x))
|
|
expect("load", "string", x);
|
|
if (stringlen(x) > TOKLEN)
|
|
error("load: path too long", x);
|
|
strcpy(path, (char *) string(x));
|
|
loadfile(path);
|
|
}
|
|
|
|
/*
|
|
* Heap image I/O
|
|
*/
|
|
|
|
struct imghdr {
|
|
char magic[5]; /* "LISP9" */
|
|
char version[8]; /* "yyyymmdd" */
|
|
char cell_size[1]; /* size + '0' */
|
|
char byte_order[4]; /* e.g. "4321" */
|
|
char pad[14];
|
|
};
|
|
|
|
char *xfwrite(void *buf, int siz, int n, FILE *f) {
|
|
if (fwrite(buf, siz, n, f) != n)
|
|
return "image file write error";
|
|
return NULL;
|
|
}
|
|
|
|
cell *Imagevars[];
|
|
|
|
char *dumpimg(char *path) {
|
|
FILE *f;
|
|
cell n, **v;
|
|
int i;
|
|
struct imghdr m;
|
|
char *s;
|
|
|
|
f = fopen(path, "wb");
|
|
if (NULL == f) return "cannot create image file";
|
|
memset(&m, '_', sizeof(m));
|
|
strncpy(m.magic, "LISP9", sizeof(m.magic));
|
|
strncpy(m.version, VERSION, sizeof(m.version));
|
|
m.cell_size[0] = sizeof(cell)+'0';
|
|
n = 0x31323334L;
|
|
memcpy(m.byte_order, &n, 4);
|
|
if ((s = xfwrite(&m, sizeof(m), 1, f)) != NULL) {
|
|
fclose(f);
|
|
return s;
|
|
}
|
|
i = NNODES;
|
|
if ((s = xfwrite(&i, sizeof(int), 1, f)) != NULL) {
|
|
fclose(f);
|
|
return s;
|
|
}
|
|
i = NVCELLS;
|
|
if ((s = xfwrite(&i, sizeof(int), 1, f)) != NULL) {
|
|
fclose(f);
|
|
return s;
|
|
}
|
|
i = 0;
|
|
v = Imagevars;
|
|
while (v && v[i]) {
|
|
if ((s = xfwrite(v[i], sizeof(cell), 1, f)) != NULL) {
|
|
fclose(f);
|
|
return s;
|
|
}
|
|
i++;
|
|
}
|
|
if ( fwrite(Car, 1, sizeof(cell) * NNODES, f)
|
|
!= sizeof(cell) * NNODES ||
|
|
fwrite(Cdr, 1, sizeof(cell) * NNODES, f)
|
|
!= sizeof(cell) * NNODES ||
|
|
fwrite(Tag, 1, NNODES, f) != NNODES||
|
|
fwrite(Vectors, 1, sizeof(cell) * NVCELLS, f)
|
|
!= sizeof(cell) * NVCELLS)
|
|
{
|
|
fclose(f);
|
|
return "image dump failed";
|
|
}
|
|
fclose(f);
|
|
return NULL;
|
|
}
|
|
|
|
char *xfread(void *buf, int siz, int n, FILE *f) {
|
|
if (fread(buf, siz, n, f) != n)
|
|
return "image file read error";
|
|
return NULL;
|
|
}
|
|
|
|
char *loadimg(char *path) {
|
|
FILE *f;
|
|
cell n, **v;
|
|
int i;
|
|
struct imghdr m;
|
|
int image_nodes, image_vcells;
|
|
char *s;
|
|
|
|
f = fopen(path, "rb");
|
|
if (NULL == f)
|
|
return "could not open file";
|
|
if ((s = xfread(&m, sizeof(m), 1, f)) != NULL)
|
|
return s;
|
|
if (memcmp(m.magic, "LISP9", sizeof(m.magic))) {
|
|
fclose(f);
|
|
return "imghdr match failed";
|
|
}
|
|
if (memcmp(m.version, VERSION, sizeof(m.version))) {
|
|
fclose(f);
|
|
return "wrong image version";
|
|
}
|
|
if (m.cell_size[0]-'0' != sizeof(cell)) {
|
|
fclose(f);
|
|
return "wrong cell size";
|
|
}
|
|
memcpy(&n, m.byte_order, sizeof(cell));
|
|
if (n != 0x31323334L) {
|
|
fclose(f);
|
|
return "wrong byte order";
|
|
}
|
|
memset(Tag, 0, NNODES);
|
|
if ((s = xfread(&image_nodes, sizeof(int), 1, f)) != NULL)
|
|
return s;
|
|
if ((s = xfread(&image_vcells, sizeof(int), 1, f)) != NULL)
|
|
return s;
|
|
if (image_nodes != NNODES) {
|
|
fclose(f);
|
|
return "wrong node pool size";
|
|
}
|
|
if (image_vcells != NVCELLS) {
|
|
fclose(f);
|
|
return "wrong vector pool size";
|
|
}
|
|
v = Imagevars;
|
|
i = 0;
|
|
while (v && v[i]) {
|
|
if ((s = xfread(v[i], sizeof(cell), 1, f)) != NULL)
|
|
return s;
|
|
i++;
|
|
}
|
|
if ( (fread(Car, 1, sizeof(cell) * NNODES, f)
|
|
!= sizeof(cell) * NNODES ||
|
|
fread(Cdr, 1, sizeof(cell) * NNODES, f)
|
|
!= sizeof(cell) * NNODES ||
|
|
fread(Tag, 1, NNODES, f) != NNODES ||
|
|
fread(Vectors, 1, sizeof(cell) * NVCELLS, f)
|
|
!= sizeof(cell) * NVCELLS ||
|
|
fgetc(f) != EOF))
|
|
{
|
|
fclose(f);
|
|
return "wrong file size";
|
|
}
|
|
fclose(f);
|
|
return NULL;
|
|
}
|
|
|
|
void dump_image(cell s) {
|
|
char *rc;
|
|
|
|
rc = dumpimg((char *) string(s));
|
|
if (rc != NULL) {
|
|
remove((char *) string(s));
|
|
error(rc, s);
|
|
}
|
|
bindset(S_imagefile, s);
|
|
}
|
|
|
|
/*
|
|
* Inline functions, misc
|
|
*/
|
|
|
|
cell b_gc(void) {
|
|
cell n;
|
|
|
|
gcv();
|
|
n = cons(mkfix(NVCELLS-Freevec), NIL);
|
|
protect(n);
|
|
n = mkfix(length(Freelist));
|
|
return cons(n, unprot(1));
|
|
}
|
|
|
|
cell gensym(void) {
|
|
static int id = 0;
|
|
char b[100];
|
|
|
|
id++;
|
|
sprintf(b, "G%d", id);
|
|
return mksym(b, strlen(b));
|
|
}
|
|
|
|
cell untag(cell x) {
|
|
if (specialp(x)) return x;
|
|
if (tag(x) & VECTOR_TAG) return NIL;
|
|
if (closurep(x)) return cdr(cadddr(x));
|
|
return cdr(x);
|
|
}
|
|
|
|
/*
|
|
* Abstract machine
|
|
*/
|
|
|
|
cell Prog = NIL;
|
|
|
|
int Ip = 0;
|
|
|
|
cell Acc = NIL;
|
|
|
|
int Sz = CHUNKSIZE;
|
|
|
|
cell Rts = NIL;
|
|
int Sp = -1,
|
|
Fp = -1;
|
|
|
|
cell E0 = NIL,
|
|
Ep = NIL;
|
|
|
|
#define ins() (string(cdr(Prog))[Ip])
|
|
|
|
#define op1() fetcharg(string(cdr(Prog)), Ip+1)
|
|
#define op2() fetcharg(string(cdr(Prog)), Ip+3)
|
|
|
|
#define skip(n) (Ip += (n))
|
|
#define clear(n) (Sp -= (n))
|
|
|
|
#define box(x) cons((x), NIL)
|
|
#define boxref(x) car(x)
|
|
#define boxset(x,v) (car(x) = (v))
|
|
|
|
#define stackref(n) (vector(Rts)[n])
|
|
|
|
#define envbox(n) (vector(Ep)[n])
|
|
#define argbox(n) (stackref(Fp-(n)))
|
|
|
|
#define argref(n) boxref(argbox(n))
|
|
#define arg(n) boxref(stackref(Sp-(n)))
|
|
|
|
void stkalloc(int k) {
|
|
cell n, *vs, *vn;
|
|
int i;
|
|
|
|
if (Sp + k >= Sz) {
|
|
/* allocate multiples of CHUNKSIZE */
|
|
if (k >= CHUNKSIZE) {
|
|
k = Sp+k-Sz;
|
|
k = CHUNKSIZE * (1 + (k / CHUNKSIZE));
|
|
}
|
|
else {
|
|
k = CHUNKSIZE;
|
|
}
|
|
n = mkvec(Sz + k);
|
|
vs = vector(Rts);
|
|
vn = vector(n);
|
|
for (i=0; i<=Sp; i++) vn[i] = vs[i];
|
|
Sz += k;
|
|
Rts = n;
|
|
}
|
|
}
|
|
|
|
void push(cell x) {
|
|
Tmp = x;
|
|
stkalloc(1);
|
|
Tmp = NIL;
|
|
Sp++;
|
|
stackset(Sp, x);
|
|
}
|
|
|
|
cell pop(void) {
|
|
if (Sp < 0) error("oops: stack underflow", UNDEF);
|
|
Sp--;
|
|
return stackref(Sp+1);
|
|
}
|
|
|
|
cell closure(cell i, cell e) {
|
|
cell c;
|
|
|
|
c = cons(Prog, NIL);
|
|
c = cons(e, c);
|
|
protect(c);
|
|
c = cons(mkfix(i), c);
|
|
unprot(1);
|
|
return mkatom(T_CLOSURE, c);
|
|
}
|
|
|
|
#define closure_ip(c) cadr(c)
|
|
#define closure_env(c) caddr(c)
|
|
#define closure_prog(c) cadddr(c)
|
|
|
|
int apply(int tail) {
|
|
int n, m, pn, pm, i;
|
|
cell k, e;
|
|
|
|
if (!closurep(Acc))
|
|
error("application of non-function", Acc);
|
|
if (tail) {
|
|
Ep = closure_env(Acc);
|
|
Prog = closure_prog(Acc);
|
|
m = fixval(stackref(Sp));
|
|
n = fixval(stackref(Sp-m-4));
|
|
pm = Sp-m;
|
|
pn = Sp-m-n-4;
|
|
if (n == m) {
|
|
for (i=0; i<=m; i++)
|
|
stackset(pn+i, stackref(pm+i));
|
|
Fp = fixval(stackref(Sp-m-1));
|
|
Sp -= n+2;
|
|
}
|
|
else {
|
|
e = stackref(Sp-m-3);
|
|
k = stackref(Sp-m-2);
|
|
Fp = fixval(stackref(Sp-m-1));
|
|
for (i=0; i<=m; i++)
|
|
stackset(pn+i, stackref(pm+i));
|
|
Sp -= n+2;
|
|
stackset(Sp-1, e);
|
|
stackset(Sp, k);
|
|
}
|
|
}
|
|
else {
|
|
push(Ep);
|
|
push(cons(mkfix(Ip+1), Prog));
|
|
Ep = closure_env(Acc);
|
|
Prog = closure_prog(Acc);
|
|
}
|
|
return fixval(closure_ip(Acc));
|
|
}
|
|
|
|
int conses(cell n) {
|
|
int k;
|
|
|
|
for (k = 0; pairp(n); n = cdr(n))
|
|
k++;
|
|
return k;
|
|
}
|
|
|
|
int applis(int tail) {
|
|
cell a, p, new;
|
|
int k, i;
|
|
|
|
a = boxref(stackref(Sp));
|
|
if (!pairp(a) && a != NIL) error("apply: expected list", a);
|
|
k = conses(a);
|
|
stkalloc(k);
|
|
Sp += k;
|
|
i = Sp-1;
|
|
for (p = a; p != NIL; p = cdr(p)) {
|
|
if (atomp(p)) error("apply: dotted list", a);
|
|
new = box(car(p));
|
|
stackset(i, new);
|
|
i--;
|
|
}
|
|
new = mkfix(k);
|
|
stackset(Sp, new);
|
|
return apply(tail);
|
|
}
|
|
|
|
int ret(void) {
|
|
int r, n;
|
|
cell *v;
|
|
|
|
v = vector(Rts);
|
|
Fp = fixval(v[Sp]);
|
|
r = v[Sp-1];
|
|
Prog = cdr(r);
|
|
Ep = v[Sp-2];
|
|
n = fixval(v[Sp-3]);
|
|
Sp -= n+4;
|
|
return fixval(car(r));
|
|
}
|
|
|
|
void entcol(int fix) {
|
|
int n, na, i, s, d;
|
|
cell a, x, new;
|
|
|
|
na = fixval(stackref(Sp-2));
|
|
if (na < fix)
|
|
error("too few arguments", UNDEF);
|
|
protect(a = NIL);
|
|
i = Sp-fix-3;
|
|
for (n = na-fix; n; n--) {
|
|
x = cons(boxref(stackref(i)), NIL);
|
|
if (NIL == a) {
|
|
a = x;
|
|
car(Protected) = a;
|
|
}
|
|
else {
|
|
cdr(a) = x;
|
|
a = cdr(a);
|
|
}
|
|
i--;
|
|
}
|
|
a = unprot(1);
|
|
if (na > fix) {
|
|
new = box(a);
|
|
stackset(Sp-fix-3, new);
|
|
}
|
|
else {
|
|
push(NIL);
|
|
s = Sp - na - 3;
|
|
d = Sp - na - 2;
|
|
for (i = na + 2; i >= 0; i--)
|
|
stackset(d+i, stackref(s+i));
|
|
new = mkfix(1+fix);
|
|
stackset(Sp-2, new);
|
|
new = box(NIL);
|
|
stackset(Sp-fix-3, new);
|
|
}
|
|
push(mkfix(Fp));
|
|
Fp = Sp-4;
|
|
}
|
|
|
|
cell mkctag(void) {
|
|
cell n;
|
|
|
|
n = cons(Ep, Prog);
|
|
Tmp = n; n = cons(mkfix(Fp), n);
|
|
Tmp = n; n = cons(mkfix(Sp), n);
|
|
Tmp = n; n = cons(mkfix(Ip+2), n);
|
|
Tmp = NIL;
|
|
return mkatom(T_CATCHTAG, n);
|
|
}
|
|
|
|
int throw(cell ct, cell v) {
|
|
if (!ctagp(ct)) expect("throw", "catch tag", ct);
|
|
ct = cdr(ct);
|
|
Ip = fixval(car(ct)); ct = cdr(ct);
|
|
Sp = fixval(car(ct)); ct = cdr(ct);
|
|
Fp = fixval(car(ct)); ct = cdr(ct);
|
|
Ep = car(ct); ct = cdr(ct);
|
|
Prog = ct;
|
|
Acc = v;
|
|
return Ip;
|
|
}
|
|
|
|
int throwerr(cell ct) {
|
|
cell n;
|
|
|
|
n = assq(S_errval, Glob);
|
|
n = NIL == n? NIL: cadr(n);
|
|
return throw(ct, n);
|
|
}
|
|
|
|
volatile int Run = 0;
|
|
cell Argv;
|
|
|
|
void run(cell x) {
|
|
Acc = NIL;
|
|
Prog = x;
|
|
Ip = 0;
|
|
if (setjmp(Errtag) != 0)
|
|
Ip = throwerr(Handler);
|
|
for (Run=1; Run;) {
|
|
switch (ins()) {
|
|
case OP_APPLIS:
|
|
Ip = applis(0);
|
|
break;
|
|
case OP_APPLIST:
|
|
Ip = applis(1);
|
|
break;
|
|
case OP_TAILAPP:
|
|
Ip = apply(1);
|
|
break;
|
|
case OP_APPLY:
|
|
Ip = apply(0);
|
|
break;
|
|
case OP_QUOTE:
|
|
Acc = vector(Obarray)[op1()];
|
|
skip(ISIZE1);
|
|
break;
|
|
case OP_ARG:
|
|
Acc = argref(op1());
|
|
skip(ISIZE1);
|
|
break;
|
|
case OP_REF:
|
|
Acc = boxref(envbox(op1()));
|
|
if (UNDEF == Acc)
|
|
error("undefined symbol", vector(Symbols)[op2()]);
|
|
if (Tp >= NTRACE) Tp = 0;
|
|
Trace[Tp++] = op2();
|
|
skip(ISIZE2);
|
|
break;
|
|
case OP_DROP:
|
|
Sp--;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_POP:
|
|
Acc = stackref(Sp);
|
|
Sp--;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_PUSH:
|
|
push(cons(Acc, NIL));
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_PUSHTRUE:
|
|
push(TRUE);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_PUSHVAL:
|
|
push(mkfix(op1()));
|
|
skip(ISIZE1);
|
|
break;
|
|
case OP_JMP:
|
|
Ip = op1();
|
|
break;
|
|
case OP_BRF:
|
|
if (NIL == Acc)
|
|
Ip = op1();
|
|
else
|
|
skip(ISIZE1);
|
|
break;
|
|
case OP_BRT:
|
|
if (NIL == Acc)
|
|
skip(ISIZE1);
|
|
else
|
|
Ip = op1();
|
|
break;
|
|
case OP_HALT:
|
|
return;
|
|
case OP_CATCHSTAR:
|
|
push(box(mkctag()));
|
|
push(mkfix(1));
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_THROWSTAR:
|
|
Ip = throw(Acc, arg(0));
|
|
break;
|
|
case OP_MKENV:
|
|
Acc = mkvec(op1());
|
|
skip(ISIZE1);
|
|
break;
|
|
case OP_PROPENV:
|
|
Acc = Ep;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CPARG:
|
|
vector(Acc)[op2()] = argbox(op1());
|
|
skip(ISIZE2);
|
|
break;
|
|
case OP_CPREF:
|
|
vector(Acc)[op2()] = envbox(op1());
|
|
skip(ISIZE2);
|
|
break;
|
|
case OP_CLOSURE:
|
|
Acc = closure(op1(), Acc);
|
|
skip(ISIZE1);
|
|
break;
|
|
case OP_ENTER:
|
|
if (fixval(stackref(Sp-2)) != op1())
|
|
error("wrong number of arguments", UNDEF);
|
|
push(mkfix(Fp));
|
|
Fp = Sp-4;
|
|
skip(ISIZE1);
|
|
break;
|
|
case OP_ENTCOL:
|
|
entcol(op1());
|
|
skip(ISIZE1);
|
|
break;
|
|
case OP_RETURN:
|
|
Ip = ret();
|
|
break;
|
|
case OP_SETARG:
|
|
boxset(argbox(op1()), Acc);
|
|
skip(ISIZE1);
|
|
break;
|
|
case OP_SETREF:
|
|
boxset(envbox(op1()), Acc);
|
|
skip(ISIZE1);
|
|
break;
|
|
case OP_MACRO:
|
|
newmacro(op1(), Acc);
|
|
skip(ISIZE1);
|
|
break;
|
|
case OP_CMDLINE:
|
|
Acc = Argv;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_QUIT:
|
|
bye(0);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_OBTAB:
|
|
Acc = Obarray;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SYMTAB:
|
|
Acc = Symbols;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_ERROR:
|
|
if (!stringp(Acc)) expect("error", "string", Acc);
|
|
error((char *) string(Acc), UNDEF);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_ERROR2:
|
|
if (!stringp(Acc)) expect("error", "string", Acc);
|
|
error((char *) string(Acc), arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_ERRPORT:
|
|
Acc = mkport(Errport, T_OUTPORT);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_INPORT:
|
|
Acc = mkport(Inport, T_INPORT);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_OUTPORT:
|
|
Acc = mkport(Outport, T_OUTPORT);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_GC:
|
|
Acc = b_gc();
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_GENSYM:
|
|
Acc = gensym();
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_ABS:
|
|
if (!fixp(Acc)) expect("abs", "fixnum", Acc);
|
|
if (INT_MIN == fixval(Acc))
|
|
error("abs: fixnum overflow", Acc);
|
|
if (fixval(Acc) < 0) Acc = mkfix(-fixval(Acc));
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_ALPHAC:
|
|
if (!charp(Acc)) expect("alphac", "char", Acc);
|
|
Acc = isalpha(charval(Acc))? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_ATOM:
|
|
Acc = pairp(Acc)? NIL: TRUE;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CAR:
|
|
if (!pairp(Acc)) expect("car", "pair", Acc);
|
|
Acc = car(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CDR:
|
|
if (!pairp(Acc)) expect("cdr", "pair", Acc);
|
|
Acc = cdr(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CAAR:
|
|
if (!pairp(Acc) || !pairp(car(Acc)))
|
|
expect("caar", "nested pair", Acc);
|
|
Acc = caar(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CADR:
|
|
if (!pairp(Acc) || !pairp(cdr(Acc)))
|
|
expect("cadr", "nested pair", Acc);
|
|
Acc = cadr(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CDAR:
|
|
if (!pairp(Acc) || !pairp(car(Acc)))
|
|
expect("cdar", "nested pair", Acc);
|
|
Acc = cdar(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CDDR:
|
|
if (!pairp(Acc) || !pairp(cdr(Acc)))
|
|
expect("cddr", "nested pair", Acc);
|
|
Acc = cddr(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CHAR:
|
|
if (!fixp(Acc)) expect("char", "fixnum", Acc);
|
|
if (fixval(Acc) < 0 || fixval(Acc) > 255)
|
|
error("char: value out of range", Acc);
|
|
Acc = mkchar(fixval(Acc));
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CHARP:
|
|
Acc = charp(Acc)? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CHARVAL:
|
|
if (!charp(Acc)) expect("charval", "char", Acc);
|
|
Acc = mkfix(charval(Acc));
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CLOSE_PORT:
|
|
if (!inportp(Acc) && !outportp(Acc))
|
|
expect("close-port", "port", Acc);
|
|
close_port(portno(Acc));
|
|
Acc = NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CONSTP:
|
|
Acc = constp(Acc)? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CTAGP:
|
|
Acc = ctagp(Acc)? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_DELETE:
|
|
if (!stringp(Acc)) expect("delete", "string", Acc);
|
|
if (remove((char *) string(Acc)) < 0)
|
|
error("delete: cannot delete", Acc);
|
|
Acc = NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_DOWNCASE:
|
|
if (!charp(Acc)) expect("downcase", "char", Acc);
|
|
Acc = mkchar(tolower(charval(Acc)));
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_DUMP_IMAGE:
|
|
if (!stringp(Acc)) expect("dump-image", "string", Acc);
|
|
dump_image(Acc);
|
|
Acc = TRUE;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_EOFP:
|
|
Acc = (EOFMARK == Acc? TRUE: NIL);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_EVAL:
|
|
Acc = eval(Acc, 1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_EXISTSP:
|
|
if (!stringp(Acc)) expect("existsp", "string", Acc);
|
|
Acc = existsp((char *) string(Acc));
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_FIXP:
|
|
Acc = fixp(Acc)? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_FLUSH:
|
|
if (!outportp(Acc)) expect("flush", "outport", Acc);
|
|
fflush(Ports[portno(Acc)]);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_FORMAT:
|
|
Acc = format(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_FUNP:
|
|
Acc = closurep(Acc)? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_INPORTP:
|
|
Acc = inportp(Acc)? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_LISTSTR:
|
|
if (!listp(Acc)) expect("liststr", "list", Acc);
|
|
Acc = liststr(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_LISTVEC:
|
|
if (!listp(Acc)) expect("listvec", "list", Acc);
|
|
Acc = listvec(Acc, 0);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_LOAD:
|
|
load(Acc);
|
|
Acc = TRUE;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_LOWERC:
|
|
if (!charp(Acc)) expect("lowerc", "char", Acc);
|
|
Acc = islower(charval(Acc))? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_MX:
|
|
Acc = expand(Acc, 1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_MX1:
|
|
Acc = expand(Acc, 0);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_NEGATE:
|
|
if (!fixp(Acc)) expect("-", "fixnum", Acc);
|
|
if (INT_MIN == fixval(Acc))
|
|
error("-: fixnum overflow", Acc);
|
|
Acc = mkfix(-fixval(Acc));
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_NULL:
|
|
Acc = (NIL == Acc? TRUE: NIL);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_NUMSTR:
|
|
if (!fixp(Acc)) expect("numstr", "fixnum", Acc);
|
|
if (!fixp(arg(0))) expect("numstr", "fixnum", arg(0));
|
|
Acc = numstr(Acc, fixval(arg(0)));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_NUMERIC:
|
|
if (!charp(Acc)) expect("numeric", "char", Acc);
|
|
Acc = isdigit(charval(Acc))? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_OPEN_INFILE:
|
|
if (!stringp(Acc)) expect("open-infile", "string", Acc);
|
|
Acc = openfile(Acc, 0);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_OPEN_OUTFILE:
|
|
if (!stringp(Acc)) expect("open-outfile", "string", Acc);
|
|
Acc = openfile(Acc, NIL == arg(0)? 1: 2);
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_OUTPORTP:
|
|
Acc = outportp(Acc)? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_PAIR:
|
|
Acc = pairp(Acc)? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_PEEKC:
|
|
if (!inportp(Acc)) expect("peekc", "inport", Acc);
|
|
Acc = b_readc(portno(Acc), 1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_READ:
|
|
if (!inportp(Acc) && !stringp(Acc))
|
|
expect("read", "inport", Acc);
|
|
Acc = b_read(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_READC:
|
|
if (!inportp(Acc)) expect("readc", "inport", Acc);
|
|
Acc = b_readc(portno(Acc), 0);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CONC:
|
|
Acc = lconc(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_NCONC:
|
|
Acc = nlconc(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SCONC:
|
|
Acc = sconc(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SET_INPORT:
|
|
if (!inportp(Acc)) expect("set-inport", "inport", Acc);
|
|
Inport = portno(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SET_OUTPORT:
|
|
if (!outportp(Acc)) expect("set-outport", "outport", Acc);
|
|
Outport = portno(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SSIZE:
|
|
if (!stringp(Acc)) expect("ssize", "string", Acc);
|
|
Acc = mkfix(stringlen(Acc)-1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_STRNUM:
|
|
if (!stringp(Acc)) expect("strnum", "string", Acc);
|
|
if (!fixp(arg(0))) expect("strnum", "fixnum", arg(0));
|
|
Acc = strnum((char *) string(Acc), fixval(arg(0)));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SYMBOLP:
|
|
Acc = symbolp(Acc)? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SYMBOL:
|
|
if (!stringp(Acc)) expect("symbol", "string", Acc);
|
|
Acc = b_symbol(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SYMNAME:
|
|
if (!symbolp(Acc)) expect("symname", "symbol", Acc);
|
|
Acc = b_symname(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_STRINGP:
|
|
Acc = stringp(Acc)? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_STRLIST:
|
|
if (!stringp(Acc)) expect("strlist", "string", Acc);
|
|
Acc = strlist(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SYSCMD:
|
|
if (!stringp(Acc)) expect("syscmd", "string", Acc);
|
|
#ifdef unix
|
|
Acc = mkfix(system((char *) string(Acc)) >> 8);
|
|
#endif
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_UNTAG:
|
|
Acc = untag(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_UPCASE:
|
|
if (!charp(Acc)) expect("upcase", "char", Acc);
|
|
Acc = mkchar(toupper(charval(Acc)));
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_UPPERC:
|
|
if (!charp(Acc)) expect("upperc", "char", Acc);
|
|
Acc = isupper(charval(Acc))? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_VCONC:
|
|
Acc = vconc(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_VECLIST:
|
|
if (!vectorp(Acc)) expect("veclist", "vector", Acc);
|
|
Acc = veclist(Acc);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_VECTORP:
|
|
Acc = vectorp(Acc)? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_VSIZE:
|
|
if (!vectorp(Acc)) expect("vsize", "vector", Acc);
|
|
Acc = mkfix(veclen(Acc));
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_WHITEC:
|
|
if (!charp(Acc)) expect("whitec", "char", Acc);
|
|
Acc = whitespc(charval(Acc))? TRUE: NIL;
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_BITOP:
|
|
Acc = bitop(Acc, arg(0), arg(1));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CLESS:
|
|
cless(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CLTEQ:
|
|
clteq(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CEQUAL:
|
|
cequal(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CGRTR:
|
|
cgrtr(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CGTEQ:
|
|
cgteq(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_CONS:
|
|
Acc = cons(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_DIV:
|
|
Acc = intdiv(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_EQ:
|
|
Acc = (Acc == arg(0))? TRUE: NIL;
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_EQUAL:
|
|
equal(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_GRTR:
|
|
grtr(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_GTEQ:
|
|
gteq(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_LESS:
|
|
less(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_LTEQ:
|
|
lteq(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_MAX:
|
|
if (fixval(arg(0)) > fixval(Acc)) Acc = arg(0);
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_MIN:
|
|
if (fixval(arg(0)) < fixval(Acc)) Acc = arg(0);
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_MINUS:
|
|
Acc = xsub(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_MKSTR:
|
|
Acc = b_mkstr(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_MKVEC:
|
|
Acc = b_mkvec(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_NRECONC:
|
|
if (!listp(Acc)) expect("nreconc", "list", Acc);
|
|
if (constp(Acc)) error("nreconc: immutable", Acc);
|
|
Acc = nreconc(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_PLUS:
|
|
Acc = add(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_PRIN:
|
|
if (!outportp(arg(0))) expect("prin", "outport", arg(0));
|
|
b_prin(Acc, portno(arg(0)), 1);
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_PRINC:
|
|
if (!outportp(arg(0))) expect("princ", "outport", arg(0));
|
|
b_prin(Acc, portno(arg(0)), 0);
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_RECONC:
|
|
if (!listp(Acc)) expect("reconc", "list", Acc);
|
|
Acc = reconc(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_REM:
|
|
Acc = intrem(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_RENAME:
|
|
b_rename(Acc, arg(0));
|
|
Acc = NIL;
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SETCAR:
|
|
if (!pairp(Acc)) expect("setcar", "pair", Acc);
|
|
if (constp(Acc)) error("setcar: immutable", Acc);
|
|
car(Acc) = arg(0);
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SETCDR:
|
|
if (!pairp(Acc)) expect("setcdr", "pair", Acc);
|
|
if (constp(Acc)) error("setcdr: immutable", Acc);
|
|
cdr(Acc) = arg(0);
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SLESS:
|
|
Acc = sless(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SLTEQ:
|
|
Acc = slteq(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SEQUAL:
|
|
Acc = sequal(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SGRTR:
|
|
Acc = sgrtr(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SGTEQ:
|
|
Acc = sgteq(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SILESS:
|
|
Acc = siless(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SILTEQ:
|
|
Acc = silteq(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SIEQUAL:
|
|
Acc = siequal(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SIGRTR:
|
|
Acc = sigrtr(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SIGTEQ:
|
|
Acc = sigteq(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SFILL:
|
|
sfill(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SREF:
|
|
Acc = sref(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SSET:
|
|
sset(Acc, arg(0), arg(1));
|
|
clear(2);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SUBSTR:
|
|
Acc = substr(Acc, arg(0), arg(1));
|
|
clear(2);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_SUBVEC:
|
|
Acc = subvec(Acc, arg(0), arg(1));
|
|
clear(2);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_TIMES:
|
|
Acc = mul(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_VFILL:
|
|
vfill(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_VREF:
|
|
Acc = vref(Acc, arg(0));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_VSET:
|
|
vset(Acc, arg(0), arg(1));
|
|
clear(2);
|
|
skip(ISIZE0);
|
|
break;
|
|
case OP_WRITEC:
|
|
if (!charp(Acc)) expect("writec", "char", Acc);
|
|
if (!outportp(arg(0))) expect("writec", "outport", arg(0));
|
|
b_writec(charval(Acc), portno(arg(0)));
|
|
clear(1);
|
|
skip(ISIZE0);
|
|
break;
|
|
default:
|
|
error("illegal instruction", mkfix(ins()));
|
|
return;
|
|
} }
|
|
error("interrupted", UNDEF);
|
|
}
|
|
|
|
cell interpret(cell x) {
|
|
cell n;
|
|
int i;
|
|
|
|
E0 = mkvec(length(Glob));
|
|
i = 0;
|
|
for (n = Glob; n != NIL; n = cdr(n)) {
|
|
vector(E0)[i] = cdar(n);
|
|
i++;
|
|
}
|
|
Ep = E0;
|
|
run(x);
|
|
return Acc;
|
|
}
|
|
|
|
void begin_rec(void) {
|
|
protect(Prog);
|
|
protect(Ep);
|
|
protect(mkfix(Ip));
|
|
protect(mkfix(Sp));
|
|
protect(mkfix(Fp));
|
|
}
|
|
|
|
void end_rec(void) {
|
|
Fp = fixval(unprot(1));
|
|
Sp = fixval(unprot(1));
|
|
Ip = fixval(unprot(1));
|
|
Ep = unprot(1);
|
|
Prog = unprot(1);
|
|
}
|
|
|
|
cell eval(cell x, int r) {
|
|
Tmp = x;
|
|
if (r) begin_rec();
|
|
protect(x);
|
|
Tmp = NIL;
|
|
x = expand(x, 1); car(Protected) = x;
|
|
syncheck(x, 1);
|
|
x = clsconv(x); car(Protected) = x;
|
|
x = compile(x); car(Protected) = x;
|
|
x = interpret(x);
|
|
unprot(1);
|
|
if (r) end_rec();
|
|
return x;
|
|
}
|
|
|
|
/*
|
|
* REPL
|
|
*/
|
|
|
|
volatile int Intr = 0;
|
|
|
|
void kbdintr(int sig) {
|
|
Run = 0;
|
|
Intr = 1;
|
|
Mxlev = -1;
|
|
}
|
|
|
|
int Quiet = 0;
|
|
int Bootstrap = 0;
|
|
|
|
void initrts(void) {
|
|
Rts = NIL;
|
|
Rts = mkvec(CHUNKSIZE);
|
|
Sz = CHUNKSIZE;
|
|
Sp = -1;
|
|
Fp = -1;
|
|
}
|
|
|
|
void repl(void) {
|
|
cell x;
|
|
|
|
if (setjmp(Restart) && Quiet)
|
|
bye(1);
|
|
if (!Quiet) signal(SIGINT, kbdintr);
|
|
for (;;) {
|
|
reset_stdports();
|
|
clrtrace();
|
|
initrts();
|
|
bindset(S_errtag, NIL);
|
|
Protected = NIL;
|
|
Run = 0;
|
|
Intr = 0;
|
|
if (!Quiet) {
|
|
prints("boot> ");
|
|
flush();
|
|
}
|
|
x = xread();
|
|
if (EOFMARK == x && !Intr) break;
|
|
Mxlev = 0;
|
|
x = eval(x, 0);
|
|
bindset(S_starstar, x);
|
|
print1(x);
|
|
}
|
|
if (!Quiet) nl();
|
|
}
|
|
|
|
/*
|
|
* Startup and initialization
|
|
*/
|
|
|
|
void init(void) {
|
|
int i;
|
|
|
|
for (i=2; i<NPORTS; i++) Ports[i] = NULL;
|
|
Ports[0] = stdin; Port_flags[0] = LOCK_TAG;
|
|
Ports[1] = stdout; Port_flags[1] = LOCK_TAG;
|
|
Ports[2] = stderr; Port_flags[2] = LOCK_TAG;
|
|
alloc_nodepool();
|
|
alloc_vecpool();
|
|
gcv();
|
|
initrts();
|
|
clrtrace();
|
|
Nullvec = newvec(T_VECTOR, 0);
|
|
Nullstr = newvec(T_STRING, 1);
|
|
Blank = mkchar(' ');
|
|
Zero = mkfix(0);
|
|
One = mkfix(1);
|
|
Ten = mkfix(10);
|
|
Symbols = mkvec(CHUNKSIZE);
|
|
Symhash = mkht(CHUNKSIZE);
|
|
Obhash = mkht(CHUNKSIZE);
|
|
Obarray = mkvec(CHUNKSIZE);
|
|
Obmap = mkstr("", CHUNKSIZE);
|
|
memset(string(Obmap), OBFREE, CHUNKSIZE);
|
|
symref("?");
|
|
I_a = symref("a");
|
|
I_e = symref("e");
|
|
I_arg = symref("%arg");
|
|
I_closure = symref("%closure");
|
|
I_ref = symref("%ref");
|
|
S_apply = symref("apply");
|
|
S_def = symref("def");
|
|
S_defmac = symref("defmac");
|
|
S_defun = symref("defun");
|
|
S_errtag = symref("*errtag*");
|
|
S_errval = symref("*errval*");
|
|
S_if = symref("if");
|
|
S_ifstar = symref("if*");
|
|
S_imagefile = symref("*imagefile*");
|
|
S_labels = symref("labels");
|
|
S_lambda = symref("lambda");
|
|
S_macro = symref("macro");
|
|
S_prog = symref("prog");
|
|
S_quiet = symref("*quiet*");
|
|
S_quote = symref("quote");
|
|
S_qquote = symref("qquote");
|
|
S_unquote = symref("unquote");
|
|
S_splice = symref("splice");
|
|
S_starstar = symref("**");
|
|
S_setq = symref("setq");
|
|
S_start = symref("start");
|
|
P_abs = symref("abs");
|
|
P_alphac = symref("alphac");
|
|
P_atom = symref("atom");
|
|
P_bitop = symref("bitop");
|
|
P_caar = symref("caar");
|
|
P_cadr = symref("cadr");
|
|
P_car = symref("car");
|
|
P_catchstar = symref("catch*");
|
|
P_cdar = symref("cdar");
|
|
P_cddr = symref("cddr");
|
|
P_cdr = symref("cdr");
|
|
P_cequal = symref("c=");
|
|
P_cgrtr = symref("c>");
|
|
P_cgteq = symref("c>=");
|
|
P_char = symref("char");
|
|
P_charp = symref("charp");
|
|
P_charval = symref("charval");
|
|
P_cless = symref("c<");
|
|
P_close_port = symref("close-port");
|
|
P_clteq = symref("c<=");
|
|
P_cmdline = symref("cmdline");
|
|
P_conc = symref("conc");
|
|
P_cons = symref("cons");
|
|
P_constp = symref("constp");
|
|
P_ctagp = symref("ctagp");
|
|
P_delete = symref("delete");
|
|
P_div = symref("div");
|
|
P_downcase = symref("downcase");
|
|
P_dump_image = symref("dump-image");
|
|
P_eofp = symref("eofp");
|
|
P_eq = symref("eq");
|
|
P_equal = symref("=");
|
|
P_error = symref("error");
|
|
P_errport = symref("errport");
|
|
P_eval = symref("eval");
|
|
P_existsp = symref("existsp");
|
|
P_fixp = symref("fixp");
|
|
P_flush = symref("flush");
|
|
P_format = symref("format");
|
|
P_funp = symref("funp");
|
|
P_gc = symref("gc");
|
|
P_gensym = symref("gensym");
|
|
P_grtr = symref(">");
|
|
P_gteq = symref(">=");
|
|
P_inport = symref("inport");
|
|
P_inportp = symref("inportp");
|
|
P_less = symref("<");
|
|
P_liststr = symref("liststr");
|
|
P_listvec = symref("listvec");
|
|
P_load = symref("load");
|
|
P_lowerc = symref("lowerc");
|
|
P_lteq = symref("<=");
|
|
P_max = symref("max");
|
|
P_min = symref("min");
|
|
P_minus = symref("-");
|
|
P_mkstr = symref("mkstr");
|
|
P_mkvec = symref("mkvec");
|
|
P_mx = symref("mx");
|
|
P_mx1 = symref("mx1");
|
|
P_not = symref("not");
|
|
P_nconc = symref("nconc");
|
|
P_nreconc = symref("nreconc");
|
|
P_null = symref("null");
|
|
P_numeric = symref("numeric");
|
|
P_numstr = symref("numstr");
|
|
P_obtab = symref("obtab");
|
|
P_open_infile = symref("open-infile");
|
|
P_open_outfile = symref("open-outfile");
|
|
P_outport = symref("outport");
|
|
P_outportp = symref("outportp");
|
|
P_pair = symref("pair");
|
|
P_peekc = symref("peekc");
|
|
P_plus = symref("+");
|
|
P_prin = symref("prin");
|
|
P_princ = symref("princ");
|
|
P_quit = symref("quit");
|
|
P_read = symref("read");
|
|
P_readc = symref("readc");
|
|
P_reconc = symref("reconc");
|
|
P_rem = symref("rem");
|
|
P_rename = symref("rename");
|
|
P_sconc = symref("sconc");
|
|
P_sequal = symref("s=");
|
|
P_set_inport = symref("set-inport");
|
|
P_set_outport = symref("set-outport");
|
|
P_setcar = symref("setcar");
|
|
P_setcdr = symref("setcdr");
|
|
P_sfill = symref("sfill");
|
|
P_sgrtr = symref("s>");
|
|
P_sgteq = symref("s>=");
|
|
P_siequal = symref("si=");
|
|
P_sigrtr = symref("si>");
|
|
P_sigteq = symref("si>=");
|
|
P_siless = symref("si<");
|
|
P_silteq = symref("si<=");
|
|
P_sless = symref("s<");
|
|
P_slteq = symref("s<=");
|
|
P_sref = symref("sref");
|
|
P_sset = symref("sset");
|
|
P_ssize = symref("ssize");
|
|
P_stringp = symref("stringp");
|
|
P_strlist = symref("strlist");
|
|
P_strnum = symref("strnum");
|
|
P_substr = symref("substr");
|
|
P_subvec = symref("subvec");
|
|
P_symbol = symref("symbol");
|
|
P_symbolp = symref("symbolp");
|
|
P_symname = symref("symname");
|
|
P_symtab = symref("symtab");
|
|
P_syscmd = symref("syscmd");
|
|
P_throwstar = symref("throw*");
|
|
P_times = symref("*");
|
|
P_untag = symref("untag");
|
|
P_upcase = symref("upcase");
|
|
P_upperc = symref("upperc");
|
|
P_vconc = symref("vconc");
|
|
P_veclist = symref("veclist");
|
|
P_vectorp = symref("vectorp");
|
|
P_vfill = symref("vfill");
|
|
P_vref = symref("vref");
|
|
P_vset = symref("vset");
|
|
P_vsize = symref("vsize");
|
|
P_whitec = symref("whitec");
|
|
P_writec = symref("writec");
|
|
bindnew(S_errtag, NIL);
|
|
bindnew(S_errval, NIL);
|
|
bindnew(S_imagefile, NIL);
|
|
bindnew(S_quiet, NIL);
|
|
bindnew(S_starstar, NIL);
|
|
bindnew(S_start, NIL);
|
|
}
|
|
|
|
void start(void) {
|
|
cell n;
|
|
|
|
if (setjmp(Restart)) return;
|
|
if (!Quiet) signal(SIGINT, kbdintr);
|
|
n = assq(S_start, Glob);
|
|
if (NIL == n || closurep(cadr(n)) == 0) return;
|
|
n = cons(cadr(n), NIL);
|
|
eval(n, 0);
|
|
}
|
|
|
|
cell *Imagevars[] = {
|
|
&Freelist, &Freevec, &Symbols, &Symhash, &Symptr,
|
|
&Rts, &Glob, &Macros, &Obhash, &Obarray, &Obmap, NULL };
|
|
|
|
cell *GC_roots[] = {
|
|
&Protected, &Symbols, &Symhash, &Prog, &Env, &Obhash,
|
|
&Obarray, &Obmap, &Cts, &Emitbuf, &Glob, &Macros, &Rts,
|
|
&Acc, &E0, &Ep, &Argv, &Tmp, &Tmp_car, &Tmp_cdr, &Files,
|
|
&Outstr, &Nullvec, &Nullstr, &Blank, &Zero, &One, &Ten,
|
|
NULL };
|
|
|
|
/*
|
|
* Command line interface
|
|
*/
|
|
|
|
void usage(void) {
|
|
prints("Usage: ls9 [-i file | -] [-l file]\n");
|
|
prints(" [-- argument ... | file argument ...]\n");
|
|
}
|
|
|
|
|
|
char *cmdarg(char *s) {
|
|
if (NULL == s) {
|
|
usage();
|
|
bye(1);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
cell Argv = NIL;
|
|
|
|
cell argvec(char **argv) {
|
|
int i;
|
|
cell a, n;
|
|
|
|
if (NULL == argv[0]) return NIL;
|
|
a = cons(NIL, NIL);
|
|
protect(a);
|
|
for (i = 0; argv[i] != NULL; i++) {
|
|
n = mkstr(argv[i], strlen(argv[i]));
|
|
car(a) = n;
|
|
if (argv[i+1] != NULL) {
|
|
n = cons(NIL, NIL);
|
|
cdr(a) = n;
|
|
a = cdr(a);
|
|
}
|
|
}
|
|
return unprot(1);
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
int i, j, k, usrimg, doload;
|
|
char *s;
|
|
char *imgfile;
|
|
|
|
imgfile = IMAGEFILE;
|
|
usrimg = 0;
|
|
doload = 1;
|
|
if (setjmp(Restart) != 0) bye(1);
|
|
init();
|
|
i = 1;
|
|
if (argc > 2 && strcmp(argv[1], "-i") == 0) {
|
|
imgfile = argv[2];
|
|
i = 3;
|
|
usrimg = 1;
|
|
}
|
|
if (existsp(imgfile) != NIL) {
|
|
s = loadimg(imgfile);
|
|
if (s != NULL) fatal(s);
|
|
bindset(S_imagefile,
|
|
mkstr(imgfile, strlen(imgfile)));
|
|
}
|
|
else if (usrimg && strcmp(imgfile, "-") != 0) {
|
|
fatal("cannot open image file");
|
|
}
|
|
else {
|
|
if (setjmp(Restart) != 0)
|
|
fatal("could not load library");
|
|
loadfile(IMAGESRC);
|
|
}
|
|
if (setjmp(Restart) != 0) bye(1);
|
|
for (; i<argc; i++) {
|
|
if (argv[i][0] != '-') break;
|
|
if ('-' == argv[i][1]) {
|
|
doload = 0;
|
|
break;
|
|
}
|
|
k = strlen(argv[i]);
|
|
for (j=1; j<k; j++) {
|
|
switch (argv[i][j]) {
|
|
case 'l':
|
|
i++;
|
|
loadfile(cmdarg(argv[i]));
|
|
j = strlen(argv[i]);
|
|
break;
|
|
case 'b':
|
|
Bootstrap++;
|
|
break;
|
|
case 'q':
|
|
Quiet = 1;
|
|
break;
|
|
default:
|
|
usage();
|
|
bye(1);
|
|
}
|
|
}
|
|
}
|
|
bindset(S_quiet, Quiet? TRUE: NIL);
|
|
Argv = NULL == argv[i]? NIL: argvec(&argv[i+1]);
|
|
start();
|
|
if (setjmp(Restart) != 0) bye(1);
|
|
if (doload && argv[i] != NULL) {
|
|
loadfile(argv[i]);
|
|
bye(0);
|
|
}
|
|
if (Bootstrap) repl(); /* REPL for bootstrapping the userspace */
|
|
return 0;
|
|
}
|