home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
254b.lha
/
AMXLISP_v2.0
/
src
/
XLREAD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-05-09
|
17KB
|
812 lines
/* xlread - xlisp expression input routine */
/* Copyright (c) 1985, by David Michael Betz
All Rights Reserved
Permission is granted for unrestricted non-commercial use */
#include "xlisp.h"
/* symbol parser modes */
#define DONE 0
#define NORMAL 1
#define ESCAPE 2
/* external variables */
extern LVAL s_stdout,true,s_dot;
extern LVAL s_quote,s_function,s_bquote,s_comma,s_comat;
extern LVAL s_rtable,k_wspace,k_const,k_nmacro,k_tmacro;
extern LVAL k_sescape,k_mescape;
extern char buf[];
/* external routines */
extern FILE *osaopen();
extern double atof();
extern ITYPE;
#define WSPACE "\t \f\r\n"
#define CONST1 "!$%&*+-./0123456789:<=>?@[]^_{}~"
#define CONST2 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
/* forward declarations */
FORWARD LVAL callmacro();
FORWARD LVAL psymbol(),punintern();
FORWARD LVAL pnumber(),pquote(),plist(),pvector();
FORWARD LVAL tentry();
/* xlload - load a file of xlisp expressions */
int xlload(fname,vflag,pflag)
char *fname; int vflag,pflag;
{
char fullname[STRMAX+1];
LVAL fptr,expr;
CONTEXT cntxt;
FILE *fp;
int sts;
/* protect some pointers */
xlstkcheck(2);
xlsave(fptr);
xlsave(expr);
/* default the extension */
if (needsextension(fname)) {
strcpy(fullname,fname);
strcat(fullname,".lsp");
fname = fullname;
}
/* allocate a file node */
fptr = cvfile(NULL);
/* open the file */
if ((fp = osaopen(fname,"r")) == NULL) {
xlpopn(2);
return (FALSE);
}
setfile(fptr,fp);
/* print the information line */
if (vflag)
{ sprintf(buf,"; loading \"%s\"\n",fname); stdputstr(buf); }
/* 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,&expr,FALSE)) {
expr = xleval(expr);
if (pflag)
stdprint(expr);
}
sts = TRUE;
}
xlend(&cntxt);
/* close the file */
osclose(getfile(fptr));
setfile(fptr,NULL);
/* restore the stack */
xlpopn(2);
/* return status */
return (sts);
}
/* xlread - read an xlisp expression */
int xlread(fptr,pval,rflag)
LVAL fptr,*pval; int rflag;
{
int sts;
/* read an expression */
while ((sts = readone(fptr,pval)) == FALSE)
;
/* return status */
return (sts == EOF ? FALSE : TRUE);
}
/* readone - attempt to read a single expression */
int readone(fptr,pval)
LVAL fptr,*pval;
{
LVAL val,type;
int ch;
/* get a character and check for EOF */
if ((ch = xlgetc(fptr)) == EOF)
return (EOF);
/* handle white space */
if ((type = tentry(ch)) == k_wspace)
return (FALSE);
/* handle symbol constituents */
else if (type == k_const) {
xlungetc(fptr,ch);
*pval = psymbol(fptr);
return (TRUE);
}
/* handle single and multiple escapes */
else if (type == k_sescape || type == k_mescape) {
xlungetc(fptr,ch);
*pval = psymbol(fptr);
return (TRUE);
}
/* handle read macros */
else if (consp(type)) {
if ((val = callmacro(fptr,ch)) && consp(val)) {
*pval = car(val);
return (TRUE);
}
else
return (FALSE);
}
/* handle illegal characters */
else
xlerror("illegal character",cvfixnum((FIXTYPE)ch));
}
/* rmhash - read macro for '#' */
LVAL rmhash()
{
LVAL fptr,mch,val;
int escflag,ch;
/* protect some pointers */
xlsave1(val);
/* get the file and macro character */
fptr = xlgetfile();
mch = xlgachar();
xllastarg();
/* make the return value */
val = consa(NIL);
/* check the next character */
switch (ch = xlgetc(fptr)) {
case '\'':
rplaca(val,pquote(fptr,s_function));
break;
case '(':
rplaca(val,pvector(fptr));
break;
case 'b':
case 'B':
rplaca(val,pnumber(fptr,2));
break;
case 'o':
case 'O':
rplaca(val,pnumber(fptr,8));
break;
case 'x':
case 'X':
rplaca(val,pnumber(fptr,16));
break;
case '\\':
xlungetc(fptr,ch);
pname(fptr,&escflag);
ch = buf[0];
if (strlen(buf) > 1) {
upcase(buf);
if (strcmp(buf,"NEWLINE") == 0)
ch = '\n';
else if (strcmp(buf,"SPACE") == 0)
ch = ' ';
else
xlerror("unknown character name",cvstring(buf));
}
rplaca(val,cvchar(ch));
break;
case ':':
rplaca(val,punintern(fptr));
break;
case '|':
pcomment(fptr);
val = NIL;
break;
default:
xlerror("illegal character after #",cvfixnum((FIXTYPE)ch));
}
/* restore the stack */
xlpop();
/* return the value */
return (val);
}
/* rmquote - read macro for '\'' */
LVAL rmquote()
{
LVAL fptr,mch;
/* get the file and macro character */
fptr = xlgetfile();
mch = xlgachar();
xllastarg();
/* parse the quoted expression */
return (consa(pquote(fptr,s_quote)));
}
/* rmdquote - read macro for '"' */
LVAL rmdquote()
{
unsigned char buf[STRMAX+1],*p,*sptr;
LVAL fptr,str,newstr,mch;
int len,blen,ch,d2,d3;
/* protect some pointers */
xlsave1(str);
/* get the file and macro character */
fptr = xlgetfile();
mch = xlgachar();
xllastarg();
/* loop looking for a closing quote */
len = blen = 0; p = buf;
while ((ch = checkeof(fptr)) != '"') {
/* handle escaped characters */
switch (ch) {
case '\\':
switch (ch = checkeof(fptr)) {
case 't':
ch = '\011';
break;
case 'n':
ch = '\012';
break;
case 'f':
ch = '\014';
break;
case 'r':
ch = '\015';
break;
default:
if (ch >= '0' && ch <= '7') {
d2 = checkeof(fptr);
d3 = checkeof(fptr);
if (d2 < '0' || d2 > '7'
|| d3 < '0' || d3 > '7')
xlfail("invalid octal digit");
ch -= '0'; d2 -= '0'; d3 -= '0';
ch = (ch << 6) | (d2 << 3) | d3;
}
break;
}
}
/* check for buffer overflow */
if (blen >= STRMAX) {
newstr = newstring(len + STRMAX + 1);
sptr = getstring(newstr); *sptr = '\0';
if (str) strcat(sptr,getstring(str));
*p = '\0'; strcat(sptr,buf);
p = buf; blen = 0;
len += STRMAX;
str = newstr;
}
/* store the character */
*p++ = ch; ++blen;
}
/* append the last substring */
if (str == NIL || blen) {
newstr = newstring(len + blen + 1);
sptr = getstring(newstr); *sptr = '\0';
if (str) strcat(sptr,getstring(str));
*p = '\0'; strcat(sptr,buf);
str = newstr;
}
/* restore the stack */
xlpop();
/* return the new string */
return (consa(str));
}
/* rmbquote - read macro for '`' */
LVAL rmbquote()
{
LVAL fptr,mch;
/* get the file and macro character */
fptr = xlgetfile();
mch = xlgachar();
xllastarg();
/* parse the quoted expression */
return (consa(pquote(fptr,s_bquote)));
}
/* rmcomma - read macro for ',' */
LVAL rmcomma()
{
LVAL fptr,mch,sym;
int ch;
/* get the file and macro character */
fptr = xlgetfile();
mch = xlgachar();
xllastarg();
/* check the next character */
if ((ch = xlgetc(fptr)) == '@')
sym = s_comat;
else {
xlungetc(fptr,ch);
sym = s_comma;
}
/* make the return value */
return (consa(pquote(fptr,sym)));
}
/* rmlpar - read macro for '(' */
LVAL rmlpar()
{
LVAL fptr,mch;
/* get the file and macro character */
fptr = xlgetfile();
mch = xlgachar();
xllastarg();
/* make the return value */
return (consa(plist(fptr)));
}
/* rmrpar - read macro for ')' */
LVAL rmrpar()
{
xlfail("misplaced right paren");
}
/* rmsemi - read macro for ';' */
LVAL rmsemi()
{
LVAL fptr,mch;
int ch;
/* get the file and macro character */
fptr = xlgetfile();
mch = xlgachar();
xllastarg();
/* skip to end of line */
while ((ch = xlgetc(fptr)) != EOF && ch != '\n')
;
/* return nil (nothing read) */
return (NIL);
}
/* pcomment - parse a comment delimited by #| and |# */
LOCAL pcomment(fptr)
LVAL fptr;
{
int lastch,ch,n;
/* look for the matching delimiter (and handle nesting) */
for (n = 1, lastch = -1; n > 0 && (ch = xlgetc(fptr)) != EOF; ) {
if (lastch == '|' && ch == '#')
{ --n; ch = -1; }
else if (lastch == '#' && ch == '|')
{ ++n; ch = -1; }
lastch = ch;
}
}
/* pnumber - parse a number */
LOCAL LVAL pnumber(fptr,radix)
LVAL fptr; int radix;
{
int digit,ch;
long num;
for (num = 0L; (ch = xlgetc(fptr)) != EOF; ) {
if (islower(ch)) ch = toupper(ch);
if (!('0' <= ch && ch <= '9') && !('A' <= ch && ch <= 'F'))
break;
if ((digit = (ch <= '9' ? ch - '0' : ch - 'A' + 10)) >= radix)
break;
num = num * (long)radix + (long)digit;
}
xlungetc(fptr,ch);
return (cvfixnum((FIXTYPE)num));
}
/* plist - parse a list */
LOCAL LVAL plist(fptr)
LVAL fptr;
{
LVAL val,expr,lastnptr,nptr;
/* protect some pointers */
xlstkcheck(2);
xlsave(val);
xlsave(expr);
/* keep appending nodes until a closing paren is found */
for (lastnptr = NIL; nextch(fptr) != ')'; )
/* get the next expression */
switch (readone(fptr,&expr)) {
case EOF:
badeof(fptr);
case TRUE:
/* check for a dotted tail */
if (expr == s_dot) {
/* make sure there's a node */
if (lastnptr == NIL)
xlfail("invalid dotted pair");
/* parse the expression after the dot */
if (!xlread(fptr,&expr,TRUE))
badeof(fptr);
rplacd(lastnptr,expr);
/* make sure its followed by a close paren */
if (nextch(fptr) != ')')
xlfail("invalid dotted pair");
}
/* otherwise, handle a normal list element */
else {
nptr = consa(expr);
if (lastnptr == NIL)
val = nptr;
else
rplacd(lastnptr,nptr);
lastnptr = nptr;
}
break;
}
/* skip the closing paren */
xlgetc(fptr);
/* restore the stack */
xlpopn(2);
/* return successfully */
return (val);
}
/* pvector - parse a vector */
LOCAL LVAL pvector(fptr)
LVAL fptr;
{
LVAL list,expr,val,lastnptr,nptr;
int len,ch,i;
/* protect some pointers */
xlstkcheck(2);
xlsave(list);
xlsave(expr);
/* keep appending nodes until a closing paren is found */
for (lastnptr = NIL, len = 0; (ch = nextch(fptr)) != ')'; ) {
/* check for end of file */
if (ch == EOF)
badeof(fptr);
/* get the next expression */
switch (readone(fptr,&expr)) {
case EOF:
badeof(fptr);
case TRUE:
nptr = consa(expr);
if (lastnptr == NIL)
list = nptr;
else
rplacd(lastnptr,nptr);
lastnptr = nptr;
len++;
break;
}
}
/* skip the closing paren */
xlgetc(fptr);
/* make a vector of the appropriate length */
val = newvector(len);
/* copy the list into the vector */
for (i = 0; i < len; ++i, list = cdr(list))
setelement(val,i,car(list));
/* restore the stack */
xlpopn(2);
/* return successfully */
return (val);
}
/* pquote - parse a quoted expression */
LOCAL LVAL pquote(fptr,sym)
LVAL fptr,sym;
{
LVAL val,p;
/* protect some pointers */
xlsave1(val);
/* allocate two nodes */
val = consa(sym);
rplacd(val,consa(NIL));
/* initialize the second to point to the quoted expression */
if (!xlread(fptr,&p,TRUE))
badeof(fptr);
rplaca(cdr(val),p);
/* restore the stack */
xlpop();
/* return the quoted expression */
return (val);
}
/* psymbol - parse a symbol name */
LOCAL LVAL psymbol(fptr)
LVAL fptr;
{
int escflag;
LVAL val;
pname(fptr,&escflag);
return (escflag || !isnumber(buf,&val) ? xlenter(buf) : val);
}
/* punintern - parse an uninterned symbol */
LOCAL LVAL punintern(fptr)
LVAL fptr;
{
int escflag;
pname(fptr,&escflag);
return (xlmakesym(buf));
}
/* pname - parse a symbol/package name */
LOCAL int pname(fptr,pescflag)
LVAL fptr; int *pescflag;
{
int mode,ch,i;
LVAL type;
/* initialize */
*pescflag = FALSE;
mode = NORMAL;
i = 0;
/* accumulate the symbol name */
while (mode != DONE) {
/* handle normal mode */
while (mode == NORMAL)
if ((ch = xlgetc(fptr)) == EOF)
mode = DONE;
else if ((type = tentry(ch)) == k_sescape) {
i = storech(buf,i,checkeof(fptr));
*pescflag = TRUE;
}
else if (type == k_mescape) {
*pescflag = TRUE;
mode = ESCAPE;
}
else if (type == k_const
|| (consp(type) && car(type) == k_nmacro))
i = storech(buf,i,islower(ch) ? toupper(ch) : ch);
else
mode = DONE;
/* handle multiple escape mode */
while (mode == ESCAPE)
if ((ch = xlgetc(fptr)) == EOF)
badeof(fptr);
else if ((type = tentry(ch)) == k_sescape)
i = storech(buf,i,checkeof(fptr));
else if (type == k_mescape)
mode = NORMAL;
else
i = storech(buf,i,ch);
}
buf[i] = 0;
/* check for a zero length name */
if (i == 0)
xlerror("zero length name");
/* unget the last character and return it */
xlungetc(fptr,ch);
return (ch);
}
/* storech - store a character in the print name buffer */
LOCAL int storech(buf,i,ch)
char *buf; int i,ch;
{
if (i < STRMAX)
buf[i++] = ch;
return (i);
}
/* tentry - get a readtable entry */
LVAL tentry(ch)
int ch;
{
LVAL rtable;
rtable = getvalue(s_rtable);
if (!vectorp(rtable) || ch < 0 || ch >= getsize(rtable))
return (NIL);
return (getelement(rtable,ch));
}
/* nextch - look at the next non-blank character */
LOCAL int nextch(fptr)
LVAL fptr;
{
int ch;
/* return and save the next non-blank character */
while ((ch = xlgetc(fptr)) != EOF && isspace(ch))
;
xlungetc(fptr,ch);
return (ch);
}
/* checkeof - get a character and check for end of file */
LOCAL int checkeof(fptr)
LVAL fptr;
{
int ch;
if ((ch = xlgetc(fptr)) == EOF)
badeof(fptr);
return (ch);
}
/* badeof - unexpected eof */
LOCAL badeof(fptr)
LVAL fptr;
{
xlgetc(fptr);
xlfail("unexpected EOF");
}
/* isnumber - check if this string is a number */
int isnumber(str,pval)
char *str; LVAL *pval;
{
int dl,dr;
char *p;
/* initialize */
p = str; dl = dr = 0;
/* check for a sign */
if (*p == '+' || *p == '-')
p++;
/* check for a string of digits */
while (isdigit(*p))
p++, dl++;
/* check for a decimal point */
if (*p == '.') {
p++;
while (isdigit(*p))
p++, dr++;
}
/* check for an exponent */
if ((dl || dr) && *p == 'E') {
p++;
/* check for a sign */
if (*p == '+' || *p == '-')
p++;
/* check for a string of digits */
while (isdigit(*p))
p++, dr++;
}
/* make sure there was at least one digit and this is the end */
if ((dl == 0 && dr == 0) || *p)
return (FALSE);
/* convert the string to an integer and return successfully */
if (pval) {
if (*str == '+') ++str;
if (str[strlen(str)-1] == '.') str[strlen(str)-1] = 0;
*pval = (dr ? cvflonum(atof(str)) : cvfixnum(ICNV(str)));
}
return (TRUE);
}
/* defmacro - define a read macro */
defmacro(ch,type,offset)
int ch; LVAL type; int offset;
{
extern FUNDEF funtab[];
LVAL subr;
subr = cvsubr(funtab[offset].fd_subr,funtab[offset].fd_type,offset);
setelement(getvalue(s_rtable),ch,cons(type,subr));
}
/* callmacro - call a read macro */
LVAL callmacro(fptr,ch)
LVAL fptr; int ch;
{
LVAL *newfp;
/* create the new call frame */
newfp = xlsp;
pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
pusharg(cdr(getelement(getvalue(s_rtable),ch)));
pusharg(cvfixnum((FIXTYPE)2));
pusharg(fptr);
pusharg(cvchar(ch));
xlfp = newfp;
return (xlapply(2));
}
/* upcase - translate a string to upper case */
LOCAL upcase(str)
unsigned char *str;
{
for (; *str != '\0'; ++str)
if (islower(*str))
*str = toupper(*str);
}
/* xlrinit - initialize the reader */
xlrinit()
{
LVAL rtable;
char *p;
int ch;
/* create the read table */
rtable = newvector(256);
setvalue(s_rtable,rtable);
/* initialize the readtable */
for (p = WSPACE; ch = *p++; )
setelement(rtable,ch,k_wspace);
for (p = CONST1; ch = *p++; )
setelement(rtable,ch,k_const);
for (p = CONST2; ch = *p++; )
setelement(rtable,ch,k_const);
/* setup the escape characters */
setelement(rtable,'\\',k_sescape);
setelement(rtable,'|', k_mescape);
/* install the read macros */
defmacro('#', k_nmacro,FT_RMHASH);
defmacro('\'',k_tmacro,FT_RMQUOTE);
defmacro('"', k_tmacro,FT_RMDQUOTE);
defmacro('`', k_tmacro,FT_RMBQUOTE);
defmacro(',', k_tmacro,FT_RMCOMMA);
defmacro('(', k_tmacro,FT_RMLPAR);
defmacro(')', k_tmacro,FT_RMRPAR);
defmacro(';', k_tmacro,FT_RMSEMI);
}