/* xlread - xlisp expression input routine */ #ifdef AZTEC #include "stdio.h" #include "setjmp.h" #else #include #include #include #endif #include "xlisp.h" /* external variables */ extern jmp_buf *xljmpbuf; extern struct node *s_quote; extern struct node *xlstack; extern int xlplevel; /* external routines */ extern FILE *fopen(); /* forward declarations */ FORWARD struct node *plist(); FORWARD struct node *pstring(); FORWARD struct node *pquote(); FORWARD struct node *pname(); /* xlload - load a file of xlisp expressions */ int xlload(name) char *name; { jmp_buf loadjmpbuf,*oldjmpbuf; struct node *oldstk,fptr,val; char fname[50]; FILE *fp; /* create a new stack frame */ oldstk = xlsave(&fptr,&val,NULL); /* add the default extension */ strcpy(fname,name); strcat(fname,".lsp"); /* open the file */ if ((fp = fopen(fname,"r")) == NULL) return (FALSE); /* allocate a file node */ fptr.n_ptr = newnode(FPTR); fptr.n_ptr->n_fp = fp; fptr.n_ptr->n_savech = 0; /* setup to trap errors */ oldjmpbuf = xljmpbuf; if (setjmp(xljmpbuf = loadjmpbuf)) { fclose(fp); longjmp(xljmpbuf = oldjmpbuf,1); } /* read and evaluate each expression in the file */ while (xlread(fptr.n_ptr,&val.n_ptr)) xleval(val.n_ptr); /* restore error trapping context and previous stack frame */ xljmpbuf = oldjmpbuf; xlstack = oldstk; /* close the file */ fclose(fp); /* return successfully */ return (TRUE); } /* xlread - read an xlisp expression */ int xlread(fptr,pval) struct node *fptr,**pval; { /* initialize */ xlplevel = 0; /* parse an expression */ return (parse(fptr,pval)); } /* parse - parse an xlisp expression */ LOCAL int parse(fptr,pval) struct 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: return (FALSE); case '\'': /* a quoted expression */ *pval = pquote(fptr); 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) struct node *fptr; { int ch; /* skip to end of line */ while ((ch = checkeof(fptr)) != EOF && ch != '\n') ; } /* plist - parse a list */ LOCAL struct node *plist(fptr) struct node *fptr; { struct node *oldstk,val,*lastnptr,*nptr; 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 = NULL; for (lastnptr = NULL; (ch = nextch(fptr)) != ')'; lastnptr = nptr) { /* check for end of file */ if (ch == EOF) badeof(); /* check for a dotted pair */ if (ch == '.') { /* skip the dot */ xlgetc(fptr); /* make sure there's a node */ if (lastnptr == NULL) xlfail("invalid dotted pair"); /* parse the expression after the dot */ if (!parse(fptr,&lastnptr->n_listnext)) badeof(); /* 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 == NULL) val.n_ptr = nptr; else lastnptr->n_listnext = nptr; /* initialize the new node */ if (!parse(fptr,&nptr->n_listvalue)) badeof(); } /* 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 struct node *pstring(fptr) struct node *fptr; { struct 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(); 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 struct node *pquote(fptr) struct node *fptr; { struct node *oldstk,val; /* create a new stack frame */ oldstk = xlsave(&val,NULL); /* skip the quote character */ xlgetc(fptr); /* allocate two nodes */ val.n_ptr = newnode(LIST); val.n_ptr->n_listvalue = s_quote; val.n_ptr->n_listnext = newnode(LIST); /* initialize the second to point to the quoted expression */ if (!parse(fptr,&val.n_ptr->n_listnext->n_listvalue)) badeof(); /* restore the previous stack frame */ xlstack = oldstk; /* return the quoted expression */ return (val.n_ptr); } /* pname - parse a symbol name */ LOCAL struct node *pname(fptr) struct node *fptr; { char sname[STRMAX+1]; struct node *val; int ch,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) struct 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) struct node *fptr; { int ch; if ((ch = xlgetc(fptr)) == EOF) badeof(); return (ch); } /* badeof - unexpected eof */ LOCAL badeof() { xlfail("unexpected EOF"); } /* isnumber - check if this string is a number */ int isnumber(str,pval) char *str; struct 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 == '(' || ch == ')' || ch == ';' || ch == '.' || ch == '"' || ch == '\'') return (FALSE); else return (TRUE); }