mplisp

miniPicoLisp with FFI and modules for Buddy BDD library, OpenGL, Gtk and GMP
git clone https://logand.com/git/mplisp.git/
Log | Files | Refs

io.c (22871B)


      1 /* 01apr08abu
      2  * (c) Software Lab. Alexander Burger
      3  */
      4 
      5 #include "pico.h"
      6 
      7 static any read0(bool);
      8 
      9 static int StrI;
     10 static cell StrCell, *StrP;
     11 static word StrW;
     12 static void (*PutSave)(int);
     13 static char Delim[] = " \t\n\r\"'()[]`~";
     14 
     15 static void openErr(any ex, char *s) {err(ex, NULL, "%s open: %s", s, strerror(errno));}
     16 static void eofErr(void) {err(NULL, NULL, "EOF Overrun");}
     17 
     18 /* Buffer size */
     19 int bufSize(any x) {return symBytes(x) + 1;}
     20 
     21 int pathSize(any x) {
     22    int c = firstByte(x);
     23 
     24    if (c != '@'  &&  (c != '+' || secondByte(x) != '@'))
     25       return bufSize(x);
     26    if (!Home)
     27       return symBytes(x);
     28    return strlen(Home) + symBytes(x);
     29 }
     30 
     31 void bufString(any x, char *p) {
     32    int c, i;
     33    word w;
     34 
     35    if (!isNil(x)) {
     36       for (x = name(x), c = getByte1(&i, &w, &x); c; c = getByte(&i, &w, &x)) {
     37          if (c == '^') {
     38             if ((c = getByte(&i, &w, &x)) == '?')
     39                c = 127;
     40             else
     41                c &= 0x1F;
     42          }
     43          *p++ = c;
     44       }
     45    }
     46    *p = '\0';
     47 }
     48 
     49 void pathString(any x, char *p) {
     50    int c, i;
     51    word w;
     52    char *h;
     53 
     54    x = name(x);
     55    if ((c = getByte1(&i, &w, &x)) == '+')
     56       *p++ = c,  c = getByte(&i, &w, &x);
     57    if (c != '@')
     58       while (*p++ = c)
     59          c = getByte(&i, &w, &x);
     60    else {
     61       if (h = Home)
     62          do
     63             *p++ = *h++;
     64          while (*h);
     65       while (*p++ = getByte(&i, &w, &x));
     66    }
     67 }
     68 
     69 // (path 'sym) -> sym
     70 any doPath(any ex) {
     71    any x;
     72 
     73    x = cdr(ex),  x = EVAL(car(x));
     74    NeedSym(ex,x);
     75    {
     76       char nm[pathSize(x)];
     77 
     78       pathString(x,nm);
     79       return mkStr(nm);
     80    }
     81 }
     82 
     83 void rdOpen(any ex, any x, inFrame *f) {
     84    NeedSymb(ex,x);
     85    if (isNil(x))
     86       f->fp = stdin;
     87    else {
     88       char nm[pathSize(x)];
     89 
     90       pathString(x,nm);
     91       if (nm[0] == '+') {
     92          if (!(f->fp = fopen(nm+1, "a+")))
     93             openErr(ex, nm);
     94          fseek(f->fp, 0L, SEEK_SET);
     95       }
     96       else if (!(f->fp = fopen(nm, "r")))
     97          openErr(ex, nm);
     98    }
     99 }
    100 
    101 void wrOpen(any ex, any x, outFrame *f) {
    102    NeedSymb(ex,x);
    103    if (isNil(x))
    104       f->fp = stdout;
    105    else {
    106       char nm[pathSize(x)];
    107 
    108       pathString(x,nm);
    109       if (nm[0] == '+') {
    110          if (!(f->fp = fopen(nm+1, "a")))
    111             openErr(ex, nm);
    112       }
    113       else if (!(f->fp = fopen(nm, "w")))
    114          openErr(ex, nm);
    115    }
    116 }
    117 
    118 /*** Reading ***/
    119 void getStdin(void) {Chr = getc(InFile);}
    120 
    121 static void getParse(void) {
    122    if ((Chr = getByte(&Env.parser->i, &Env.parser->w, &Env.parser->nm)) == 0)
    123       Chr = ']';
    124 }
    125 
    126 void pushInFiles(inFrame *f) {
    127    f->next = Chr,  Chr = 0;
    128    InFile = f->fp;
    129    f->get = Env.get,  Env.get = getStdin;
    130    f->link = Env.inFiles,  Env.inFiles = f;
    131 }
    132 
    133 void pushOutFiles(outFrame *f) {
    134    OutFile = f->fp;
    135    f->put = Env.put,  Env.put = putStdout;
    136    f->link = Env.outFiles,  Env.outFiles = f;
    137 }
    138 
    139 void popInFiles(void) {
    140    if (InFile != stdin)
    141       fclose(InFile);
    142    Chr = Env.inFiles->next;
    143    Env.get = Env.inFiles->get;
    144    InFile = (Env.inFiles = Env.inFiles->link)?  Env.inFiles->fp : stdin;
    145 }
    146 
    147 void popOutFiles(void) {
    148    if (OutFile != stdout)
    149       fclose(OutFile);
    150    Env.put = Env.outFiles->put;
    151    OutFile = (Env.outFiles = Env.outFiles->link)? Env.outFiles->fp : stdout;
    152 }
    153 
    154 /* Skip White Space and Comments */
    155 static int skip(int c) {
    156    for (;;) {
    157       if (Chr < 0)
    158          return Chr;
    159       while (Chr <= ' ') {
    160          Env.get();
    161          if (Chr < 0)
    162             return Chr;
    163       }
    164       if (Chr != c)
    165          return Chr;
    166       while (Env.get(), Chr != '\n')
    167          if (Chr < 0)
    168             return Chr;
    169       Env.get();
    170    }
    171 }
    172 
    173 /* Test for escaped characters */
    174 static bool testEsc(void) {
    175    for (;;) {
    176       if (Chr < 0)
    177          return NO;
    178       if (Chr != '\\')
    179          return YES;
    180       if (Env.get(), Chr != '\n')
    181          return YES;
    182       do
    183          Env.get();
    184       while (Chr == ' '  ||  Chr == '\t');
    185    }
    186 }
    187 
    188 /* Read a list */
    189 static any rdList(void) {
    190    any x;
    191    cell c1, c2;
    192 
    193    if (skip('#') == ')') {
    194       Env.get();
    195       return Nil;
    196    }
    197    if (Chr == ']')
    198       return Nil;
    199    for (;;) {
    200       if (Chr != '~') {
    201          Push(c1, x = cons(read0(NO),Nil));
    202          break;
    203       }
    204       Env.get();
    205       Push(c1, read0(NO));
    206       if (isCell(x = data(c1) = EVAL(data(c1)))) {
    207          do
    208             x = cdr(x);
    209          while (isCell(cdr(x)));
    210          break;
    211       }
    212       drop(c1);
    213    }
    214    for (;;) {
    215       if (skip('#') == ')') {
    216          Env.get();
    217          break;
    218       }
    219       if (Chr == ']')
    220          break;
    221       if (Chr == '.') {
    222          Env.get();
    223          cdr(x) = skip('#')==')' || Chr==']'? data(c1) : read0(NO);
    224          if (skip('#') == ')')
    225             Env.get();
    226          else if (Chr != ']')
    227             err(NULL, x, "Bad dotted pair");
    228          break;
    229       }
    230       if (Chr != '~')
    231          x = cdr(x) = cons(read0(NO),Nil);
    232       else {
    233          Env.get();
    234          Push(c2, read0(NO));
    235          data(c2) = EVAL(data(c2));
    236          if (isCell(cdr(x) = Pop(c2)))
    237             do
    238                x = cdr(x);
    239             while (isCell(cdr(x)));
    240       }
    241    }
    242    return Pop(c1);
    243 }
    244 
    245 /* Try for anonymous symbol */
    246 static any anonymous(any s) {
    247    int c, i;
    248    word w;
    249    unsigned long n;
    250    heap *h;
    251 
    252    if ((c = getByte1(&i, &w, &s)) != '$')
    253       return NULL;
    254    n = 0;
    255    while (c = getByte(&i, &w, &s)) {
    256       if (c < '0' || c > '9')
    257          return NULL;
    258       n = n * 10 + c - '0';
    259    }
    260    n *= sizeof(cell);
    261    h = Heaps;
    262    do
    263       if ((any)n > h->cells  &&  (any)n < h->cells + CELLS)
    264          return symPtr((any)n);
    265    while (h = h->next);
    266    return NULL;
    267 }
    268 
    269 /* Relocate anonymous symbol */
    270 static any reloc(any key) {
    271    any x, y;
    272    int n;
    273 
    274    if (!isCell(x = Reloc)) {
    275       Reloc = cons(cons(key, y = consSym(Nil,0)), Nil);
    276       return y;
    277    }
    278    for (;;) {
    279       if ((n = num(key) - num(caar(x))) == 0)
    280          return cdar(x);
    281       if (!isCell(cdr(x))) {
    282          key = cons(cons(key, y = consSym(Nil,0)), Nil);
    283          cdr(x) = n<0? cons(key,Nil) : cons(Nil,key);
    284          return y;
    285       }
    286       if (n < 0) {
    287          if (!isCell(cadr(x))) {
    288             cadr(x) = cons(cons(key, y = consSym(Nil,0)), Nil);
    289             return y;
    290          }
    291          x = cadr(x);
    292       }
    293       else {
    294          if (!isCell(cddr(x))) {
    295             cddr(x) = cons(cons(key, y = consSym(Nil,0)), Nil);
    296             return y;
    297          }
    298          x = cddr(x);
    299       }
    300    }
    301 }
    302 
    303 /* Read one expression */
    304 static any read0(bool top) {
    305    int i;
    306    word w;
    307    any x, y;
    308    cell c1, *p;
    309 
    310    if (skip('#') < 0) {
    311       if (top)
    312          return Nil;
    313       eofErr();
    314    }
    315    if (Chr == '(') {
    316       Env.get();
    317       x = rdList();
    318       if (top  &&  Chr == ']')
    319          Env.get();
    320       return x;
    321    }
    322    if (Chr == '[') {
    323       Env.get();
    324       x = rdList();
    325       if (Chr != ']')
    326          err(NULL, x, "Super parentheses mismatch");
    327       Env.get();
    328       return x;
    329    }
    330    if (Chr == '\'') {
    331       Env.get();
    332       return cons(Quote, read0(NO));
    333    }
    334    if (Chr == '`') {
    335       Env.get();
    336       Push(c1, read0(NO));
    337       x = EVAL(data(c1));
    338       drop(c1);
    339       return x;
    340    }
    341    if (Chr == '\\') {
    342       Env.get();
    343       Push(c1, read0(NO));
    344       if (isNum(x = data(c1)))
    345          x = reloc(x);
    346       else if (isCell(x)) {
    347          Transient[0] = Transient[1] = Nil;
    348          if (isNum(x = car(y = x)))
    349             x = car(y) = reloc(x);
    350          if (isCell(y = cdr(y))) {
    351             val(x) = car(y);
    352             p = (any)&tail(x);
    353             while (isCell(car(p)))
    354                car(p) = caar(p);
    355             while (isCell(y = cdr(y)))
    356                car(p) = cons(car(p),car(y)),  p = car(p);
    357          }
    358       }
    359       drop(c1);
    360       return x;
    361    }
    362    if (Chr == '"') {
    363       Env.get();
    364       if (Chr == '"') {
    365          Env.get();
    366          return Nil;
    367       }
    368       if (!testEsc())
    369          eofErr();
    370       putByte1(Chr, &i, &w, &p);
    371       while (Env.get(), Chr != '"') {
    372          if (!testEsc())
    373             eofErr();
    374          putByte(Chr, &i, &w, &p, &c1);
    375       }
    376       y = popSym(i, w, p, &c1),  Env.get();
    377       if (x = isIntern(tail(y), Transient))
    378          return x;
    379       if (Env.get == getStdin)
    380          intern(y, Transient);
    381       return y;
    382    }
    383    if (strchr(Delim, Chr))
    384       err(NULL, NULL, "Bad input '%c' (%d)", isprint(Chr)? Chr:'?', Chr);
    385    if (Chr == '\\')
    386       Env.get();
    387    putByte1(Chr, &i, &w, &p);
    388    for (;;) {
    389       Env.get();
    390       if (strchr(Delim, Chr))
    391          break;
    392       if (Chr == '\\')
    393          Env.get();
    394       putByte(Chr, &i, &w, &p, &c1);
    395    }
    396    y = popSym(i, w, p, &c1);
    397    if (x = symToNum(tail(y), (int)unBox(val(Scl)), '.', 0))
    398       return x;
    399    if (x = isIntern(tail(y), Intern))
    400       return x;
    401    if (x = anonymous(name(y)))
    402       return x;
    403    intern(y, Intern);
    404    val(y) = Nil;
    405    return y;
    406 }
    407 
    408 any read1(int end) {
    409    any x;
    410 
    411    if (!Chr)
    412       Env.get();
    413    if (Chr == end)
    414       return Nil;
    415    x = read0(YES);
    416    while (Chr  &&  strchr(" \t)]", Chr))
    417       Env.get();
    418    return x;
    419 }
    420 
    421 /* Read one token */
    422 any token(any x, int c) {
    423    int i;
    424    word w;
    425    any y;
    426    cell c1, *p;
    427 
    428    if (!Chr)
    429       Env.get();
    430    if (skip(c) < 0)
    431       return Nil;
    432    if (Chr == '"') {
    433       Env.get();
    434       if (Chr == '"') {
    435          Env.get();
    436          return Nil;
    437       }
    438       testEsc();
    439       putByte1(Chr, &i, &w, &p);
    440       while (Env.get(), Chr != '"' && testEsc())
    441          putByte(Chr, &i, &w, &p, &c1);
    442       Env.get();
    443       return popSym(i, w, p, &c1);
    444    }
    445    if (Chr >= '0' && Chr <= '9') {
    446       putByte1(Chr, &i, &w, &p);
    447       while (Env.get(), Chr >= '0' && Chr <= '9' || Chr == '.')
    448          putByte(Chr, &i, &w, &p, &c1);
    449       return symToNum(tail(popSym(i, w, p, &c1)), (int)unBox(val(Scl)), '.', 0);
    450    }
    451    {
    452       char nm[bufSize(x)];
    453 
    454       bufString(x, nm);
    455       if (Chr >= 'A' && Chr <= 'Z' || Chr == '\\' || Chr >= 'a' && Chr <= 'z' || strchr(nm,Chr)) {
    456          if (Chr == '\\')
    457             Env.get();
    458          putByte1(Chr, &i, &w, &p);
    459          while (Env.get(),
    460                Chr >= '0' && Chr <= '9' || Chr >= 'A' && Chr <= 'Z' ||
    461                Chr == '\\' || Chr >= 'a' && Chr <= 'z' || strchr(nm,Chr) ) {
    462             if (Chr == '\\')
    463                Env.get();
    464             putByte(Chr, &i, &w, &p, &c1);
    465          }
    466          y = popSym(i, w, p, &c1);
    467          if (x = isIntern(tail(y), Intern))
    468             return x;
    469          intern(y, Intern);
    470          val(y) = Nil;
    471          return y;
    472       }
    473    }
    474    y = mkTxt(c = Chr);
    475    Env.get();
    476    if (x = isIntern(y, Intern))
    477       return x;
    478    return mkChar(c);
    479 }
    480 
    481 // (read ['sym1 ['sym2]]) -> any
    482 any doRead(any ex) {
    483    any x, y;
    484 
    485    if (!isCell(x = cdr(ex)))
    486       x = read1(0),  Reloc = Nil;
    487    else {
    488       y = EVAL(car(x));
    489       NeedSym(ex,y);
    490       x = cdr(x),  x = EVAL(car(x));
    491       NeedSym(ex,x);
    492       x = token(y, firstByte(x));
    493    }
    494    if (InFile == stdin  &&  Chr == '\n')
    495       Chr = 0;
    496    return x;
    497 }
    498 
    499 // (peek) -> sym
    500 any doPeek(any ex __attribute__((unused))) {
    501    if (!Chr)
    502       Env.get();
    503    return Chr<0? Nil : mkChar(Chr);
    504 }
    505 
    506 // (char) -> sym
    507 // (char 'num) -> sym
    508 // (char 'sym) -> num
    509 any doChar(any ex) {
    510    any x = cdr(ex);
    511 
    512    if (!isCell(x)) {
    513       if (!Chr)
    514          Env.get();
    515       x = Chr<0? Nil : mkChar(Chr);
    516       Env.get();
    517       return x;
    518    }
    519    if (isNum(x = EVAL(car(x)))) {
    520       int c = (int)unBox(x);
    521 
    522       if (c == 127)
    523          return mkChar2('^','?');
    524       if (c < ' ')
    525          return mkChar2('^', c + 0x40);
    526       return mkChar(c);
    527    }
    528    if (isSym(x)) {
    529       int c;
    530 
    531       if ((c = firstByte(x)) != '^')
    532          return box(c);
    533       return box((c = secondByte(x)) == '?'? 127 : c & 0x1F);
    534    }
    535    atomError(ex,x);
    536 }
    537 
    538 // (skip ['sym]) -> sym
    539 any doSkip(any ex) {
    540    any x;
    541 
    542    x = cdr(ex),  x = EVAL(car(x));
    543    NeedSymb(ex,x);
    544    return skip(firstByte(x))<0? Nil : mkChar(Chr);
    545 }
    546 
    547 // (eol) -> flg
    548 any doEol(any ex __attribute__((unused))) {
    549    return InFile && Chr=='\n' || Chr<=0? T : Nil;
    550 }
    551 
    552 // (eof ['flg]) -> flg
    553 any doEof(any x) {
    554    x = cdr(x);
    555    if (!isNil(EVAL(car(x)))) {
    556       Chr = -1;
    557       return T;
    558    }
    559    if (!Chr)
    560       Env.get();
    561    return Chr < 0? T : Nil;
    562 }
    563 
    564 // (from 'any ..) -> sym
    565 any doFrom(any ex) {
    566    any x;
    567    int res, i, j, ac = length(x = cdr(ex)), p[ac];
    568    cell c[ac];
    569    char *av[ac];
    570 
    571    if (ac == 0)
    572       return Nil;
    573    for (i = 0;;) {
    574       Push(c[i], evSym(x));
    575       av[i] = alloc(NULL, bufSize(data(c[i]))),  bufString(data(c[i]), av[i]);
    576       p[i] = 0;
    577       if (++i == ac)
    578          break;
    579       x = cdr(x);
    580    }
    581    res = -1;
    582    if (!Chr)
    583       Env.get();
    584    while (Chr >= 0) {
    585       for (i = 0; i < ac; ++i) {
    586          for (;;) {
    587             if (av[i][p[i]] == (byte)Chr) {
    588                if (av[i][++p[i]])
    589                   break;
    590                Env.get();
    591                res = i;
    592                goto done;
    593             }
    594             if (!p[i])
    595                break;
    596             for (j = 1; --p[i]; ++j)
    597                if (memcmp(av[i], av[i]+j, p[i]) == 0)
    598                   break;
    599          }
    600       }
    601       Env.get();
    602    }
    603 done:
    604    i = 0;  do
    605       free(av[i]);
    606    while (++i < ac);
    607    drop(c[0]);
    608    return res < 0? Nil : data(c[res]);
    609 }
    610 
    611 // (till 'any ['flg]) -> lst|sym
    612 any doTill(any ex) {
    613    any x;
    614    int i;
    615    word w;
    616    cell c1;
    617 
    618    x = evSym(cdr(ex));
    619    {
    620       char buf[bufSize(x)];
    621 
    622       bufString(x, buf);
    623       if (!Chr)
    624          Env.get();
    625       if (Chr < 0 || strchr(buf,Chr))
    626          return Nil;
    627       x = cddr(ex);
    628       if (isNil(EVAL(car(x)))) {
    629          Push(c1, x = cons(mkChar(Chr), Nil));
    630          while (Env.get(), Chr > 0 && !strchr(buf,Chr))
    631             x = cdr(x) = cons(mkChar(Chr), Nil);
    632          return Pop(c1);
    633       }
    634       putByte1(Chr, &i, &w, &x);
    635       while (Env.get(), Chr > 0 && !strchr(buf,Chr))
    636          putByte(Chr, &i, &w, &x, &c1);
    637       return popSym(i, w, x, &c1);
    638    }
    639 }
    640 
    641 static inline bool eol(void) {
    642    if (Chr < 0)
    643       return YES;
    644    if (Chr == '\n') {
    645       Chr = 0;
    646       return YES;
    647    }
    648    if (Chr == '\r') {
    649       Env.get();
    650       if (Chr == '\n')
    651          Chr = 0;
    652       return YES;
    653    }
    654    return NO;
    655 }
    656 
    657 // (line 'flg) -> lst|sym
    658 any doLine(any x) {
    659    any y;
    660    int i;
    661    word w;
    662    cell c1;
    663 
    664    if (!Chr)
    665       Env.get();
    666    if (eol())
    667       return Nil;
    668    x = cdr(x);
    669    if (isNil(EVAL(car(x)))) {
    670       Push(c1, cons(mkChar(Chr), Nil));
    671       y = data(c1);
    672       for (;;) {
    673          if (Env.get(), eol())
    674             return Pop(c1);
    675          y = cdr(y) = cons(mkChar(Chr), Nil);
    676       }
    677    }
    678    else {
    679       putByte1(Chr, &i, &w, &y);
    680       for (;;) {
    681          if (Env.get(), eol())
    682             return popSym(i, w, y, &c1);
    683          putByte(Chr, &i, &w, &y, &c1);
    684       }
    685    }
    686 }
    687 
    688 static any parse(any x, bool skp) {
    689    int c;
    690    parseFrame *save, parser;
    691    void (*getSave)(void);
    692    cell c1;
    693 
    694    if (save = Env.parser)
    695       Push(c1, Env.parser->sym);
    696    Env.parser = &parser;
    697    parser.nm = name(parser.sym = x);
    698    getSave = Env.get,  Env.get = getParse,  c = Chr;
    699    Chr = getByte1(&parser.i, &parser.w, &parser.nm);
    700    if (skp)
    701       getParse();
    702    x = rdList();
    703    Chr = c,  Env.get = getSave;
    704    if (Env.parser = save)
    705       drop(c1);
    706    return x;
    707 }
    708 
    709 static void putString(int c) {
    710    putByte(c, &StrI, &StrW, &StrP, &StrCell);
    711 }
    712 
    713 void begString(void) {
    714    putByte0(&StrI, &StrW, &StrP);
    715    PutSave = Env.put,  Env.put = putString;
    716 }
    717 
    718 any endString(void) {
    719    Env.put = PutSave;
    720    StrP = popSym(StrI, StrW, StrP, &StrCell);
    721    return StrI? StrP : Nil;
    722 }
    723 
    724 // (any 'sym) -> any
    725 any doAny(any ex) {
    726    any x;
    727 
    728    x = cdr(ex),  x = EVAL(car(x));
    729    NeedSymb(ex,x);
    730    if (!isNil(x)) {
    731       int c;
    732       parseFrame *save, parser;
    733       void (*getSave)(void);
    734       cell c1;
    735 
    736       if (save = Env.parser)
    737          Push(c1, Env.parser->sym);
    738       Env.parser = &parser;
    739       parser.nm = name(parser.sym = x);
    740       getSave = Env.get,  Env.get = getParse,  c = Chr;
    741       Chr = getByte1(&parser.i, &parser.w, &parser.nm);
    742       x = read0(YES);
    743       Chr = c,  Env.get = getSave;
    744       if (Env.parser = save)
    745          drop(c1);
    746    }
    747    return x;
    748 }
    749 
    750 // (sym 'any) -> sym
    751 any doSym(any x) {
    752    cell c1;
    753 
    754    x = EVAL(cadr(x));
    755    begString();
    756    Push(c1,x);
    757    print(data(c1));
    758    drop(c1);
    759    return endString();
    760 }
    761 
    762 // (str 'sym) -> lst
    763 // (str 'lst) -> sym
    764 any doStr(any ex) {
    765    any x;
    766    cell c1;
    767 
    768    x = cdr(ex);
    769    if (isSymb(x = EVAL(car(x))))
    770       return isNil(x)? Nil : parse(x,NO);
    771    NeedCell(ex,x);
    772    begString();
    773    Push(c1,x);
    774    print(car(x));
    775    while (isCell(x = cdr(x)))
    776       space(),  print(car(x));
    777    drop(c1);
    778    return endString();
    779 }
    780 
    781 any load(any ex, int pr, any x) {
    782    cell c1;
    783    inFrame f;
    784 
    785    if (isSymb(x) && firstByte(x) == '-') {
    786       Push(c1, parse(x,YES));
    787       x = evList(data(c1));
    788       drop(c1);
    789       return x;
    790    }
    791    rdOpen(ex, x, &f);
    792    doHide(Nil);
    793    pushInFiles(&f);
    794    x = Nil;
    795    for (;;) {
    796       if (InFile != stdin)
    797          data(c1) = read1(0);
    798       else {
    799          if (pr && !Chr)
    800             Env.put(pr), space(), fflush(OutFile);
    801          data(c1) = read1('\n');
    802          if (Chr == '\n')
    803             Chr = 0;
    804       }
    805       if (isNil(data(c1)))
    806          break;
    807       Save(c1),  x = EVAL(data(c1)),  drop(c1);
    808       if (InFile == stdin && !Chr) {
    809          val(At3) = val(At2),  val(At2) = val(At),  val(At) = x;
    810          outString("-> "),  fflush(OutFile),  print(x),  crlf();
    811       }
    812    }
    813    popInFiles();
    814    doHide(Nil);
    815    return x;
    816 }
    817 
    818 // (load 'any ..) -> any
    819 any doLoad(any ex) {
    820    any x, y;
    821 
    822    x = cdr(ex);
    823    do {
    824       if ((y = EVAL(car(x))) != T)
    825          y = load(ex, '>', y);
    826       else
    827          while (*AV  &&  strcmp(*AV,"-") != 0)
    828             y = load(ex, '>', mkStr(*AV++));
    829    } while (isCell(x = cdr(x)));
    830    return y;
    831 }
    832 
    833 // (in 'any . prg) -> any
    834 any doIn(any ex) {
    835    any x;
    836    inFrame f;
    837 
    838    x = cdr(ex),  x = EVAL(car(x));
    839    rdOpen(ex,x,&f);
    840    pushInFiles(&f);
    841    x = prog(cddr(ex));
    842    popInFiles();
    843    return x;
    844 }
    845 
    846 // (out 'any . prg) -> any
    847 any doOut(any ex) {
    848    any x;
    849    outFrame f;
    850 
    851    x = cdr(ex),  x = EVAL(car(x));
    852    wrOpen(ex,x,&f);
    853    pushOutFiles(&f);
    854    x = prog(cddr(ex));
    855    popOutFiles();
    856    return x;
    857 }
    858 
    859 /*** Prining ***/
    860 void putStdout(int c) {putc(c, OutFile);}
    861 
    862 void crlf(void) {Env.put('\n');}
    863 void space(void) {Env.put(' ');}
    864 
    865 void outString(char *s) {
    866    while (*s)
    867       Env.put(*s++);
    868 }
    869 
    870 int bufNum(char buf[BITS/2], long n) {
    871    return sprintf(buf, "%ld", n);
    872 }
    873 
    874 void outNum(long n) {
    875    char buf[BITS/2];
    876 
    877    bufNum(buf, n);
    878    outString(buf);
    879 }
    880 
    881 void prIntern(any nm) {
    882    int i, c;
    883    word w;
    884 
    885    c = getByte1(&i, &w, &nm);
    886    if (strchr(Delim, c))
    887       Env.put('\\');
    888    Env.put(c);
    889    while (c = getByte(&i, &w, &nm)) {
    890       if (strchr(Delim, c))
    891          Env.put('\\');
    892       Env.put(c);
    893    }
    894 }
    895 
    896 void prTransient(any nm) {
    897    int i, c;
    898    word w;
    899 
    900    Env.put('"');
    901    c = getByte1(&i, &w, &nm);
    902    do {
    903       if (c == '"'  ||  c == '\\')
    904          Env.put('\\');
    905       Env.put(c);
    906    } while (c = getByte(&i, &w, &nm));
    907    Env.put('"');
    908 }
    909 
    910 /* Print one expression */
    911 void print(any x) {
    912    if (isNum(x))
    913       outNum(unBox(x));
    914    else if (isSym(x)) {
    915       any nm = name(x);
    916 
    917       if (nm == txt(0))
    918          Env.put('$'),  outNum((word)x/sizeof(cell));
    919       else if (x == isIntern(nm, Intern))
    920          prIntern(nm);
    921       else
    922          prTransient(nm);
    923    }
    924    else if (car(x) == Quote  &&  x != cdr(x))
    925       Env.put('\''),  print(cdr(x));
    926    else {
    927       any y = x;
    928       Env.put('(');
    929       while (print(car(x)), !isNil(x = cdr(x))) {
    930          if (x == y) {
    931             outString(" .");
    932             break;
    933          }
    934          if (!isCell(x)) {
    935             outString(" . ");
    936             print(x);
    937             break;
    938          }
    939          space();
    940       }
    941       Env.put(')');
    942    }
    943 }
    944 
    945 void prin(any x) {
    946    if (!isNil(x)) {
    947       if (isNum(x))
    948          outNum(unBox(x));
    949       else if (isSym(x)) {
    950          int i, c;
    951          word w;
    952 
    953          for (x = name(x), c = getByte1(&i, &w, &x); c; c = getByte(&i, &w, &x)) {
    954             if (c != '^')
    955                Env.put(c);
    956             else if (!(c = getByte(&i, &w, &x)))
    957                Env.put('^');
    958             else if (c == '?')
    959                Env.put(127);
    960             else
    961                Env.put(c &= 0x1F);
    962          }
    963       }
    964       else {
    965          while (prin(car(x)), !isNil(x = cdr(x))) {
    966             if (!isCell(x)) {
    967                prin(x);
    968                break;
    969             }
    970          }
    971       }
    972    }
    973 }
    974 
    975 // (prin 'any ..) -> any
    976 any doPrin(any x) {
    977    any y = Nil;
    978 
    979    while (isCell(x = cdr(x)))
    980       prin(y = EVAL(car(x)));
    981    return y;
    982 }
    983 
    984 // (prinl 'any ..) -> any
    985 any doPrinl(any x) {
    986    any y = Nil;
    987 
    988    while (isCell(x = cdr(x)))
    989       prin(y = EVAL(car(x)));
    990    crlf();
    991    return y;
    992 }
    993 
    994 // (space ['num]) -> num
    995 any doSpace(any ex) {
    996    any x;
    997    int n;
    998 
    999    if (isNil(x = EVAL(cadr(ex)))) {
   1000       Env.put(' ');
   1001       return One;
   1002    }
   1003    for (n = xNum(ex,x); n > 0; --n)
   1004       Env.put(' ');
   1005    return x;
   1006 }
   1007 
   1008 // (print 'any ..) -> any
   1009 any doPrint(any x) {
   1010    any y;
   1011 
   1012    x = cdr(x),  print(y = EVAL(car(x)));
   1013    while (isCell(x = cdr(x)))
   1014       space(),  print(y = EVAL(car(x)));
   1015    return y;
   1016 }
   1017 
   1018 // (printsp 'any ..) -> any
   1019 any doPrintsp(any x) {
   1020    any y;
   1021 
   1022    x = cdr(x);
   1023    do
   1024       print(y = EVAL(car(x))),  space();
   1025    while (isCell(x = cdr(x)));
   1026    return y;
   1027 }
   1028 
   1029 // (println 'any ..) -> any
   1030 any doPrintln(any x) {
   1031    any y;
   1032 
   1033    x = cdr(x),  print(y = EVAL(car(x)));
   1034    while (isCell(x = cdr(x)))
   1035       space(),  print(y = EVAL(car(x)));
   1036    crlf();
   1037    return y;
   1038 }
   1039 
   1040 /* Save one expression */
   1041 static void save(any x) {
   1042    any y, nm;
   1043 
   1044    if (isNum(x))
   1045       outNum(unBox(x));
   1046    else if (isSym(x)) {
   1047       if (x == isIntern(nm = name(x), Intern))
   1048          prIntern(nm);
   1049       else if (num(y = val(x)) & 1) {
   1050          if (nm == txt(0))
   1051             Env.put('\\'), outNum((word)x/sizeof(cell));
   1052          else
   1053             prTransient(nm);
   1054       }
   1055       else {
   1056          *(long*)&val(x) |= 1;
   1057          if (x == y && nm != txt(0))
   1058             prTransient(nm);
   1059          else {
   1060             outString("\\(");
   1061             if (nm == txt(0))
   1062                outNum((word)x/sizeof(cell));
   1063             else
   1064                prTransient(nm);
   1065             space(), save(y);
   1066             for (y = tail(x); isCell(y); y = car(y))
   1067                space(), save(cdr(y));
   1068             Env.put(')');
   1069          }
   1070       }
   1071    }
   1072    else {
   1073       y = x;
   1074       Env.put('(');
   1075       while (save(car(x)), !isNil(x = cdr(x))) {
   1076          if (x == y) {
   1077             outString(" .");
   1078             break;
   1079          }
   1080          if (!isCell(x)) {
   1081             outString(" . ");
   1082             save(x);
   1083             break;
   1084          }
   1085          space();
   1086       }
   1087       Env.put(')');
   1088    }
   1089 }
   1090 
   1091 // (save 'any) -> any
   1092 any doSave(any x) {
   1093    any p;
   1094    heap *h;
   1095 
   1096    x = cdr(x),  save(x = EVAL(car(x))),  crlf();
   1097    h = Heaps;
   1098    do {
   1099       p = h->cells + CELLS-1;
   1100       do
   1101          *(long*)&cdr(p) &= ~1;
   1102       while (--p >= h->cells);
   1103    } while (h = h->next);
   1104    return x;
   1105 }
   1106 
   1107 // (flush) -> flg
   1108 any doFlush(any ex __attribute__((unused))) {
   1109    return fflush(OutFile)? Nil : T;
   1110 }