+#include "global.h"
+#include <stdio.h>
+#include <ctype.h>
+#include "chars.h"
+
+struct readtable {
+char ctable[132];
+} initread = {
+/* ^@ nul ^A soh ^B stx ^C etx ^D eot ^E eng ^F ack ^G bel */
+ VERR, VERR, VERR, VERR, VERR, VERR, VERR, VERR,
+/* ^H bs ^I ht ^J nl ^K vt ^L np ^M cr ^N so ^O si */
+ VCHAR, VSEP, VSEP, VSEP, VSEP, VSEP, VERR, VERR,
+/* ^P dle ^Q dc1 ^R dc2 ^S dc3 ^T dc4 ^U nak ^V syn ^W etb */
+ VERR, VERR, VERR, VERR, VERR, VERR, VERR, VERR,
+/* ^X can ^Y em ^Z sub ^[ esc ^\ fs ^] gs ^^ rs ^_ us */
+ VERR, VERR, VERR, VSEP, VERR, VERR, VERR, VERR,
+/* sp ! " # $ % & ' */
+ VSEP, VCHAR, VDQ, VCHAR, VCHAR, VCHAR, VCHAR, VSQ,
+/* ( ) * + , - . / */
+ VLPARA, VRPARA, VCHAR, VSIGN, VCHAR, VSIGN, VPERD, VCHAR,
+/* 0 1 2 3 4 5 6 7 */
+ VNUM, VNUM, VNUM, VNUM, VNUM, VNUM, VNUM, VNUM,
+/* 8 9 : ; < = > ? */
+ VNUM, VNUM, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR,
+/* @ A B C D E F G */
+ VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR,
+/* H I J K L M N O */
+ VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR,
+/* P Q R S T U V W */
+ VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR,
+/* X Y Z [ \ ] ^ _ */
+ VCHAR, VCHAR, VCHAR, VLBRCK, VESC, VRBRCK, VCHAR, VCHAR,
+/* ` a b c d e f g */
+ VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR,
+/* h i j k l m n o */
+ VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR,
+/* p q r s t u v w */
+ VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR,
+/* x y z { | } ~ del */
+ VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VCHAR, VEOF,
+/* unused unused Xesc Xdqc */
+ 0, 0, '\\', '"'
+};
+
+char *ctable = initread.ctable;
+lispval atomval; /* external varaible containing atom returned
+ from internal atom reading routine */
+lispval protect();
+lispval unprotect();
+lispval readrx(); lispval readr(); lispval readry();
+int keywait;
+static int dbqflag;
+static int macflag;
+static int splflag;
+static int mantisfl = 0;
+lispval lastrtab; /* external variable designating current reader
+ table */
+static char baddot1[]=
+"Bad reader construction: (. <something>)\nShould be (nil . <something>)\n";
+static char baddot2[]=
+"Bad reader construction: (<something> .)\n\
+Should be (<something> . <something>), assumed to be (<something>)";
+static char baddot3[]=
+"Bad reader construction: (<something> . <something> not followed by )";
+
+#include "chkrtab.h"
+/* readr ****************************************************************/
+/* returns a s-expression read in from the port specified as the first */
+/* argument. Handles superbrackets, reader macros. */
+lispval
+readr(useport)
+FILE *useport;
+{
+ register lispval handy = Vreadtable->clb;
+
+ chkrtab(handy);
+ rbktf = FALSE;
+ rdrport = (FILE *) useport;
+ if(useport==stdin)
+ keywait = TRUE;
+ handy = readrx(Iratom());
+ if(useport==stdin)
+ keywait = FALSE;
+ return(handy);
+
+}
+
+
+/* readrx **************************************************************/
+/* returns a s-expression beginning with the syntax code of an atom */
+/* passed in the first */
+/* argument. Does the actual work for readr, including list, dotted */
+/* pair, and quoted atom detection */
+lispval
+readrx(code)
+register int code;
+{
+ register lispval work;
+ register lispval *current;
+ register struct argent *result;
+ register struct argent *lbot, *np;
+ int inlbkt = FALSE;
+ lispval errorh();
+
+top:
+ switch(code)
+ {
+ case TLBKT:
+ inlbkt = TRUE;
+ case TLPARA:
+ result = np;
+ current = (lispval *)np;
+ np++->val = nil; /*protect(nil);*/
+ for(EVER) {
+ switch(code = Iratom())
+ {
+ case TRPARA:
+ if(rbktf && inlbkt)
+ rbktf = FALSE;
+ return(result->val);
+ default:
+ atomval = readrx(code);
+ case TSCA:
+ np++->val=atomval;
+ *current = work = newdot();
+ work->car = atomval;
+ np--;
+ current = (lispval *) &(work->cdr);
+ break;
+ case TSPL:
+ macrox(); /* input and output in atomval */
+ *current = atomval;
+ while(*current!=nil) {
+ if(TYPE(*current)!=DTPR)
+ errorh(Vermisc,"Non-list returned from splicing macro",nil,FALSE,7,*current);
+ current=(lispval *)&((*current)->cdr);
+ }
+ break;
+ case TPERD:
+ if(result->val==nil) {
+ work = result->val=newdot();
+ current = (lispval *) &(work->cdr);
+ fprintf(stderr,baddot1);
+ }
+ code = Iratom();
+ if(code==TRPARA) {
+ return(errorh(Vermisc,baddot2,nil,TRUE,58,result->val));
+ }
+ *current = readrx(code);
+ if((code = Iratom())!=TRPARA) {
+ errorh(Vermisc,baddot3,nil,TRUE,59,result->val,atomval);
+ }
+ if(rbktf && inlbkt)
+ rbktf = FALSE;
+ return(result->val);
+ case TEOF:
+ clearerr(rdrport);
+ error("Premature end of file.", FALSE);
+ }
+ if(rbktf) {
+ if(inlbkt)
+ rbktf = FALSE;
+ return(result->val);
+ }
+ }
+ case TSCA:
+ return(atomval);
+ case TEOF:
+ return(eofa);
+ case TMAC:
+ macrox();
+ return(atomval);
+ case TSPL:
+ macrox();
+ if((work = atomval)!=nil) {
+ if(TYPE(work)==DTPR && work->cdr==nil)
+ return(work->car);
+ else
+ errorh(Vermisc,
+"Improper value returned from splicing macro at top-level",nil,FALSE,9,work);
+ }
+ code = Iratom();
+ goto top;
+ /* return(readrx(Iratom())); */
+ case TSQ:
+ result = np;
+ protect(newdot());
+ (work = result->val)->car = quota;
+ work = work->cdr = newdot();
+ work->car = readrx(Iratom());
+ return(result->val);
+ default:
+ return(error("Readlist error",FALSE));
+ }
+}
+macrox()
+{
+ lispval Lapply();
+
+ snpand(0);
+ lbot = np;
+ protect(Iget(atomval,macro));
+ protect(nil);
+ atomval = Lapply();
+ return;
+}
+
+
+
+/* ratomr ***************************************************************/
+/* this routine returns a pointer to an atom read in from the port given*/
+/* by the first argument */
+lispval
+ratomr(useport)
+register FILE *useport;
+{
+ rdrport = useport;
+ switch(Iratom())
+ {
+ case TEOF:
+ return(eofa);
+ case TSQ:
+ case TRPARA:
+ case TLPARA:
+ case TLBKT:
+ case TPERD:
+ strbuf[1]=0;
+ return(getatom());
+ default:
+ return(atomval);
+ }
+}
+Iratom()
+{
+ register FILE *useport = rdrport;
+ register char c, marker, *name;
+ extern lispval finatom(), calcnum(), getnum();
+ char positv = TRUE;
+ int code;
+ int strflag = FALSE;
+
+ name = strbuf;
+
+again: c = getc(useport) & 0177;
+ *name = c;
+
+ switch(ctable[c] & 0377) {
+
+ default: goto again;
+
+ case VNUM:
+
+ case VSIGN: *name++ = c;
+ atomval = (getnum(name));
+ return(TSCA);
+
+ case VESC:
+ dbqflag = TRUE;
+ *name++ = getc(useport) & 0177;
+ atomval = (finatom(name));
+ return(TSCA);
+
+ case VCHAR:
+ *name++ = c;
+ atomval = (finatom(name));
+ return(TSCA);
+
+ case VLPARA: return(TLPARA);
+
+ case VRPARA: return(TRPARA);
+
+ case VPERD: c = peekc(useport);
+ if(VNUM!=ctable[c])
+ return(TPERD);
+ *name++ = '.';
+ mantisfl = 1;
+ atomval = (getnum(name));
+ return(TSCA);
+
+ case VLBRCK: return(TLBKT);
+
+ case VRBRCK: rbktf = TRUE;
+ return(TRPARA);
+
+ case VEOF: /*printf("returning eof atom\n");*/
+ return(TEOF);
+
+ case VSQ: return(TSQ);
+
+ case VSD: strflag = TRUE;
+ case VDQ: name = strbuf;
+ marker = c;
+ while ((c = getc(useport)) != marker) {
+
+ if(VESC==ctable[c]) c = getc(useport);
+ *name++ = c;
+ if (name >= endstrb)
+ error("ATOM TOO LONG",FALSE);
+ if (feof(useport)) {
+ clearerr(useport);
+ error("EOF ecountered while reading atom", FALSE);
+ }
+ }
+ *name = NULL_CHAR;
+ if(strflag)
+ atomval = (lispval) inewstr(strbuf);
+ else
+ atomval = (getatom(name));
+ return(TSCA);
+
+ case VERR: if (c == '\0') goto same; /* null pname */
+ fprintf(stderr,"%c (%o): ",c,(int) c);
+ error("ILLEGAL CHARACTER IN ATOM",TRUE);
+
+ case VSPL:
+ code = TSPL;
+ goto same;
+ case VMAC:
+ code = TMAC;
+ goto same;
+ case VSCA:
+ code = TSCA;
+ same:
+ strbuf[0] = c;
+ strbuf[1] = 0;
+ atomval = (getatom());
+ return(code);
+ }
+}
+
+#define push(); if(name==endstrb) error("Int too long",FALSE); else *name++=c;
+#define next() (stats = ctable[c=getc(useport) & 0177])
+
+lispval
+getnum(name)
+register char *name;
+{
+ register char c;
+ register lispval result;
+ register FILE *useport=rdrport;
+ char stats;
+ double realno;
+ extern lispval finatom(), calcnum(), newdoub(), dopow();
+
+ if(mantisfl) {
+ mantisfl = 0;
+ next();
+ goto mantissa;
+ }
+ while(VNUM==next()) {
+ push(); /* recognize [0-9]*, in "ex" parlance */
+ }
+ if(stats==VPERD) {
+ push(); /* continue */
+ } else if(stats & SEPMASK) {
+ ungetc(c,useport);
+ return(calcnum(strbuf,name,ibase->clb->i));
+ } else if(c=='^') {
+ push();
+ return(dopow(name,ibase->clb->i));
+ } else if(c=='_') {
+ push();
+ return(dopow(name,2));
+ } else{
+ ungetc(c,useport);
+ return(finatom(name));
+ }
+ /* at this point we have [0-9]*\. , which might
+ be a decimal int or the leading part of a
+ float */
+ if(next()!=VNUM) {
+ if(c=='e' || c=='E' || c=='d' ||c=='D')
+ goto expt;
+ else if(c=='^') {
+ push();
+ return(dopow(name,ibase->clb->i));
+ } else if(c=='_') {
+ push();
+ return(dopow(name,2));
+ } else {
+ /* Here we have 1.x where x not num, not sep */
+ /* Here we have decimal int. NOT FORTRAN! */
+ ungetc(c,useport);
+ return(calcnum(strbuf,name-1,10));
+ }
+ }
+mantissa:
+ do {
+ push();
+ } while (VNUM==next());
+ /* Here we have [0-9]*\.[0-9]* */
+ if(stats & SEPMASK)
+ goto last;
+ else if(c!='e' && c!='E' && c!='d' && c!='D') {
+ ungetc(c,useport);
+ goto verylast;
+ }
+expt: push();
+ next();
+ if(c=='+' || c =='-') {
+ push();
+ next();
+ }
+ while (VNUM==stats) {
+ push();
+ next();
+ }
+last: ungetc(c,useport);
+ if(! (stats & SEPMASK) )
+ return(finatom(name));
+
+verylast:
+ *name=0;
+ sscanf(strbuf,"%F",&realno);
+ (result = newdoub())->r = realno;
+ return(result);
+}
+
+lispval
+dopow(part2,base)
+lispval base;
+char *part2;
+{
+ register char *name = part2;
+ register char c;
+ register FILE *useport = rdrport;
+ register int power;
+ register struct argent *lbot, *np;
+ char stats;
+ char *end1 = part2 - 1; lispval Ltimes();
+
+ while(VNUM==next()) {
+ push();
+ }
+ if(c!='.') {
+ ungetc(c,useport);
+ }
+ if(c!='.' && !(stats & SEPMASK)) {
+ return(finatom(name));
+ }
+ lbot = np;
+ np++->val = inewint(base);
+ /* calculate "mantissa"*/
+ if(*end1=='.')
+ np++->val = calcnum(strbuf,end1-1,10);
+ else
+ np++->val = calcnum(strbuf,end1,ibase->clb->i);
+
+ /* calculate exponent */
+ if(c=='.')
+ power = calcnum(part2,name,10)->i;
+ else
+ power = calcnum(part2,name,ibase->clb->i)->i;
+ while(power-- > 0)
+ lbot[1].val = Ltimes();
+ return(lbot[1].val);
+}
+
+
+lispval
+calcnum(strbuf,name,base)
+char *name;
+char *strbuf;
+{
+ register char *p;
+ register lispval result, temp;
+ int negflag = 0;
+
+ temp = rdrsdot; /* initialize sdot cell */
+ temp->CDR = nil;
+ temp->i = 0;
+ p = strbuf;
+ if(*p=='+') p++;
+ else if(*p=='-') {negflag = 1; p++;}
+ *name = 0;
+ if(p>=name) return(getatom());
+
+ for(;p < name; p++)
+ dmlad(temp,base,*p-'0');
+ if(negflag)
+ dmlad(temp,-1,0);
+
+ if(temp->CDR==0) {
+ result = inewint(temp->i);
+ return(result);
+ } else {
+ (result = newsdot())->i = temp->i;
+ result->CDR = temp->CDR;
+ temp->CDR = 0;
+ }
+ return(result);
+}
+lispval
+finatom(name)
+register char *name;
+{
+ extern int uctolc;
+ register FILE *useport = rdrport;
+ register char c, stats;
+ register char *savenm;
+ savenm = name - 1; /* remember start of name */
+ while(!(next()&SEPMASK)) {
+
+ if(stats == VESC) c = getc(useport) & 0177;
+ *name++=c;
+ if (name >= endstrb)
+ error("ATOM TOO LONG",FALSE);
+ }
+ *name = NULL_CHAR;
+ ungetc(c,useport);
+ if (uctolc) for(; *savenm ; savenm++)
+ if( isupper(*savenm) ) *savenm = tolower(*savenm);
+ return(getatom());
+}
+
+/* printr ***************************************************************/
+/* prints the first argument onto the port specified by the second */
+printr(a,useport)
+register lispval a;
+register FILE *useport;
+{
+ register lispval temp;
+ char strflag = 0;
+ char Idqc = 0;
+
+
+val_loop:
+ if( ! VALID(a) )
+ {
+ error("BAD LISP DATA ENCOUNTERED BY PRINTR",TRUE);
+ a = badst;
+ }
+
+ switch (TYPE(a)) {
+
+
+ case UNBO: fputs("<UNBOUND>",useport);
+ break;
+
+ case VALUE: fputs("(ptr to)",useport);
+ a = a->l;
+ goto val_loop;
+
+ case INT: fprintf(useport,"%d",a->i);
+ break;
+
+ case DOUB: fprintf(useport,"%0.16G",a->r);
+ break;
+
+ case PORT: fputs("port",useport);
+ break;
+
+ case ARRAY: fputs("array[",useport);
+ printr(a->length,useport);
+ fputs("]",useport);
+ break;
+
+ case BCD: fprintf(useport,"#%X-",a->entry);
+ printr(a->discipline,useport);
+ break;
+
+ case SDOT: pbignum(a,useport);
+ break;
+
+ case DTPR: if(a->car==quota && a->cdr!=nil
+ && a->cdr->cdr==nil) {
+ putc('\'',useport);
+ printr(a->cdr->car,useport);
+ break;
+ }
+ putc('(',useport);
+ morelist: printr(a->car,useport);
+ if ((a = a->cdr) != nil)
+ {
+ putc(' ',useport);
+ if (TYPE(a) == DTPR) goto morelist;
+ fputs(". ",useport);
+ printr(a,useport);
+ }
+ fputc(')',useport);
+ break;
+
+ case STRNG: strflag = TRUE;
+ Idqc = Xsdc;
+
+ case ATOM: {
+ char *front, *temp; int clean;
+ temp = front = (strflag ? ((char *) a) : a->pname);
+ if(Idqc==0) Idqc = Xdqc;
+
+ if(Idqc) {
+ clean = *temp;
+ if (*temp == '-') temp++;
+ clean = clean && (ctable[*temp] != VNUM);
+ while (clean && *temp)
+ clean = (!(ctable[*temp++] & QUTMASK));
+ if (clean)
+ fputs(front,useport);
+ else {
+ putc(Idqc,useport);
+ for(temp=front;*temp;temp++) {
+ if( *temp==Idqc
+ || ctable[*temp] == VESC)
+ putc(Xesc,useport);
+ putc(*temp,useport);
+ }
+ putc(Idqc,useport);
+ }
+
+ } else {
+ register char *cp = front;
+
+ if(ctable[*cp]==VNUM)
+ putc(Xesc,useport);
+ for(; *cp; cp++) {
+ if(ctable[*cp]& QUTMASK)
+ putc(Xesc,useport);
+ putc(*cp,useport);
+ }
+
+ }
+
+ }
+ }
+}
+
+/* dmpport ****************************************************************/
+/* outputs buffer indicated by first argument whether full or not */
+dmpport(useport)
+register lispval useport;
+ {
+ fflush(useport);
+}
+
+/* protect and unprot moved to eval.c (whr) */