Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
1128 lines (1021 sloc) 22.9 KB
/* 31jan13abu
* (c) Software Lab. Alexander Burger
*/
#include "pico.h"
static any read0(bool);
static int StrI;
static cell StrCell, *StrP;
static word StrW;
static void (*PutSave)(int);
static char Delim[] = " \t\n\r\"'(),[]`~{}";
static void openErr(any ex, char *s) {err(ex, NULL, "%s open: %s", s, strerror(errno));}
static void eofErr(void) {err(NULL, NULL, "EOF Overrun");}
/* Buffer size */
int bufSize(any x) {return symBytes(x) + 1;}
int pathSize(any x) {
int c = firstByte(x);
if (c != '@' && (c != '+' || secondByte(x) != '@'))
return bufSize(x);
if (!Home)
return symBytes(x);
return strlen(Home) + symBytes(x);
}
void bufString(any x, char *p) {
int c, i;
word w;
if (!isNil(x)) {
for (x = name(x), c = getByte1(&i, &w, &x); c; c = getByte(&i, &w, &x)) {
if (c == '^') {
if ((c = getByte(&i, &w, &x)) == '?')
c = 127;
else
c &= 0x1F;
}
*p++ = c;
}
}
*p = '\0';
}
void pathString(any x, char *p) {
int c, i;
word w;
char *h;
x = name(x);
if ((c = getByte1(&i, &w, &x)) == '+')
*p++ = c, c = getByte(&i, &w, &x);
if (c != '@')
while (*p++ = c)
c = getByte(&i, &w, &x);
else {
if (h = Home)
do
*p++ = *h++;
while (*h);
while (*p++ = getByte(&i, &w, &x));
}
}
// (path 'any) -> sym
any doPath(any x) {
x = evSym(cdr(x));
{
char nm[pathSize(x)];
pathString(x,nm);
return mkStr(nm);
}
}
void rdOpen(any ex, any x, inFrame *f) {
NeedSymb(ex,x);
if (isNil(x))
f->fp = stdin;
else {
char nm[pathSize(x)];
pathString(x,nm);
if (nm[0] == '+') {
if (!(f->fp = fopen(nm+1, "a+")))
openErr(ex, nm);
fseek(f->fp, 0L, SEEK_SET);
}
else if (!(f->fp = fopen(nm, "r")))
openErr(ex, nm);
}
}
void wrOpen(any ex, any x, outFrame *f) {
NeedSymb(ex,x);
if (isNil(x))
f->fp = stdout;
else {
char nm[pathSize(x)];
pathString(x,nm);
if (nm[0] == '+') {
if (!(f->fp = fopen(nm+1, "a")))
openErr(ex, nm);
}
else if (!(f->fp = fopen(nm, "w")))
openErr(ex, nm);
}
}
/*** Reading ***/
void getStdin(void) {Chr = getc(InFile);}
static void getParse(void) {
if ((Chr = getByte(&Env.parser->i, &Env.parser->w, &Env.parser->nm)) == 0)
Chr = ']';
}
void pushInFiles(inFrame *f) {
f->next = Chr, Chr = 0;
InFile = f->fp;
f->get = Env.get, Env.get = getStdin;
f->link = Env.inFrames, Env.inFrames = f;
}
void pushOutFiles(outFrame *f) {
OutFile = f->fp;
f->put = Env.put, Env.put = putStdout;
f->link = Env.outFrames, Env.outFrames = f;
}
void popInFiles(void) {
if (InFile != stdin)
fclose(InFile);
Chr = Env.inFrames->next;
Env.get = Env.inFrames->get;
InFile = (Env.inFrames = Env.inFrames->link)? Env.inFrames->fp : stdin;
}
void popOutFiles(void) {
if (OutFile != stdout && OutFile != stderr)
fclose(OutFile);
Env.put = Env.outFrames->put;
OutFile = (Env.outFrames = Env.outFrames->link)? Env.outFrames->fp : stdout;
}
/* Skip White Space and Comments */
static int skip(int c) {
for (;;) {
if (Chr < 0)
return Chr;
while (Chr <= ' ') {
Env.get();
if (Chr < 0)
return Chr;
}
if (Chr != c)
return Chr;
Env.get();
if (c != '#' || Chr != '{') {
while (Chr != '\n') {
if (Chr < 0)
return Chr;
Env.get();
}
}
else {
for (;;) { // #{block-comment}# from Kriangkrai Soatthiyanont
Env.get();
if (Chr < 0)
return Chr;
if (Chr == '}' && (Env.get(), Chr == '#'))
break;
}
}
Env.get();
}
}
/* Test for escaped characters */
static bool testEsc(void) {
for (;;) {
if (Chr < 0)
return NO;
if (Chr != '\\')
return YES;
if (Env.get(), Chr != '\n')
return YES;
do
Env.get();
while (Chr == ' ' || Chr == '\t');
}
}
/* Read a list */
static any rdList(void) {
any x;
cell c1;
for (;;) {
if (skip('#') == ')') {
Env.get();
return Nil;
}
if (Chr == ']')
return Nil;
if (Chr != '~') {
Push(c1, x = cons(read0(NO),Nil));
break;
}
Env.get();
Push(c1, read0(NO));
if (isCell(x = data(c1) = EVAL(data(c1)))) {
while (isCell(cdr(x)))
x = cdr(x);
break;
}
drop(c1);
}
for (;;) {
if (skip('#') == ')') {
Env.get();
break;
}
if (Chr == ']')
break;
if (Chr == '.') {
Env.get();
cdr(x) = skip('#')==')' || Chr==']'? data(c1) : read0(NO);
if (skip('#') == ')')
Env.get();
else if (Chr != ']')
err(NULL, x, "Bad dotted pair");
break;
}
if (Chr != '~')
x = cdr(x) = cons(read0(NO),Nil);
else {
Env.get();
cdr(x) = read0(NO);
cdr(x) = EVAL(cdr(x));
while (isCell(cdr(x)))
x = cdr(x);
}
}
return Pop(c1);
}
/* Try for anonymous symbol */
static any anonymous(any s) {
int c, i;
word w;
unsigned long n;
heap *h;
if ((c = getByte1(&i, &w, &s)) != '$')
return NULL;
n = 0;
while (c = getByte(&i, &w, &s)) {
if (c < '0' || c > '9')
return NULL;
n = n * 10 + c - '0';
}
n *= sizeof(cell);
h = Heaps;
do
if ((any)n > h->cells && (any)n < h->cells + CELLS)
return symPtr((any)n);
while (h = h->next);
return NULL;
}
/* Relocate anonymous symbol */
static any reloc(any key) {
any x, y;
int n;
if (!isCell(x = Reloc)) {
Reloc = cons(cons(key, y = consSym(Nil,0)), Nil);
return y;
}
for (;;) {
if ((n = num(key) - num(caar(x))) == 0)
return cdar(x);
if (!isCell(cdr(x))) {
key = cons(cons(key, y = consSym(Nil,0)), Nil);
cdr(x) = n<0? cons(key,Nil) : cons(Nil,key);
return y;
}
if (n < 0) {
if (!isCell(cadr(x))) {
cadr(x) = cons(cons(key, y = consSym(Nil,0)), Nil);
return y;
}
x = cadr(x);
}
else {
if (!isCell(cddr(x))) {
cddr(x) = cons(cons(key, y = consSym(Nil,0)), Nil);
return y;
}
x = cddr(x);
}
}
}
/* Read one expression */
static any read0(bool top) {
int i;
word w;
any x, y;
cell c1, *p;
if (skip('#') < 0) {
if (top)
return Nil;
eofErr();
}
if (Chr == '(') {
Env.get();
x = rdList();
if (top && Chr == ']')
Env.get();
return x;
}
if (Chr == '[') {
Env.get();
x = rdList();
if (Chr != ']')
err(NULL, x, "Super parentheses mismatch");
Env.get();
return x;
}
if (Chr == '\'') {
Env.get();
return cons(Quote, read0(NO));
}
if (Chr == ',') {
Env.get();
return read0(NO);
}
if (Chr == '`') {
Env.get();
Push(c1, read0(NO));
x = EVAL(data(c1));
drop(c1);
return x;
}
if (Chr == '\\') {
Env.get();
Push(c1, read0(NO));
if (isNum(x = data(c1)))
x = reloc(x);
else if (isCell(x)) {
Transient[0] = Transient[1] = Nil;
if (isNum(x = car(y = x)))
x = car(y) = reloc(x);
if (isCell(y = cdr(y))) {
val(x) = car(y);
p = (any)&tail(x);
while (isCell(car(p)))
car(p) = caar(p);
while (isCell(y = cdr(y)))
car(p) = cons(car(p),car(y)), p = car(p);
}
}
drop(c1);
return x;
}
if (Chr == '"') {
Env.get();
if (Chr == '"') {
Env.get();
return Nil;
}
if (!testEsc())
eofErr();
putByte1(Chr, &i, &w, &p);
while (Env.get(), Chr != '"') {
if (!testEsc())
eofErr();
putByte(Chr, &i, &w, &p, &c1);
}
y = popSym(i, w, p, &c1), Env.get();
if (x = isIntern(tail(y), Transient))
return x;
intern(y, Transient);
return y;
}
if (strchr(Delim, Chr))
err(NULL, NULL, "Bad input '%c' (%d)", isprint(Chr)? Chr:'?', Chr);
if (Chr == '\\')
Env.get();
putByte1(Chr, &i, &w, &p);
for (;;) {
Env.get();
if (strchr(Delim, Chr))
break;
if (Chr == '\\')
Env.get();
putByte(Chr, &i, &w, &p, &c1);
}
y = popSym(i, w, p, &c1);
if (x = symToNum(tail(y), (int)unBox(val(Scl)), '.', 0))
return x;
if (x = anonymous(name(y)))
return x;
if (x = isIntern(tail(y), Intern))
return x;
intern(y, Intern);
val(y) = Nil;
return y;
}
any read1(int end) {
any x;
if (!Chr)
Env.get();
if (Chr == end)
return Nil;
x = read0(YES);
while (Chr && strchr(" \t)]", Chr))
Env.get();
return x;
}
/* Read one token */
any token(any x, int c) {
int i;
word w;
any y;
cell c1, *p;
if (!Chr)
Env.get();
if (skip(c) < 0)
return Nil;
if (Chr == '"') {
Env.get();
if (Chr == '"') {
Env.get();
return Nil;
}
if (!testEsc())
return Nil;
Push(c1, y = cons(mkChar(Chr), Nil));
while (Env.get(), Chr != '"' && testEsc())
y = cdr(y) = cons(mkChar(Chr), Nil);
Env.get();
return Pop(c1);
}
if (Chr >= '0' && Chr <= '9') {
putByte1(Chr, &i, &w, &p);
while (Env.get(), Chr >= '0' && Chr <= '9' || Chr == '.')
putByte(Chr, &i, &w, &p, &c1);
return symToNum(tail(popSym(i, w, p, &c1)), (int)unBox(val(Scl)), '.', 0);
}
if (Chr != '+' && Chr != '-') {
char nm[bufSize(x)];
bufString(x, nm);
if (Chr >= 'A' && Chr <= 'Z' || Chr == '\\' || Chr >= 'a' && Chr <= 'z' || strchr(nm,Chr)) {
if (Chr == '\\')
Env.get();
putByte1(Chr, &i, &w, &p);
while (Env.get(),
Chr >= '0' && Chr <= '9' || Chr >= 'A' && Chr <= 'Z' ||
Chr == '\\' || Chr >= 'a' && Chr <= 'z' || strchr(nm,Chr) ) {
if (Chr == '\\')
Env.get();
putByte(Chr, &i, &w, &p, &c1);
}
y = popSym(i, w, p, &c1);
if (x = isIntern(tail(y), Intern))
return x;
intern(y, Intern);
val(y) = Nil;
return y;
}
}
y = mkTxt(c = Chr);
Env.get();
return mkChar(c);
}
// (read ['sym1 ['sym2]]) -> any
any doRead(any ex) {
any x, y;
if (!isCell(x = cdr(ex)))
x = read1(0), Reloc = Nil;
else {
y = EVAL(car(x));
NeedSym(ex,y);
x = cdr(x), x = EVAL(car(x));
NeedSym(ex,x);
x = token(y, firstByte(x));
}
if (InFile == stdin && Chr == '\n')
Chr = 0;
return x;
}
// (peek) -> sym
any doPeek(any ex __attribute__((unused))) {
if (!Chr)
Env.get();
return Chr<0? Nil : mkChar(Chr);
}
// (char) -> sym
// (char 'num) -> sym
// (char 'sym) -> num
any doChar(any ex) {
any x = cdr(ex);
if (!isCell(x)) {
if (!Chr)
Env.get();
x = Chr<0? Nil : mkChar(Chr);
Env.get();
return x;
}
if (isNum(x = EVAL(car(x)))) {
int c = (int)unBox(x);
if (c == 0)
return Nil;
if (c == 127)
return mkChar2('^','?');
if (c < ' ')
return mkChar2('^', c + 0x40);
return mkChar(c);
}
if (isSym(x)) {
int c;
if ((c = firstByte(x)) != '^')
return box(c);
return box((c = secondByte(x)) == '?'? 127 : c & 0x1F);
}
atomError(ex,x);
}
// (skip ['any]) -> sym
any doSkip(any x) {
x = evSym(cdr(x));
return skip(firstByte(x))<0? Nil : mkChar(Chr);
}
// (eol) -> flg
any doEol(any ex __attribute__((unused))) {
return InFile && Chr=='\n' || Chr<=0? T : Nil;
}
// (eof ['flg]) -> flg
any doEof(any x) {
x = cdr(x);
if (!isNil(EVAL(car(x)))) {
Chr = -1;
return T;
}
if (!Chr)
Env.get();
return Chr < 0? T : Nil;
}
// (from 'any ..) -> sym
any doFrom(any x) {
int i, j, ac = length(x = cdr(x)), p[ac];
cell c[ac];
char *av[ac];
if (ac == 0)
return Nil;
for (i = 0;;) {
Push(c[i], evSym(x));
av[i] = alloc(NULL, bufSize(data(c[i]))), bufString(data(c[i]), av[i]);
p[i] = 0;
if (++i == ac)
break;
x = cdr(x);
}
if (!Chr)
Env.get();
while (Chr >= 0) {
for (i = 0; i < ac; ++i) {
for (;;) {
if (av[i][p[i]] == (byte)Chr) {
if (av[i][++p[i]])
break;
Env.get();
x = data(c[i]);
goto done;
}
if (!p[i])
break;
for (j = 1; --p[i]; ++j)
if (memcmp(av[i], av[i]+j, p[i]) == 0)
break;
}
}
Env.get();
}
x = Nil;
done:
i = 0; do
free(av[i]);
while (++i < ac);
drop(c[0]);
return x;
}
// (till 'any ['flg]) -> lst|sym
any doTill(any ex) {
any x;
int i;
word w;
cell c1;
x = evSym(cdr(ex));
{
char buf[bufSize(x)];
bufString(x, buf);
if (!Chr)
Env.get();
if (Chr < 0 || strchr(buf,Chr))
return Nil;
x = cddr(ex);
if (isNil(EVAL(car(x)))) {
Push(c1, x = cons(mkChar(Chr), Nil));
while (Env.get(), Chr > 0 && !strchr(buf,Chr))
x = cdr(x) = cons(mkChar(Chr), Nil);
return Pop(c1);
}
putByte1(Chr, &i, &w, &x);
while (Env.get(), Chr > 0 && !strchr(buf,Chr))
putByte(Chr, &i, &w, &x, &c1);
return popSym(i, w, x, &c1);
}
}
static inline bool eol(void) {
if (Chr < 0)
return YES;
if (Chr == '\n') {
Chr = 0;
return YES;
}
if (Chr == '\r') {
Env.get();
if (Chr == '\n')
Chr = 0;
return YES;
}
return NO;
}
// (line 'flg) -> lst|sym
any doLine(any x) {
any y;
int i;
word w;
cell c1;
if (!Chr)
Env.get();
if (eol())
return Nil;
x = cdr(x);
if (isNil(EVAL(car(x)))) {
Push(c1, cons(mkChar(Chr), Nil));
y = data(c1);
for (;;) {
if (Env.get(), eol())
return Pop(c1);
y = cdr(y) = cons(mkChar(Chr), Nil);
}
}
else {
putByte1(Chr, &i, &w, &y);
for (;;) {
if (Env.get(), eol())
return popSym(i, w, y, &c1);
putByte(Chr, &i, &w, &y, &c1);
}
}
}
static any parse(any x, bool skp) {
int c;
parseFrame *save, parser;
void (*getSave)(void);
cell c1;
save = Env.parser;
Env.parser = &parser;
parser.nm = name(parser.sym = x);
getSave = Env.get, Env.get = getParse, c = Chr;
Push(c1, Env.parser->sym);
Chr = getByte1(&parser.i, &parser.w, &parser.nm);
if (skp)
getParse();
x = rdList();
drop(c1);
Chr = c, Env.get = getSave, Env.parser = save;
return x;
}
static void putString(int c) {
putByte(c, &StrI, &StrW, &StrP, &StrCell);
}
void begString(void) {
putByte0(&StrI, &StrW, &StrP);
PutSave = Env.put, Env.put = putString;
}
any endString(void) {
Env.put = PutSave;
StrP = popSym(StrI, StrW, StrP, &StrCell);
return StrI? StrP : Nil;
}
// (any 'sym) -> any
any doAny(any ex) {
any x;
x = cdr(ex), x = EVAL(car(x));
NeedSymb(ex,x);
if (!isNil(x)) {
int c;
parseFrame *save, parser;
void (*getSave)(void);
cell c1;
save = Env.parser;
Env.parser = &parser;
parser.nm = name(parser.sym = x);
getSave = Env.get, Env.get = getParse, c = Chr;
Push(c1, Env.parser->sym);
Chr = getByte1(&parser.i, &parser.w, &parser.nm);
x = read0(YES);
drop(c1);
Chr = c, Env.get = getSave, Env.parser = save;
}
return x;
}
// (sym 'any) -> sym
any doSym(any x) {
x = EVAL(cadr(x));
begString();
print(x);
return endString();
}
// (str 'sym) -> lst
// (str 'lst) -> sym
any doStr(any ex) {
any x;
x = cdr(ex);
if (isNum(x = EVAL(car(x))))
argError(ex,x);
if (isSym(x))
return isNil(x)? Nil : parse(x,NO);
begString();
while (print(car(x)), isCell(x = cdr(x)))
space();
return endString();
}
any load(any ex, int pr, any x) {
cell c1, c2;
inFrame f;
if (isSymb(x) && firstByte(x) == '-') {
Push(c1, parse(x,YES));
x = evList(data(c1));
drop(c1);
return x;
}
rdOpen(ex, x, &f);
pushInFiles(&f);
doHide(Nil);
x = Nil;
for (;;) {
if (InFile != stdin)
data(c1) = read1(0);
else {
if (pr && !Chr)
Env.put(pr), space(), fflush(OutFile);
data(c1) = read1('\n');
if (Chr == '\n')
Chr = 0;
}
if (isNil(data(c1))) {
popInFiles();
doHide(Nil);
return x;
}
Save(c1);
if (InFile != stdin || Chr || !pr)
x = EVAL(data(c1));
else {
Push(c2, val(At));
x = val(At) = EVAL(data(c1));
val(At3) = val(At2), val(At2) = data(c2);
outString("-> "), fflush(OutFile), print(x), newline();
}
drop(c1);
}
}
// (load 'any ..) -> any
any doLoad(any ex) {
any x, y;
x = cdr(ex);
do {
if ((y = EVAL(car(x))) != T)
y = load(ex, '>', y);
else
y = loadAll(ex);
} while (isCell(x = cdr(x)));
return y;
}
// (in 'any . prg) -> any
any doIn(any ex) {
any x;
inFrame f;
x = cdr(ex), x = EVAL(car(x));
rdOpen(ex,x,&f);
pushInFiles(&f);
x = prog(cddr(ex));
popInFiles();
return x;
}
// (out 'any . prg) -> any
any doOut(any ex) {
any x;
outFrame f;
x = cdr(ex), x = EVAL(car(x));
wrOpen(ex,x,&f);
pushOutFiles(&f);
x = prog(cddr(ex));
popOutFiles();
return x;
}
/*** Prining ***/
void putStdout(int c) {putc(c, OutFile);}
void newline(void) {Env.put('\n');}
void space(void) {Env.put(' ');}
void outString(char *s) {
while (*s)
Env.put(*s++);
}
int bufNum(char buf[BITS/2], long n) {
return sprintf(buf, "%ld", n);
}
void outNum(long n) {
char buf[BITS/2];
bufNum(buf, n);
outString(buf);
}
void prIntern(any nm) {
int i, c;
word w;
c = getByte1(&i, &w, &nm);
if (strchr(Delim, c))
Env.put('\\');
Env.put(c);
while (c = getByte(&i, &w, &nm)) {
if (c == '\\' || strchr(Delim, c))
Env.put('\\');
Env.put(c);
}
}
void prTransient(any nm) {
int i, c;
word w;
Env.put('"');
c = getByte1(&i, &w, &nm);
do {
if (c == '"' || c == '\\')
Env.put('\\');
Env.put(c);
} while (c = getByte(&i, &w, &nm));
Env.put('"');
}
/* Print one expression */
void print(any x) {
if (isNum(x))
outNum(unBox(x));
else if (isSym(x)) {
any nm = name(x);
if (nm == txt(0))
Env.put('$'), outNum((word)x/sizeof(cell));
else if (x == isIntern(nm, Intern))
prIntern(nm);
else
prTransient(nm);
}
else if (car(x) == Quote && x != cdr(x))
Env.put('\''), print(cdr(x));
else {
any y;
Env.put('(');
if ((y = circ(x)) == NULL) {
while (print(car(x)), !isNil(x = cdr(x))) {
if (!isCell(x)) {
outString(" . ");
print(x);
break;
}
space();
}
}
else if (y == x) {
do
print(car(x)), space();
while (y != (x = cdr(x)));
Env.put('.');
}
else {
do
print(car(x)), space();
while (y != (x = cdr(x)));
outString(". (");
do
print(car(x)), space();
while (y != (x = cdr(x)));
outString(".)");
}
Env.put(')');
}
}
void prin(any x) {
if (!isNil(x)) {
if (isNum(x))
outNum(unBox(x));
else if (isSym(x)) {
int i, c;
word w;
for (x = name(x), c = getByte1(&i, &w, &x); c; c = getByte(&i, &w, &x)) {
if (c != '^')
Env.put(c);
else if (!(c = getByte(&i, &w, &x)))
Env.put('^');
else if (c == '?')
Env.put(127);
else
Env.put(c &= 0x1F);
}
}
else {
while (prin(car(x)), !isNil(x = cdr(x))) {
if (!isCell(x)) {
prin(x);
break;
}
}
}
}
}
// (prin 'any ..) -> any
any doPrin(any x) {
any y = Nil;
while (isCell(x = cdr(x)))
prin(y = EVAL(car(x)));
return y;
}
// (prinl 'any ..) -> any
any doPrinl(any x) {
any y = Nil;
while (isCell(x = cdr(x)))
prin(y = EVAL(car(x)));
newline();
return y;
}
// (space ['num]) -> num
any doSpace(any ex) {
any x;
int n;
if (isNil(x = EVAL(cadr(ex)))) {
Env.put(' ');
return One;
}
for (n = xNum(ex,x); n > 0; --n)
Env.put(' ');
return x;
}
// (print 'any ..) -> any
any doPrint(any x) {
any y;
x = cdr(x), print(y = EVAL(car(x)));
while (isCell(x = cdr(x)))
space(), print(y = EVAL(car(x)));
return y;
}
// (printsp 'any ..) -> any
any doPrintsp(any x) {
any y;
x = cdr(x);
do
print(y = EVAL(car(x))), space();
while (isCell(x = cdr(x)));
return y;
}
// (println 'any ..) -> any
any doPrintln(any x) {
any y;
x = cdr(x), print(y = EVAL(car(x)));
while (isCell(x = cdr(x)))
space(), print(y = EVAL(car(x)));
newline();
return y;
}
/* Save one expression */
static void save(any x) {
any y, nm;
if (isNum(x))
outNum(unBox(x));
else if (isSym(x)) {
if (x == isIntern(nm = name(x), Intern))
prIntern(nm);
else if (num(y = val(x)) & 1) {
if (nm == txt(0))
Env.put('\\'), outNum((word)x/sizeof(cell));
else
prTransient(nm);
}
else {
*(long*)&val(x) |= 1;
if (x == y && nm != txt(0))
prTransient(nm);
else {
outString("\\(");
if (nm == txt(0))
outNum((word)x/sizeof(cell));
else
prTransient(nm);
space(), save(y);
for (y = tail(x); isCell(y); y = car(y))
space(), save(cdr(y));
Env.put(')');
}
}
}
else {
y = x;
Env.put('(');
while (save(car(x)), !isNil(x = cdr(x))) {
if (x == y) {
outString(" .");
break;
}
if (!isCell(x)) {
outString(" . ");
save(x);
break;
}
space();
}
Env.put(')');
}
}
// (save 'any) -> any
any doSave(any x) {
any p;
heap *h;
x = cdr(x), save(x = EVAL(car(x))), newline();
h = Heaps;
do {
p = h->cells + CELLS-1;
do
*(long*)&cdr(p) &= ~1;
while (--p >= h->cells);
} while (h = h->next);
return x;
}
// (flush) -> flg
any doFlush(any ex __attribute__((unused))) {
return fflush(OutFile)? Nil : T;
}