Node *makearr(Node *p) { Cell *cp; if (isvalue(p)) { cp = (Cell *) (p->narg[0]); if (isfcn(cp)) SYNTAX( "%s is a function, not an array", cp->nval ); else if (!isarr(cp)) { xfree(cp->sval); cp->sval = (char *) makesymtab(NSYMTAB); cp->tval = ARR; } } return p; }
Cell *call(Node **a, int n) /* function call. very kludgy and fragile */ { static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE }; int i, ncall, ndef; int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */ Node *x; Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */ Cell *y, *z, *fcn; char *s; fcn = execute(a[0]); /* the function itself */ s = fcn->nval; if (!isfcn(fcn)) FATAL("calling undefined function %s", s); if (frame == NULL) { fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame)); if (frame == NULL) FATAL("out of space for stack frames calling %s", s); } for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */ ncall++; ndef = (int) fcn->fval; /* args in defn */ dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) ); if (ncall > ndef) WARNING("function %s called with %d args, uses only %d", s, ncall, ndef); if (ncall + ndef > NARGS) FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS); for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */ dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) ); y = execute(x); oargs[i] = y; dprintf( ("args[%d]: %s %f <%s>, t=%o\n", i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval) ); if (isfcn(y)) FATAL("can't use function %s as argument in %s", y->nval, s); if (isarr(y)) args[i] = y; /* arrays by ref */ else args[i] = copycell(y); tempfree(y); } for ( ; i < ndef; i++) { /* add null args for ones not provided */ args[i] = gettemp(); *args[i] = newcopycell; } fp++; /* now ok to up frame */ if (fp >= frame + nframe) { int dfp = fp - frame; /* old index */ frame = (struct Frame *) realloc((char *) frame, (nframe += 100) * sizeof(struct Frame)); if (frame == NULL) FATAL("out of space for stack frames in %s", s); fp = frame + dfp; } fp->fcncell = fcn; fp->args = args; fp->nargs = ndef; /* number defined with (excess are locals) */ fp->retval = gettemp(); dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) ); y = execute((Node *)(fcn->sval)); /* execute body */ dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) ); for (i = 0; i < ndef; i++) { Cell *t = fp->args[i]; if (isarr(t)) { if (t->csub == CCOPY) { if (i >= ncall) { freesymtab(t); t->csub = CTEMP; tempfree(t); } else { oargs[i]->tval = t->tval; oargs[i]->tval &= ~(STR|NUM|DONTFREE); oargs[i]->sval = t->sval; tempfree(t); } } } else if (t != y) { /* kludge to prevent freeing twice */ t->csub = CTEMP; tempfree(t); } else if (t == y && t->csub == CCOPY) { t->csub = CTEMP; tempfree(t); freed = 1; } } tempfree(fcn); if (isexit(y) || isnext(y)) return y; if (freed == 0) { tempfree(y); /* don't free twice! */ } z = fp->retval; /* return value */ dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) ); fp--; return(z); }