john@x.UUCP (John Woods) (08/27/84)
This represents part 5 of 5 of my modified XLISP. Tear at the dotted line, and run "sh" over it to extract. Thanks to Dave Betz for providing the original XLISP. ________________________________________________________________ echo extract with /bin/sh, not /bin/csh echo x xlread.c sed -n -e 's/^X//p' > xlread.c << '!Funky!Stuff!' X X /* xlread - xlisp expression input routine */ X#define static X#ifdef CI_86 X#include "a:stdio.h" X#include "xlisp.h" X#endif X X#ifdef AZTEC X#include "a:stdio.h" X#include "xlisp.h" X#endif X X#ifdef unix X#include <stdio.h> X#include <ctype.h> X#include "xlisp.h" X#endif X X /* global variables */ X Xstruct node *oblist; X X /* external variables */ X Xextern struct node *xlstack; Xextern int (*xlgetc)(); Xextern int xlplevel; X X /* local variables */ X Xstatic int savech; X#ifdef HACK X /* forward declarations (the extern hack is for decusc) */ X Xextern struct node *parse(); Xextern struct node *plist(); Xextern struct node *pstring(); Xextern struct node *pnumber(); Xextern struct node *pquote(); Xextern struct node *pname(); X#endif X#ifdef REALS Xextern struct node *pfloat(); X#endif X X /************************************** X * xlread - read an xlisp expression * X **************************************/ X Xstruct node *xlread() X{ X savech = -1; /* initialize */ X xlplevel = 0; X X return (parse()); /* Parse an expression */ X} X X X /************************************** X * parse - parse an xlisp expression * X **************************************/ X Xstatic struct node *parse() X{ X int ch; X X while (TRUE) /* Look for a node, skipp comments */ X { X switch (ch = nextch()) /* Switch on next character */ X { X case '\'': /* a quoted expression */ X return (pquote()); X X case '(': /* a sublist */ X return (plist()); X X case ')': /* closing paren - shouldn't happen */ X/* xlfail("extra right paren"); */ X getch(); X break; X X case '.': X#ifdef REALS X return (pfloat(0)); /* Real fractional only */ X#else X xlfail("misplaced dot");/* dot - shouldn't happen */ X#endif X X case ';': /* a comment */ X pcomment(); X break; X X case '|': /* a superquoted symbol */ X case '"': /* a string */ X return (pstring(ch)); X X default: X if (!issym(ch)) X xlfail("invalid character"); X /* else ... */ X case '\\': X return (pword()); X } X } X} X X X /******************************* X * pcomment - parse a comment * X *******************************/ X Xstatic pcomment() X{ X while (getch() != '\n') /* Skip to end of line */ X ; X} X X X /************************* X * plist - parse a list * X *************************/ X Xstatic struct node *plist() X{ X struct node *oldstk,val,*lastnptr,*nptr; X int ch; X X xlplevel += 1; /* Increment nesting level */ X oldstk = xlsave(&val,NULL); /* Create .... */ X savech = -1; /* Skip opend paren */ X X /* keep appending nodes until a closing paren is found */ X for (lastnptr = NULL; (ch = nextch()) > 0 && ch != ')'; lastnptr = nptr) X { X if (ch == '.') /* Check for a dotted pair */ X { X savech = -1; /* Skip the dot */ X X if (lastnptr == NULL) /* Make sure there is a node */ X xlfail("invalid dotted pair"); X X lastnptr->n_listnext = parse(); /* Parse expression */ X X if (nextch() != ')') /* Check for closing paren */ X xlfail("invalid dotted pair"); X X break; /* Done with this list */ X } X X nptr = newnode(LIST); /* Allocate and link new node */ X if (lastnptr == NULL) X val.n_ptr = nptr; X else X lastnptr->n_listnext = nptr; X X nptr->n_listvalue = parse(); /* Initialize it */ X } X X savech = -1; /* Skip the closing paren */ X X xlstack = oldstk; /* Restore previous stack frame */ X xlplevel -= 1; /* Decrement nesting level */ X X return (val.n_ptr); /* Successful return */ X} X X /***************************** X * pstring - parse a string * X *****************************/ X Xstatic struct node *pstring(term) X int term; /* terminator */ X{ X struct node *oldstk,val; X char sbuf[STRMAX+1]; X int ch,i,d1,d2,d3; X X oldstk = xlsave(&val,NULL); /* Create a new stack frame */ X savech = -1; /* Skip opening quote */ X X /* loop looking for a closing qte */ X for (i = 0; i < STRMAX && (ch = getch()) != term; i++) X { X switch (ch) X { X case '\\': X switch (ch = getch()) X { X case 'e': X ch = '\033'; X break; X X case 'n': X ch = '\n'; X break; X X case 'r': X ch = '\r'; X break; X X case 't': X ch = '\t'; X break; X X case '0': X case '1': X case '2': X case '3': X case '4': X case '5': X case '6': X case '7': X d1 = ch - '0'; X while (((ch = getch()) >= '0') && (ch < '8')) X d1 = d1 <<3 + (ch - '0'); X ch = d1; X break; X X default: X break; X } X } X sbuf[i] = ch; X } X sbuf[i] = 0; X X if (term == '|') X return xlenter(sbuf); X X val.n_ptr = newnode(STR); /* Initialize the node */ X val.n_ptr->n_str = strsave(sbuf); X X xlstack = oldstk; /* Restore old stack frame */ X return (val.n_ptr); /* .. and return */ X} X X X#ifdef REALS X /******************************************************** X * pfloat - parse the fractional part of a real number * X ********************************************************/ X Xstatic struct node *pfloat(i) X int i; X{ X struct node *val; X int ch; X long float rval = (float) ((i<0) ? -i : i), fp= 1; X X for ( ; isdigit(ch = thisch()); savech = -1) X rval = rval + (ch - '0')/(fp *= 10); X X if (issym(ch)) /* ensure correct termination */ X xlfail("badly formed number"); X X val = newnode(REAL); /* Initialze the new node */ X val->n_real = (i < 0) ? -rval : rval; X X return (val); X} X#endif X X /***************************** X * pnumber - parse a number * X *****************************/ X Xstruct node *pnumber(buf) X char *buf; X{ X struct node *val; X int ch,ival = 0, sign = 1; X X if (*buf == '+') buf++; X else if (*buf == '-') sign = -1, buf++; X X for ( ; isdigit(*buf); ++buf) /* loop while digits */ X ival = ival * 10 + *buf - '0'; X X#ifdef REALS X if (thisch() == '.') X { X savech = -1; X return pfloat(sign*ival); X } X#endif X X val = newnode(INT); /* Initialze the new node */ X val->n_int = sign * ival; X X return (val); X} X X /* isallnumeric - is all of this char buffer numeric? */ Xint isallnumeric(s) char *s; X{ X if (*s == '+' || *s == '-') { X s++; X if (!*s) return 0; X } X while (*s) if (!isdigit(*s)) return 0; else s++; X return 1; X} X X /*************************************************** X * xlenter - enter a symbol into the symbol table * X ***************************************************/ X Xstruct node *xlenter(sname) X char *sname; X{ X struct node *sptr; X X if (strcmp(sname,"nil") == 0) /* Check for nil */ X return (NULL); X X if (oblist == NULL) /* Create oblist if required */ X { X oblist = newnode(SYM); X oblist->n_symname = strsave("oblist"); X oblist->n_symvalue = newnode(LIST); X oblist->n_symvalue->n_listvalue = oblist; X } X X sptr = oblist->n_symvalue; /* check for symbol already in table */ X while (sptr != NULL) X { X if (sptr->n_listvalue == NULL) X { X printf("bad oblist\n"); X sptr = oblist->n_symvalue; X while (sptr != NULL) X { X if (sptr->n_listvalue == NULL) X xlfail("end oblist"); X printf("\n%s",sptr->n_listvalue->n_symname); X sptr = sptr->n_listnext; X } X } X else if (sptr->n_listvalue->n_symname == NULL) X printf("bad oblist symbol\n"); X else X if (strcmp(sptr->n_listvalue->n_symname,sname) == 0) X return (sptr->n_listvalue); X sptr = sptr->n_listnext; X } X X sptr = newnode(LIST); /* Create and link new symbol */ X sptr->n_listnext = oblist->n_symvalue; X oblist->n_symvalue = sptr; X sptr->n_listvalue = newnode(SYM); X sptr->n_listvalue->n_symname = strsave(sname); X X return (sptr->n_listvalue); X} X X X /*************************************** X * pquote - parse a quoted expression * X ***************************************/ X Xstatic struct node *pquote() X{ X struct node *oldstk,val; X X oldstk = xlsave(&val,NULL); /* Create new stack frame */ X savech = -1; /* Skip the quote character */ X X val.n_ptr = newnode(LIST); /* Allocate two new nodes */ X val.n_ptr->n_listvalue = xlenter("quote"); X val.n_ptr->n_listnext = newnode(LIST); X val.n_ptr->n_listnext->n_listvalue = parse(); X X xlstack = oldstk; /* Restore old stack frame */ X return (val.n_ptr); /* .. return quoted expression */ X} X X X /******************************************** X * pword - parse a symbol name or a number * X *********************************************/ X Xstruct node *pword() X{ X char sname[STRMAX+1]; X int ch,i, quoted = 0; X X /* get symbol name */ X for (i = 0; i < STRMAX && (issym(ch = thisch()) || ch == '\\'); i++) X { if (ch == '\\') X { quoted = 1; X savech = -1; X } X sname[i] = getch(); X } X sname[i] = 0; X X if (!quoted && isallnumeric(sname)) X return (pnumber(sname)); /* create number */ X X return (xlenter(sname)); /* Create symbol */ X} X X X /************************************************** X * nextch - look at the next non-blank character * X **************************************************/ X Xstatic int nextch() X{ X while (isspace(thisch())) /* Find non blank character */ X savech = -1; X X return savech; /* .. and return it */ X} X X X /******************************************* X * thisch - look at the current character * X *******************************************/ X Xstatic int thisch() X{ X return (savech = getch()); /* return and save next character */ X} X X X /*********************************** X * getch - get the next character * X ***********************************/ X Xstatic int getch() X{ X int ch; X X if ((ch = savech) >= 0) /* Check for saved character */ X savech = -1; X else X ch = (*xlgetc)(); X X if (ch == EOF) /* Check for abort character */ X if (xlplevel > 0) X { X putchar('\n'); X xltin(FALSE); X xlfail("input aborted"); X } X else X exit(); X X return (ch); /* Return char */ X} X X X /**************************************************************** X * issym - check whether a character if valid in a symbol name * X ****************************************************************/ X Xstatic int issym(ch) X int ch; X{ X if (isspace(ch)) X return FALSE; X X return (index("();.\"'|\\",ch) == 0); X X} !Funky!Stuff! echo x xlstr.c sed -n -e 's/^X//p' > xlstr.c << '!Funky!Stuff!' X /* xlstr - xlisp string builtin functions */ X X#ifdef CI_86 X#include "a:stdio.h" X#include "xlisp.h" X#endif X X#ifdef AZTEC X#include "a:stdio.h" X#include "xlisp.h" X#endif X X#ifdef unix X#include <stdio.h> X#include "xlisp.h" X#endif X X X /* external variables */ X Xextern struct node *xlstack; X X X /* external procedures */ X Xextern char *strcat(); X X X /********************************* X * xstrlen - length of a string * X *********************************/ X Xstatic struct node *xstrlen(args) X struct node *args; X{ X struct node *oldstk,arg,*val; X int total; X X oldstk = xlsave(&arg,NULL); X arg.n_ptr = args; X total = 0; X X while (arg.n_ptr != NULL) X total += strlen(xlmatch(STR,&arg.n_ptr)->n_str); X X xlstack = oldstk; X X val = newnode(INT); X val->n_int = total; X X return (val); X} X X X /********************************************* X * xstrcat - concatenate a bunch of strings * X *********************************************/ X X Xstatic struct node *xstrcat(args) X struct node *args; X{ X/* this routine does it the dumb way -- one at a time */ X struct node *oldstk,arg,val,rval; X int newlen; X char *result,*argstr,*newstr; X X oldstk = xlsave(&arg,&val,&rval,NULL); X arg.n_ptr = args; X rval.n_ptr = newnode(STR); X rval.n_ptr->n_str = result = stralloc(0); X *result = 0; X X while (arg.n_ptr != NULL) { X val.n_ptr = xlmatch(STR,&arg.n_ptr); X argstr = val.n_ptr->n_str; X newlen = strlen(result) + strlen(argstr); X newstr = stralloc(newlen); X strcpy(newstr,result); X strfree(result); X rval.n_ptr->n_str = result = strcat(newstr,argstr); X } X X xlstack = oldstk; X return (rval.n_ptr); X} X X X /******************************** X * substr - return a substring * X ********************************/ X Xstatic struct node *substr(args) X struct node *args; X{ X struct node *oldstk,arg,src,val; X int start,forlen,srclen; X char *srcptr,*dstptr; X X oldstk = xlsave(&arg,&src,&val,NULL); X arg.n_ptr = args; X X src.n_ptr = xlmatch(STR,&arg.n_ptr); X srcptr = src.n_ptr->n_str; X srclen = strlen(srcptr); X X start = xlmatch(INT,&arg.n_ptr)->n_int; X X if (arg.n_ptr != NULL) X forlen = xlmatch(INT,&arg.n_ptr)->n_int; X else X forlen = srclen; /* use len and fix below */ X X xllastarg(arg.n_ptr); X X if (start + forlen > srclen) X forlen = srclen - start + 1; X X if (start > srclen) X { X start = 1; X forlen = 0; X } X X val.n_ptr = newnode(STR); X val.n_ptr->n_str = dstptr = stralloc(forlen); X X for (srcptr += start-1; forlen--; *dstptr++ = *srcptr++) X ; X X *dstptr = 0; X X xlstack = oldstk; X return (val.n_ptr); X} X X X /******************************* X * ascii - return ascii value * X *******************************/ X Xstatic struct node *ascii(args) X struct node *args; X{ X struct node *oldstk,val; X X oldstk = xlsave(&val,NULL); X X val.n_ptr = newnode(INT); X val.n_ptr->n_int = *(xlmatch(STR,&args)->n_str); X X xllastarg(args); X X xlstack = oldstk; X return (val.n_ptr); X} X X X /*********************************************************** X * chr - convert an INT into a one character ascii string * X ***********************************************************/ X Xstatic struct node *chr(args) X struct node *args; X{ X struct node *oldstk,val; X char *sptr; X X oldstk = xlsave(&val,NULL); X X val.n_ptr = newnode(STR); X val.n_ptr->n_str = sptr = stralloc(1); X *sptr++ = xlmatch(INT,&args)->n_int; X *sptr = 0; X X xllastarg(args); X X xlstack = oldstk; X return (val.n_ptr); X} X X X /************************************************** X * xatoi - convert an ascii string to an integer * X **************************************************/ X Xstatic struct node *xatoi(args) X struct node *args; X{ X struct node *val; X int n; X X n = atoi(xlmatch(STR,&args)->n_str); X X xllastarg(args); X X val = newnode(INT); X val->n_int = n; X return (val); X} X X X /************************************************** X * xitoa - convert an integer to an ascii string * X **************************************************/ X Xstatic struct node *xitoa(args) X struct node *args; X{ X struct node *val; X char buf[20]; X X sprintf(buf,"%d",xlmatch(INT,&args)->n_int); X X xllastarg(args); X X val = newnode(STR); X val->n_str = strsave(buf); X return (val); X} X X X /************************************************** X * xlsinit - xlisp string initialization routine * X **************************************************/ X Xxlsinit() X{ X xlsubr("strlen",xstrlen); X xlsubr("strcat",xstrcat); X xlsubr("substr",substr); X xlsubr("ascii",ascii); X xlsubr("chr", chr); X xlsubr("atoi",xatoi); X xlsubr("itoa",xitoa); X} !Funky!Stuff! echo x xlsubr.c sed -n -e 's/^X//p' > xlsubr.c << '!Funky!Stuff!' X /* xlfsubr - xlisp builtin functions */ X#ifdef CI_86 X#include "a:stdio.h" X#include "xlisp.h" X#endif X X#ifdef AZTEC X#include "a:stdio.h" X#include "xlisp.h" X#endif X X#ifdef unix X#include <stdio.h> X#include "xlisp.h" X#endif X X /* external variables */ X Xextern int (*xlgetc)(); Xextern struct node *xlstack; X X /* global variables */ X Xstruct node *Lambda, *Fexpr, *Macro; Xstruct node *Subrprop, *Fsubrprop, *Exprop, *Fexprop, *Macprop; X X /* local variables */ Xstatic char *sgetptr; Xstatic struct node *t; X X /*************************************** X * xlsubr - define a builtin function * X ***************************************/ X Xxlsubr(sname,subr) X char *sname; struct node *(*subr)(); X{ X struct node *sym, *newsubr; X X sym = xlenter(sname); /* Enter the symbol */ X X (newsubr = newnode(SUBR))->n_subr = subr; X xlputprop(sym,newsubr,Subrprop); X} X X X /********************************************* X * xlfsubr - define a builtin funny function * X **********************************************/ X Xxlfsubr(sname,fsubr) X char *sname; struct node *(*fsubr)(); X{ X struct node *sym, *newsubr; X X sym = xlenter(sname); /* Enter the symbol */ X X (newsubr = newnode(FSUBR))->n_subr = fsubr; X xlputprop(sym,newsubr,Fsubrprop); X} X X X /********************************************** X * xlsvar - define a builtin string variable * X **********************************************/ X Xxlsvar(sname,str) X char *sname,*str; X{ X struct node *sym; X X sym = xlenter(sname); /* Enter the symbol */ X X sym->n_symvalue = newnode(STR); /* Initialize the value */ X sym->n_symvalue->n_str = strsave(str); X} X X X /********************************** X * xlarg - get the next argument * X **********************************/ X Xstruct node *xlarg(pargs) X struct node **pargs; X{ X struct node *arg; X X if (*pargs == NULL) /* Does argument exist ? */ X xlfail("too few arguments"); X X arg = (*pargs)->n_listvalue; /* If so get its value */ X *pargs = (*pargs)->n_listnext; /* and mov arg pointer ahead */ X X return (arg); X} X X X /************************************************* X * xlmatch - get an argument and match its type * X *************************************************/ X Xstruct node *xlmatch(type,pargs) X int type; struct node **pargs; X{ X struct node *arg; X X arg = xlarg(pargs); /* Get the argument */ X if (type == LIST) /* Check its type */ X { X if (arg != NULL && arg->n_type != LIST) X xlfail("bad argument type"); X } X else X { X if (arg == NULL || arg->n_type != type) X xlfail("bad argument type"); X } X X return (arg); X} X X X /**************************************************** X * xlevarg - get the next argument and evaluate it * X ****************************************************/ X Xstruct node *xlevarg(pargs) X struct node **pargs; X{ X struct node *oldstk,val; X X oldstk = xlsave(&val,NULL); /* Creat new stack frame */ X X val.n_ptr = xlarg(pargs); /* Get and evaluate the argument */ X val.n_ptr = xleval(val.n_ptr); X X xlstack = oldstk; /* Restore old stack frame */ X return (val.n_ptr); X} X X X /************************************************************* X * xlevmatch - get an evaluated argument and match its type * X *************************************************************/ X Xstruct node *xlevmatch(type,pargs) X int type; struct node **pargs; X{ X struct node *arg; X X arg = xlevarg(pargs); /* Get argument and check type */ X if (type == LIST) X { X if (arg != NULL && arg->n_type != LIST) X xlfail("bad argument type"); X } X else X { X if (arg == NULL || arg->n_type != type) X xlfail("bad argument type"); X } X X return (arg); X} X X X /********************************************************************** X * xllastarg - make sure the remainder of the argument list is empty * X **********************************************************************/ X Xxllastarg(args) X struct node *args; X{ X if (args != NULL) X xlfail("too many arguments"); X} X X X /**************************************** X * assign - assign a value to a symbol * X ****************************************/ X Xstatic assign(sym,val) X struct node *sym,*val; X{ X struct node *lptr; X X if ((lptr = xlobsym(sym)) != NULL) /* Check for a current object */ X lptr->n_listvalue = val; X else X sym->n_symvalue = val; X} X X X /******************************* X * set - builtin function set * X *******************************/ X Xstatic struct node *set(args) X struct node *args; X{ X struct node *oldstk,arg,sym,val; X X oldstk = xlsave(&arg,&sym,&val,NULL); /* Create new stack frame */ X arg.n_ptr = args; X X sym.n_ptr = xlmatch(SYM,&arg.n_ptr); /* Get symbol */ X val.n_ptr = xlarg(&arg.n_ptr); X xllastarg(arg.n_ptr); X assign(sym.n_ptr,val.n_ptr); X X xlstack = oldstk; /* Restore old stack frame */ X return (val.n_ptr); X} X X X /********************************* X * setq - builtin function setq * X *********************************/ X Xstatic struct node *setq(args) X struct node *args; X{ X struct node *oldstk,arg,sym,val; X X oldstk = xlsave(&arg,&sym,&val,NULL); /* Create new stack frame */ X arg.n_ptr = args; X X sym.n_ptr = xlmatch(SYM,&arg.n_ptr); /* get symbol */ X val.n_ptr = xlevarg(&arg.n_ptr); X xllastarg(arg.n_ptr); X assign(sym.n_ptr,val.n_ptr); X X xlstack = oldstk; /* Restore old stack frame */ X return (val.n_ptr); X} X X X /************************************ X * load - direct input from a file * X ************************************/ X Xstatic struct node *load(args) X struct node *args; X{ X struct node *fname; X X fname = xlmatch(STR,&args); /* Get file name */ X xllastarg(args); X X xlfin(fname->n_str); X X return (fname); X} X X X /*********************************** X * defun - builtin function defun * X ***********************************/ X Xstatic struct node *defun(args) X struct node *args; X{ X struct node *oldstk,arg,sym,fargs,fun, *p; X int macro = 0, fexpr = 0; X X /* create a new stack frame */ X oldstk = xlsave(&arg,&sym,&fargs,&fun,NULL); X X /* initialize */ X arg.n_ptr = args; X X /* get the function symbol */ X sym.n_ptr = xlmatch(SYM,&arg.n_ptr); X X /* get the formal argument list */ X fargs.n_ptr = xlarg(&arg.n_ptr); X X /* is this a magic form? */ X if ((xeq(fargs.n_ptr,Macro) && (macro=1)) X || (xeq(fargs.n_ptr,Fexpr) && (fexpr=1))) X { fargs.n_ptr = xlmatch(LIST,&arg.n_ptr); X } else X if (fargs.n_ptr->n_type != LIST X && fargs.n_ptr->n_type != SYM) xlfail("bad argument type"); X X /* create a new function definition */ X fun.n_ptr = newnode(LIST); X fun.n_ptr->n_listvalue = Lambda; X p = fun.n_ptr->n_listnext = newnode(LIST); X p->n_listvalue = fargs.n_ptr; X p->n_listnext = arg.n_ptr; X X /* make the symbol point to a new function definition */ X xlputprop(sym.n_ptr,fun.n_ptr,(macro?Macprop: (fexpr?Fexprop:Exprop))); X X /* restore the previous stack frame */ X xlstack = oldstk; X X /* return the function symbol */ X return (sym.n_ptr); X} X X /****************************************** X * sgetc - get a character from a string * X ******************************************/ X Xstatic int sgetc() X{ X if (*sgetptr == 0) X return (-1); X else X return (*sgetptr++); X} X X /****************************** X * read - read an expression * X ******************************/ X Xstatic struct node *read(args) X struct node *args; X{ X struct node *val; X int (*oldgetc)(); X X /* save the old input stream */ X oldgetc = xlgetc; X X /* get the string or file pointer */ X if (args != NULL) { X sgetptr = xlmatch(STR,&args)->n_str; X xlgetc = sgetc; X } X X /* make sure there aren't any more arguments */ X xllastarg(args); X X val = xlread(); X xlgetc = oldgetc; X X return (val); X} X X X /************************************ X * fwhile - builtin function while * X ************************************/ X Xstatic struct node *fwhile(args) X struct node *args; X{ X struct node *oldstk,farg,arg,*val; X X /* create a new stack frame */ X oldstk = xlsave(&farg,&arg,NULL); X X /* initialize */ X farg.n_ptr = arg.n_ptr = args; X X /* loop until test fails */ X val = NULL; X for (; TRUE; arg.n_ptr = farg.n_ptr) { X X /* evaluate the test expression */ X if (!testvalue(xlevarg(&arg.n_ptr))) X break; X X /* evaluate each remaining argument */ X while (arg.n_ptr != NULL) X val = xlevarg(&arg.n_ptr); X } X X /* restore the previous stack frame */ X xlstack = oldstk; X X /* return the last test expression value */ X return (val); X} X X X /************************************** X * frepeat - builtin function repeat * X **************************************/ X Xstatic struct node *frepeat(args) X struct node *args; X{ X struct node *oldstk,farg,arg,*val; X int cnt; X X /* create a new stack frame */ X oldstk = xlsave(&farg,&arg,NULL); X X /* initialize */ X arg.n_ptr = args; X X cnt = xlevmatch(INT,&arg.n_ptr)->n_int; X X /* save the first expression to repeat */ X farg.n_ptr = arg.n_ptr; X X /* loop until test fails */ X val = NULL; X for (; cnt > 0; cnt--) { X X /* evaluate each remaining argument */ X while (arg.n_ptr != NULL) X val = xlevarg(&arg.n_ptr); X X /* restore pointer to first expression */ X arg.n_ptr = farg.n_ptr; X } X X /* restore the previous stack frame */ X xlstack = oldstk; X X /* return the last test expression value */ X return (val); X} X X X /*************************************** X * foreach - builtin function foreach * X ***************************************/ X Xstatic struct node *foreach(args) X struct node *args; X{ X struct node *oldstk,arg,sym,list,code,oldbnd,*val; X X /* create a new stack frame */ X oldstk = xlsave(&arg,&sym,&list,&code,&oldbnd,NULL); X X /* initialize */ X arg.n_ptr = args; X X /* get the symbol to bind to each list element */ X sym.n_ptr = xlmatch(SYM,&arg.n_ptr); X X /* save the old binding of the symbol */ X oldbnd.n_ptr = sym.n_ptr->n_symvalue; X X /* get the list to iterate over */ X list.n_ptr = xlevmatch(LIST,&arg.n_ptr); X X /* save the pointer to the code */ X code.n_ptr = arg.n_ptr; X X /* loop until test fails */ X val = NULL; X while (list.n_ptr != NULL) { X X /* check the node type */ X if (list.n_ptr->n_type != LIST) X xlfail("bad node type in list"); X X /* bind the symbol to the list element */ X sym.n_ptr->n_symvalue = list.n_ptr->n_listvalue; X X /* evaluate each remaining argument */ X while (arg.n_ptr != NULL) X val = xlevarg(&arg.n_ptr); X X /* point to the next list element */ X list.n_ptr = list.n_ptr->n_listnext; X X /* restore the pointer to the code */ X arg.n_ptr = code.n_ptr; X } X X /* restore the previous stack frame */ X xlstack = oldstk; X X /* restore the old binding of the symbol */ X sym.n_ptr->n_symvalue = oldbnd.n_ptr; X X /* return the last test expression value */ X return (val); X} X X X /****************************** X * fif - builtin function if * X ******************************/ X Xstatic struct node *fif(args) X struct node *args; X{ X struct node *oldstk,arg,testexpr,thenexpr,elseexpr,*val; X int dothen; X X /* create a new stack frame */ X oldstk = xlsave(&arg,&testexpr,&thenexpr,&elseexpr,NULL); X X /* initialize */ X arg.n_ptr = args; X X /* evaluate the test expression */ X testexpr.n_ptr = xlevarg(&arg.n_ptr); X X /* get the then clause */ X thenexpr.n_ptr = xlmatch(LIST,&arg.n_ptr); X X /* get the else clause */ X if (arg.n_ptr != NULL) X elseexpr.n_ptr = xlmatch(LIST,&arg.n_ptr); X else X elseexpr.n_ptr = NULL; X X /* make sure there aren't any more arguments */ X xllastarg(arg.n_ptr); X X /* figure out which expression to evaluate */ X dothen = testvalue(testexpr.n_ptr); X X /* default the result value to the value of the test expression */ X val = testexpr.n_ptr; X X /* evaluate the appropriate clause */ X if (dothen) X while (thenexpr.n_ptr != NULL) X val = xlevarg(&thenexpr.n_ptr); X else X while (elseexpr.n_ptr != NULL) X val = xlevarg(&elseexpr.n_ptr); X X /* restore the previous stack frame */ X xlstack = oldstk; X X /* return the last value */ X return (val); X} X X X /**************************************************** X * quote - builtin function to quote an expression * X ****************************************************/ X Xstatic struct node *quote(args) X struct node *args; X{ X /* make sure there is exactly one argument */ X if (args == NULL || args->n_listnext != NULL) X xlfail("incorrect number of arguments"); X X /* return the quoted expression */ X return (args->n_listvalue); X} X X X /***************************** X * fexit - get out of xlisp * X *****************************/ X Xfexit() X{ X exit(); X} X X X /*********************************************** X * testvalue - test a value for true or false * X ***********************************************/ X Xstatic int testvalue(val) X struct node *val; X{ X /* check for a nil value */ X if (val == NULL) X return (FALSE); X X /* check the value type */ X switch (val->n_type) { X case INT: X return (val->n_int != 0); X X case STR: X return (strlen(val->n_str) != 0); X X default: X return (TRUE); X } X} X Xstatic struct node *comment() { return t; } X X /****************************************** X * xlinit - xlisp initialization routine * X ******************************************/ X Xxlinit() X{ X /* enter a copyright notice into the oblist */ X xlenter("Copyright-1983-by-David-Betz"); X t = xlenter("t"); X Lambda = xlenter("lambda"); X Fexpr = xlenter("fexpr"); X Macro = xlenter("macro"); X Subrprop = xlenter("SUBR"); X Fsubrprop = xlenter("FSUBR"); X Exprop = xlenter("EXPR"); X Fexprop = xlenter("FEXPR"); X Macprop = xlenter("MACRO"); X X /* enter the builtin functions */ X xlsubr("set",set); X xlfsubr("setq",setq); X xlsubr("load",load); X xlsubr("read",read); X xlfsubr("comment",comment); X xlfsubr("quote",quote); X xlfsubr("while",fwhile); X xlfsubr("repeat",frepeat); X xlfsubr("foreach",foreach); X xlfsubr("defun",defun); X xlfsubr("if",fif); X xlfsubr("exit",fexit); X} !Funky!Stuff! exit 0 -- John Woods, Charles River Data Systems, Framingham MA, (617) 626-1114 ...!decvax!frog!john, ...!mit-eddie!jfw, JFW@MIT-XX.ARPA I have absolutely nothing clever to say in this signature.