home *** CD-ROM | disk | FTP | other *** search
- /* exec.c - execution for spin
- *
- * 16.Oct.87 jimmc Initial definition
- * 21.Oct.87 jimmc Add xexec stuff
- * 22.Oct.87 jimmc Add I and S arg types
- * 4.Nov.87 jimmc Add longjmp stuff, use SPescape
- * 5.Nov.87 jimmc Add SPbool
- * 30.Nov.87 jimmc Lint cleanup
- * 18.Jan.88 jimmc Allow negative default values for I arg format
- */
- /* LINTLIBRARY */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <strings.h>
- #include "goto.h"
- #include "xalloc.h"
- #include "spin.h"
- #include "spinparse.h"
- #include "exec.h"
-
- typedef char *string;
- typedef int (*intfuncp)();
- typedef double (*dblfuncp)();
- typedef string (*strfuncp)();
- typedef SPtoken * (*listfuncp)();
-
- int (*SPxexecp)();
-
- SPsetxexecp(funcp)
- int (*funcp)();
- {
- SPxexecp = funcp;
- }
-
- SPtoken *
- SPnewnil()
- {
- SPtoken *rval;
-
- ALLOCTOKEN(rval)
- rval->type = SPTokNil;
- return rval;
- }
-
- SPtoken *
- SPcopytoken(tk)
- SPtoken *tk;
- {
- SPtoken *newtk, *ltk, *newltk, *prevltk;
-
- if (!tk) return NIL;
- if (tk->type==SPTokList) {
- ALLOCTOKEN(newtk)
- *newtk = *tk;
- newtk->value.l = NIL;
- prevltk = NIL;
- for (ltk=tk->value.l; ltk; ltk=ltk->next) {
- newltk = SPcopytoken(ltk);
- newltk->next = NIL;
- if (!newtk->value.l) newtk->value.l = newltk;
- else prevltk->next = newltk;
- prevltk = newltk;
- }
- return newtk;
- }
- ALLOCTOKEN(newtk)
- *newtk = *tk; /* structure copy */
- if (tk->type==SPTokStr || tk->type==SPTokName) {
- newtk->value.s = XALLOCM(char,strlen(tk->value.s)+1,
- "copy token");
- strcpy(newtk->value.s,tk->value.s);
- }
- return newtk;
- }
-
- SPtoken *
- SPexec(tk)
- SPtoken *tk;
- {
- SPtoken *SPexeclist(), *SPexecname();
-
- #if 0 /* sometimes useful for debugging */
- printf("exec\n");
- SPdumptoken(tk);
- #endif
- if (!tk) return NIL;
- if (tk->type!=SPTokList) { /* treat as constant */
- return SPcopytoken(tk);
- }
- /* It is a list, so we need to examine the first item in the list
- * and base our mode of execution on that item.
- */
- tk = tk->value.l;
- if (!tk) return SPnewnil();
- switch (tk->type) {
- case SPTokList:
- return SPexeclist(tk);
- case SPTokName:
- return SPexecname(tk);
- default:
- SPescape("BadExecList",
- "bad node type %c in list execution",tk->type);
- /* NOTREACHED */
- }
- }
-
- SPtoken *
- SPqexec(tk)
- SPtoken *tk;
- {
- if (!tk) return NIL;
- if (tk->type==SPTokList) return SPexec(tk);
- return tk;
- }
-
- int
- SPbool(tk) /* returns boolean value for token */
- SPtoken *tk;
- {
- if (!tk) return 0;
- switch (tk->type) {
- case SPTokInt:
- return (tk->value.n!=0);
- case SPTokFloat:
- return (tk->value.f!=0.0);
- case SPTokNil:
- return 0;
- case SPTokStr:
- case SPTokName:
- return (tk->value.s!=0 && tk->value.s[0]!=0);
- case SPTokList:
- return (tk->value.l!=0);
- default:
- SPescape("UnknownType","unknown node type %c",tk->type);
- /* NOTREACHED */
- }
- }
-
- int
- SPbooleval(tk)
- SPtoken *tk;
- {
- return SPbool(SPqexec(tk));
- }
-
- SPtoken *
- SPexecname(tk)
- SPtoken *tk;
- {
- char *name;
- SPfuncinfo *finfo, *SPfindfunc();
- SPtoken *tkval;
- int argc;
- int argv[100];
- char *argstr;
- int argtype;
- SPtoken *rval;
- int rtype;
- int t;
- int n;
- float f;
- char *s;
- SPtoken *l;
- int dflti;
- char *dflts, *dflts0;
- double *dptr;
- int (*ifp)();
- double (*ffp)();
- char * (*sfp)();
- SPtoken * (*lfp)();
- static char *badargs="BadArgument";
- static char *toomanyargsdef="TooManyArgsDef";
- static char *badargstr="BadArgstrFormat";
-
- if (!tk || tk->type!=SPTokName) return NIL;
- name = tk->value.s;
- #if 0
- printf("execname %s\n", name);
- #endif
- finfo = SPfindfunc(name);
- if (!finfo) {
- /* maybe it's a user-defined function */
- if (SPxexecp) {
- ALLOCTOKEN(rval)
- t = (*SPxexecp)(name,tk->next,rval);
- if (t) return rval; /* he did it! */
- FREETOKEN(rval)
- }
- SPescape("NoSuchFunction","can't fund function %s",name);
- /* NOTREACHED */
- }
- argc = 0;
- argstr = finfo->args+1;
- tk = tk->next;
- while (*argstr && *argstr!=';') {
- argtype = *argstr;
- switch (argtype) {
- case 'b': /* any type, converted to bool int */
- tkval = SPqexec(tk);
- if (!tkval) {
- SPescape(badargs,"needed arg for %s",name);
- /* NOTREACHED */
- }
- argv[argc++] = SPbool(tkval);
- break;
- case 'i': /* int */
- tkval = SPqexec(tk);
- if (tkval && tkval->type==SPTokInt) {
- argv[argc++] = tkval->value.n;
- }
- else {
- SPescape(badargs,"needed int for %s",name);
- /* NOTREACHED */
- }
- break;
- case 'I': /* optional int */
- if (argstr[1]=='-') {
- argstr++;
- dflti = -atoi(argstr+1);
- } else {
- dflti = atoi(argstr+1);
- }
- while (isdigit(argstr[1])) argstr++;
- tkval = SPqexec(tk);
- if (tkval)
- if (tkval->type==SPTokInt) {
- argv[argc++] = tkval->value.n;
- }
- else {
- SPescape(badargs,"needed int for %s",
- name);
- /* NOTREACHED */
- }
- else {
- argv[argc++] = dflti;
- }
- break;
- case 'f': /* float */
- tkval = SPqexec(tk);
- if (tkval && tkval->type==SPTokFloat) {
- dptr = (double *)(argv+argc);
- *dptr = (double)(tkval->value.f);
- argc = ((int *)dptr)-argv;
- }
- else {
- SPescape(badargs,"needed float for %s",name);
- /* NOTREACHED */
- }
- break;
- case 'n': /* name */
- case 's': /* string */
- tkval = SPqexec(tk);
- if (tkval && (tkval->type==SPTokName ||
- (argtype=='s'&&tkval->type==SPTokStr))) {
- ((char **)argv)[argc++] = tkval->value.s;
- }
- else {
- SPescape(badargs,"needed %s for %s",
- argtype=='n'?"name":"string",name);
- /* NOTREACHED */
- }
- break;
- case 'S': /* optional string */
- if (argstr[1]=='N') {
- dflts = NIL;
- ++argstr;
- }
- else if (argstr[1]=='"') { /* read str */
- argstr += 2; /* point past quote */
- dflts0 = argstr;
- while (*argstr!=0 && *argstr!='"') {
- argstr++;
- }
- dflts = XALLOC(char,argstr-dflts0+1);
- strncpy(dflts,dflts0,argstr-dflts0);
- dflts[argstr-dflts0]=0;
- }
- else {
- SPescape("BadArgstrFormat",
- "bad format in arg string for %s",
- name);
- /* NOTREACHED */
- }
- tkval = SPqexec(tk);
- if (tkval) {
- if ((tkval->type==SPTokName ||
- (argtype=='S'&&tkval->type==SPTokStr))) {
- ((char **)argv)[argc++] =
- tkval->value.s;
- XFREE(dflts);
- }
- else {
- SPescape(badargs,"needed %s for %s",
- argtype=='n'?"name":"string",name);
- /* NOTREACHED */
- }
- }
- else {
- ((char **)argv)[argc++] = dflts;
- }
- break;
- case 'V': /* single evaluated variable */
- tkval = SPqexec(tk);
- if (!tkval) tkval=SPnewnil();
- ((SPtoken **)argv)[argc++] = tkval;
- break;
- case 'L': /* unevaluated list */
- ((SPtoken **)argv)[argc++] = tk;
- break;
- case 'R': /* remainder of list as one arg, uneval. */
- ALLOCTOKEN(tkval)
- tkval->type = SPTokList;
- tkval->next = 0;
- tkval->value.l = tk;
- tk = 0;
- ((SPtoken **)argv)[argc++] = tkval;
- break;
- default:
- SPescape(badargstr,
- "bad arg type %c in func %s",argtype,name);
- /* NOTREACHED */
- }
- if (*argstr) argstr++;
- if (tk) tk = tk->next;
- }
- if (tk) {
- SPescape("TooManyArgs","too many arguments for %s",name);
- /* NOTREACHED */
- }
- if (*argstr && *argstr!=';') {
- SPescape("NotEnoughArgs","not enough arguments for %s", name);
- /* NOTREACHED */
- }
- ALLOCTOKEN(rval)
- rtype = finfo->args[0];
- switch (rtype) { /* return value type */
- case 'i': /* int */
- case 'v': /* no return value */
- ifp = finfo->funcp;
- switch (argc) {
- case 0: n = (*ifp)(); break;
- case 1: n = (*ifp)(argv[0]); break;
- case 2: n = (*ifp)(argv[0],argv[1]); break;
- case 3: n = (*ifp)(argv[0],argv[1],argv[2]); break;
- case 4: n = (*ifp)(argv[0],argv[1],argv[2],argv[3]); break;
- default:
- SPescape(toomanyargsdef,
- "too many args in definition of %s",name);
- /* NOTREACHED */
- }
- if (rtype=='v') {
- rval->type = SPTokNil;
- } else {
- rval->type = SPTokInt;
- rval->value.n = n;
- }
- break;
- case 'f': /* float (double) */
- ffp = (dblfuncp)(finfo->funcp);
- switch (argc) {
- case 0: f = (*ffp)(); break;
- case 1: f = (*ffp)(argv[0]); break;
- case 2: f = (*ffp)(argv[0],argv[1]); break;
- case 3: f = (*ffp)(argv[0],argv[1],argv[2]); break;
- case 4: f = (*ffp)(argv[0],argv[1],argv[2],argv[3]); break;
- default:
- SPescape(toomanyargsdef,
- "too many args in definition of %s",name);
- /* NOTREACHED */
- }
- rval->type = SPTokFloat;
- rval->value.f = f;
- break;
- case 'n': /* name */
- case 's': /* string */
- case 'S': /* allocated string */
- sfp = (strfuncp)(finfo->funcp);
- switch (argc) {
- case 0: s = (*sfp)(); break;
- case 1: s = (*sfp)(argv[0]); break;
- case 2: s = (*sfp)(argv[0],argv[1]); break;
- case 3: s = (*sfp)(argv[0],argv[1],argv[2]); break;
- case 4: s = (*sfp)(argv[0],argv[1],argv[2],argv[3]); break;
- default:
- SPescape(toomanyargsdef,
- "too many args in definition of %s",name);
- /* NOTREACHED */
- }
- if (rtype=='n')
- rval->type = SPTokName;
- else
- rval->type = SPTokStr;
- if (islower(rtype) || !s) {
- if (!s) s="";
- rval->value.s =
- XALLOCM(char,strlen(s)+1,"eval str func");
- }
- else {
- rval->value.s = s; /* allocated for us */
- }
- strcpy(rval->value.s,s);
- break;
- case 'V': /* returns an already allocated var token */
- case 'l': /* returns a static list */
- case 'L': /* returns an already-allocated list */
- lfp = (listfuncp)finfo->funcp;
- switch (argc) {
- case 0: l = (*lfp)(); break;
- case 1: l = (*lfp)(argv[0]); break;
- case 2: l = (*lfp)(argv[0],argv[1]); break;
- case 3: l = (*lfp)(argv[0],argv[1],argv[2]); break;
- case 4: l = (*lfp)(argv[0],argv[1],argv[2],argv[3]); break;
- default:
- SPescape(toomanyargsdef,
- "too many args in definition of %s",name);
- /* NOTREACHED */
- }
- FREETOKEN(rval)
- if (islower(rtype))
- rval = SPcopytoken(l);
- else
- rval = l;
- break;
- default:
- SPescape(badargstr,"bad return code type %c for %s",rtype,name);
- rval->type = SPTokNil;
- break;
- }
- return rval;
- }
-
- /* execute all of the nodes in a list of nodes */
- SPtoken *
- SPexeclist(tklist)
- SPtoken *tklist;
- {
- SPtoken *rval;
- jmp_bufp savejbufp;
- jmp_buf ourjbuf;
- SPtoken *tk, *jtk;
-
- rval = NIL;
- savejbufp = SPjbufp;
- SPjbufp = jmpbuf_addr(ourjbuf);
- for (tk=tklist; tk; tk=tk->next) {
- if (rval) FREETOKEN(rval)
- if (setjmp(jmpbuf_ref(SPjbufp))) { /* process goto */
- for (jtk=tklist; jtk; jtk=jtk->next) {
- if (SPisgotolabel(jtk)) {
- tk = jtk; /* go there */
- goto foundlabel; /* resume execution */
- }
- }
- /* didn't find the label, keep going up */
- SPjbufp = savejbufp;
- longjmp(jmpbuf_ref(SPjbufp),1);
- }
- foundlabel:
- rval = SPexec(tk); /* execute one node */
- }
- SPjbufp = savejbufp;
- return rval;
- }
-
- int /* returns 1 if the node is a label list and matches SPgotolabel */
- SPisgotolabel(tk)
- SPtoken *tk;
- {
- SPtoken *tkl, *tkln;
-
- if (tk &&
- tk->type==SPTokList &&
- ((tkl=tk->value.l)) &&
- tkl->type==SPTokName &&
- tkl->value.s &&
- strcmp(tkl->value.s,"label")==0 &&
- ((tkln=tkl->next)) &&
- tkln->type==SPTokName &&
- tkln->value.s &&
- strcmp(tkln->value.s,SPgotolabel)==0
- ) {
- return 1; /* found it */
- }
- return 0; /* not this one */
- }
-
- /*..........*/
-
- SPfuncinfo *SPfuncbase;
-
- SPfuncinfo *
- SPfindfunc(name)
- char *name; /* name of the func to find */
- {
- SPfuncinfo *finfo;
-
- for (finfo=SPfuncbase; finfo; finfo=finfo->next)
- if (strcmp(finfo->name,name)==0) return finfo;
- return NIL;
- }
-
- SPfuncinfo *
- SPnewfunc(name) /* make a new entry for the name */
- char *name;
- {
- SPfuncinfo *finfo;
-
- finfo = XALLOCM(SPfuncinfo,1,"newfunc");
- finfo->name = name;
- finfo->next = SPfuncbase;
- SPfuncbase = finfo;
- return finfo;
- }
-
- /* VARARGS2 */ /* not really - but third arg is of variable type */
- void
- SPdeffunc(name,args,funcp)
- char *name; /* the name of the function */
- char *args; /* type of args encoded as string */
- void (*funcp)(); /* pointer to the function */
- {
- SPfuncinfo *finfo;
-
- if (strlen(args)<1) {
- SPwerror("args string for %s is too short", name);
- return;
- }
- finfo = SPfindfunc(name); /* find the function */
- if (finfo) { /* redefinition */
- SPwerror("%s redefined",name);
- }
- else { /* new */
- finfo = SPnewfunc(name);
- }
- finfo->args = args;
- finfo->funcp = funcp;
- }
-
- /*..........*/
-
- SPprintval(stream,tk,indent)
- FILE *stream;
- SPtoken *tk;
- int indent;
- {
- int i;
- SPtoken *ltk;
-
- for (i=0;i<indent;i++)
- fputs(" ",stream);
- if (!tk) fprintf(stream,"<NIL>\n");
- else switch (tk->type) {
- case SPTokNil: fprintf(stream,"NIL\n"); break;
- case SPTokInt: fprintf(stream,"INT %d\n",tk->value.n); break;
- case SPTokFloat: fprintf(stream,"FLOAT %g\n",tk->value.f); break;
- case SPTokStr: fprintf(stream,"STRING %s\n",tk->value.s); break;
- case SPTokName: fprintf(stream,"NAME %s\n",tk->value.s); break;
- case SPTokList:
- fprintf(stream,"LIST:\n");
- for (ltk=tk->value.l; ltk; ltk=ltk->next)
- SPprintval(stream,ltk,indent+1);
- break;
- default:
- fprintf(stream,"Type %03o (%c)\n",tk->type,tk->type);
- break;
- }
- }
-
- /*..........*/
-
- /* some debug routines which print out tokens */
- void
- SPdumptoken(tk)
- SPtoken *tk;
- {
- if (!tk) {
- printf("NIL pointer\n");
- return;
- }
- if (!isprint(tk->type)) {
- printf("bad type: %03o\n", tk->type);
- return;
- }
- printf("type=%c",tk->type);
- switch (tk->type) {
- case SPTokInt:
- printf(" %d", tk->value.n);
- break;
- case SPTokFloat:
- printf(" %f", tk->value.f);
- break;
- case SPTokStr:
- case SPTokName:
- printf(" %s", tk->value.s);
- break;
- case SPTokList:
- printf("\n");
- SPdumptokenlist(tk->value.l);
- break;
- }
- printf("\n");
- }
-
- void
- SPdumptokenlist(tk)
- SPtoken *tk;
- {
- while (tk) {
- SPdumptoken(tk);
- tk = tk->next;
- }
- }
-
- /* end */
-