/* xlread - xlisp expression input routine */ #include "xlisp.h" #include "ctype.h" /* external variables */ extern NODE *s_stdout,*true; extern NODE *s_quote,*s_function,*s_bquote,*s_comma,*s_comat; extern NODE *xlstack; extern int xlplevel; /* external routines */ extern FILE *fopen(); /* forward declarations */ FORWARD NODE *plist(); FORWARD NODE *pstring(); FORWARD NODE *pquote(); FORWARD NODE *pname(); /* xlload - load a file of xlisp expressions */ int xlload(name,vflag,pflag) char *name; int vflag,pflag; { NODE *oldstk,fptr,expr; char fname[50]; CONTEXT cntxt; int sts; /* create a new stack frame */ oldstk = xlsave(&fptr,&expr,NULL); /* allocate a file node */ fptr.n_ptr = newnode(FPTR); fptr.n_ptr->n_fp = NULL; fptr.n_ptr->n_savech = 0; /* create the file name and print the information line */ strcpy(fname,name); strcat(fname,".lsp"); if (vflag) printf("; loading \"%s\"\n",fname); /* open the file */ if ((fptr.n_ptr->n_fp = fopen(fname,"r")) == NULL) { xlstack = oldstk; return (FALSE); } /* read, evaluate and possibly print each expression in the file */ xlbegin(&cntxt,CF_ERROR,true); if (setjmp(cntxt.c_jmpbuf)) sts = FALSE; else { while (xlread(fptr.n_ptr,&expr.n_ptr)) { expr.n_ptr = xleval(expr.n_ptr); if (pflag) stdprint(expr.n_ptr); } sts = TRUE; } xlend(&cntxt); /* close the file */ fclose(fptr.n_ptr->n_fp); fptr.n_ptr->n_fp = NULL; /* restore the previous stack frame */ xlstack = oldstk; /* return status */ return (sts); } /* xlread - read an xlisp expression */ int xlread(fptr,pval) NODE *fptr,**pval; { /* initialize */ xlplevel = 0; /* parse an expression */ return (parse(fptr,pval)); } /* parse - parse an xlisp expression */ LOCAL int parse(fptr,pval) NODE *fptr,**pval; { int ch; /* keep looking for a node skipping comments */ while (TRUE) /* check next character for type of node */ switch (ch = nextch(fptr)) { case EOF: xlgetc(fptr); return (FALSE); case '\'': /* a quoted expression */ xlgetc(fptr); *pval = pquote(fptr,s_quote); return (TRUE); case '#': /* a quoted function */ xlgetc(fptr); if ((ch = xlgetc(fptr)) == '<') xlfail("unreadable atom"); else if (ch != '\'') xlfail("expected quote after #"); *pval = pquote(fptr,s_function); return (TRUE); case '`': /* a back quoted expression */ xlgetc(fptr); *pval = pquote(fptr,s_bquote); return (TRUE); case ',': /* a comma or comma-at expression */ xlgetc(fptr); if (xlpeek(fptr) == '@') { xlgetc(fptr); *pval = pquote(fptr,s_comat); } else *pval = pquote(fptr,s_comma); return (TRUE); case '(': /* a sublist */ *pval = plist(fptr); return (TRUE); case ')': /* closing paren - shouldn't happen */ xlfail("extra right paren"); case '.': /* dot - shouldn't happen */ xlfail("misplaced dot"); case ';': /* a comment */ pcomment(fptr); break; case '"': /* a string */ *pval = pstring(fptr); return (TRUE); default: if (issym(ch)) /* a name */ *pval = pname(fptr); else xlfail("invalid character"); return (TRUE); } } /* pcomment - parse a comment */ LOCAL pcomment(fptr) NODE *fptr; { int ch; /* skip to end of line */ while ((ch = checkeof(fptr)) != EOF && ch != '\n') ; } /* plist - parse a list */ LOCAL NODE *plist(fptr) NODE *fptr; { NODE *oldstk,val,*lastnptr,*nptr,*p; int ch; /* increment the nesting level */ xlplevel += 1; /* create a new stack frame */ oldstk = xlsave(&val,NULL); /* skip the opening paren */ xlgetc(fptr); /* keep appending nodes until a closing paren is found */ lastnptr = NIL; for (lastnptr = NIL; (ch = nextch(fptr)) != ')'; lastnptr = nptr) { /* check for end of file */ if (ch == EOF) badeof(fptr); /* check for a dotted pair */ if (ch == '.') { /* skip the dot */ xlgetc(fptr); /* make sure there's a node */ if (lastnptr == NIL) xlfail("invalid dotted pair"); /* parse the expression after the dot */ if (!parse(fptr,&p)) badeof(fptr); rplacd(lastnptr,p); /* make sure its followed by a close paren */ if (nextch(fptr) != ')') xlfail("invalid dotted pair"); /* done with this list */ break; } /* allocate a new node and link it into the list */ nptr = newnode(LIST); if (lastnptr == NIL) val.n_ptr = nptr; else rplacd(lastnptr,nptr); /* initialize the new node */ if (!parse(fptr,&p)) badeof(fptr); rplaca(nptr,p); } /* skip the closing paren */ xlgetc(fptr); /* restore the previous stack frame */ xlstack = oldstk; /* decrement the nesting level */ xlplevel -= 1; /* return successfully */ return (val.n_ptr); } /* pstring - parse a string */ LOCAL NODE *pstring(fptr) NODE *fptr; { NODE *oldstk,val; char sbuf[STRMAX+1]; int ch,i,d1,d2,d3; /* create a new stack frame */ oldstk = xlsave(&val,NULL); /* skip the opening quote */ xlgetc(fptr); /* loop looking for a closing quote */ for (i = 0; i < STRMAX && (ch = checkeof(fptr)) != '"'; i++) { switch (ch) { case EOF: badeof(fptr); case '\\': switch (ch = checkeof(fptr)) { case 'e': ch = '\033'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; default: if (ch >= '0' && ch <= '7') { d1 = ch - '0'; d2 = checkeof(fptr) - '0'; d3 = checkeof(fptr) - '0'; ch = (d1 << 6) + (d2 << 3) + d3; } break; } } sbuf[i] = ch; } sbuf[i] = 0; /* initialize the node */ val.n_ptr = newnode(STR); val.n_ptr->n_str = strsave(sbuf); val.n_ptr->n_strtype = DYNAMIC; /* restore the previous stack frame */ xlstack = oldstk; /* return the new string */ return (val.n_ptr); } /* pquote - parse a quoted expression */ LOCAL NODE *pquote(fptr,sym) NODE *fptr,*sym; { NODE *oldstk,val,*p; /* create a new stack frame */ oldstk = xlsave(&val,NULL); /* allocate two nodes */ val.n_ptr = newnode(LIST); rplaca(val.n_ptr,sym); rplacd(val.n_ptr,newnode(LIST)); /* initialize the second to point to the quoted expression */ if (!parse(fptr,&p)) badeof(fptr); rplaca(cdr(val.n_ptr),p); /* restore the previous stack frame */ xlstack = oldstk; /* return the quoted expression */ return (val.n_ptr); } /* pname - parse a symbol name */ LOCAL NODE *pname(fptr) NODE *fptr; { char sname[STRMAX+1]; NODE *val; int i; /* get symbol name */ for (i = 0; i < STRMAX && issym(xlpeek(fptr)); ) sname[i++] = xlgetc(fptr); sname[i] = 0; /* check for a number or enter the symbol into the oblist */ return (isnumber(sname,&val) ? val : xlenter(sname,DYNAMIC)); } /* nextch - look at the next non-blank character */ LOCAL int nextch(fptr) NODE *fptr; { int ch; /* return and save the next non-blank character */ while ((ch = xlpeek(fptr)) != EOF && isspace(ch)) xlgetc(fptr); return (ch); } /* checkeof - get a character and check for end of file */ LOCAL int checkeof(fptr) NODE *fptr; { int ch; if ((ch = xlgetc(fptr)) == EOF) badeof(fptr); return (ch); } /* badeof - unexpected eof */ LOCAL badeof(fptr) NODE *fptr; { xlgetc(fptr); xlfail("unexpected EOF"); } /* isnumber - check if this string is a number */ int isnumber(str,pval) char *str; NODE **pval; { char *p; int d; /* initialize */ p = str; d = 0; /* check for a sign */ if (*p == '+' || *p == '-') p++; /* check for a string of digits */ while (isdigit(*p)) p++, d++; /* make sure there was at least one digit and this is the end */ if (d == 0 || *p) return (FALSE); /* convert the string to an integer and return successfully */ *pval = newnode(INT); (*pval)->n_int = atoi(*str == '+' ? ++str : str); return (TRUE); } /* issym - check whether a character if valid in a symbol name */ LOCAL int issym(ch) int ch; { if (ch <= ' ' || ch >= 0177 || ch == '(' || ch == ')' || ch == ';' || ch == ',' || ch == '`' || ch == '"' || ch == '\'') return (FALSE); else return (TRUE); }