📄 interp.c
字号:
int collen; /* length of string */ int row, col; /* integer values */ struct ent *ep = (struct ent *)0; /* selected entry */ if (((row = (int) floor (rowdoub)) >= 0) && (row < maxrows) /* in range */ && ((collen = strlen (colstr)) <= 2) /* not too long */ && ((col = atocol (colstr, collen)) >= 0) && (col < maxcols)) /* in range */ { ep = *ATBL(tbl, row, col); } xfree (colstr); return (ep);}/* * Given a string representing a column name and a value which is a column * number, return the selected cell's numeric value, if any. */doubledonval (colstr, rowdoub) char *colstr; double rowdoub;{ struct ent *ep; return (((ep = getent (colstr, rowdoub)) && ((ep -> flags) & is_valid)) ? (ep -> v) : (double)0);}/* * The list routines (e.g. dolmax) are called with an LMAX enode. * The left pointer is a chain of ELIST nodes, the right pointer * is a value. */doubledolmax(ep)struct enode *ep;{ register int count = 0; register double maxval = 0; /* Assignment to shut up lint */ register struct enode *p; register double v; for (p = ep; p; p = p->e.o.left) { v = eval(p->e.o.right); if (!count || v > maxval) { maxval = v; count++; } } if (count) return maxval; else return (double)0;}doubledolmin(ep)struct enode *ep;{ register int count = 0; register double minval = 0; /* Assignment to shut up lint */ register struct enode *p; register double v; for (p = ep; p; p = p->e.o.left) { v = eval(p->e.o.right); if (!count || v < minval) { minval = v; count++; } } if (count) return minval; else return (double)0;}double eval(e)register struct enode *e;{ if (e == (struct enode *)0) return (double)0; switch (e->op) { case '+': return (eval(e->e.o.left) + eval(e->e.o.right)); case '-': return (eval(e->e.o.left) - eval(e->e.o.right)); case '*': return (eval(e->e.o.left) * eval(e->e.o.right)); case '/': return (eval(e->e.o.left) / eval(e->e.o.right)); case '%': { double num, denom; num = floor(eval(e->e.o.left)); denom = floor(eval (e->e.o.right)); return denom ? num - floor(num/denom)*denom : (double)0; } case '^': return (fn2_eval(pow,eval(e->e.o.left),eval(e->e.o.right))); case '<': return (eval(e->e.o.left) < eval(e->e.o.right)); case '=': return (eval(e->e.o.left) == eval(e->e.o.right)); case '>': return (eval(e->e.o.left) > eval(e->e.o.right)); case '&': return (eval(e->e.o.left) && eval(e->e.o.right)); case '|': return (eval(e->e.o.left) || eval(e->e.o.right)); case IF: case '?': return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left) : eval(e->e.o.right->e.o.right); case 'm': return (-eval(e->e.o.right)); case 'f': return (eval(e->e.o.right)); case '~': return (eval(e->e.o.right) == 0.0); case 'k': return (e->e.k); case 'v': return (e->e.v.vp->v); case INDEX: case LOOKUP: case HLOOKUP: case VLOOKUP: { register r,c; register maxr, maxc; register minr, minc; maxr = e->e.o.right->e.r.right.vp -> row; maxc = e->e.o.right->e.r.right.vp -> col; minr = e->e.o.right->e.r.left.vp -> row; minc = e->e.o.right->e.r.left.vp -> col; if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; switch(e->op){ case LOOKUP: return dolookup(e->e.o.left, minr, minc, maxr, maxc, minr==maxr, minc==maxc); case HLOOKUP: return dolookup(e->e.o.left->e.o.left, minr,minc,maxr,maxc, (int) eval(e->e.o.left->e.o.right), 0); case VLOOKUP: return dolookup(e->e.o.left->e.o.left, minr,minc,maxr,maxc, 0, (int) eval(e->e.o.left->e.o.right)); case INDEX: return doindex(eval(e->e.o.left), minr, minc, maxr, maxc); } } case REDUCE | '+': case REDUCE | '*': case REDUCE | 'a': case REDUCE | 'c': case REDUCE | 's': case REDUCE | MAX: case REDUCE | MIN: { register r,c; register maxr, maxc; register minr, minc; maxr = e->e.r.right.vp -> row; maxc = e->e.r.right.vp -> col; minr = e->e.r.left.vp -> row; minc = e->e.r.left.vp -> col; if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; switch (e->op) { case REDUCE | '+': return dosum(minr, minc, maxr, maxc); case REDUCE | '*': return doprod(minr, minc, maxr, maxc); case REDUCE | 'a': return doavg(minr, minc, maxr, maxc); case REDUCE | 'c': return docount(minr, minc, maxr, maxc); case REDUCE | 's': return dostddev(minr, minc, maxr, maxc); case REDUCE | MAX: return domax(minr, minc, maxr, maxc); case REDUCE | MIN: return domin(minr, minc, maxr, maxc); } } case ABS: return (fn1_eval( fabs, eval(e->e.o.right))); case ACOS: return (fn1_eval( acos, eval(e->e.o.right))); case ASIN: return (fn1_eval( asin, eval(e->e.o.right))); case ATAN: return (fn1_eval( atan, eval(e->e.o.right))); case ATAN2: return (fn2_eval( atan2, eval(e->e.o.left), eval(e->e.o.right))); case CEIL: return (fn1_eval( ceil, eval(e->e.o.right))); case COS: return (fn1_eval( cos, eval(e->e.o.right))); case EXP: return (fn1_eval( exp, eval(e->e.o.right))); case FABS: return (fn1_eval( fabs, eval(e->e.o.right))); case FLOOR: return (fn1_eval( floor, eval(e->e.o.right))); case HYPOT: return (fn2_eval( hypot, eval(e->e.o.left), eval(e->e.o.right))); case LOG: return (fn1_eval( log, eval(e->e.o.right))); case LOG10: return (fn1_eval( log10, eval(e->e.o.right))); case POW: return (fn2_eval( pow, eval(e->e.o.left), eval(e->e.o.right))); case SIN: return (fn1_eval( sin, eval(e->e.o.right))); case SQRT: return (fn1_eval( sqrt, eval(e->e.o.right))); case TAN: return (fn1_eval( tan, eval(e->e.o.right))); case DTR: return (dtr(eval(e->e.o.right))); case RTD: return (rtd(eval(e->e.o.right))); case RND: { double temp; temp = eval(e->e.o.right); return(temp-floor(temp) < 0.5 ? floor(temp) : ceil(temp)); } case ROUND: { double temp = eval(e->e.o.left); int prec = (int) eval(e->e.o.right), scal = 1; while (prec-- > 0) scal *= 10; temp *= scal; temp = ((temp-floor(temp)) < 0.5 ? floor(temp) : ceil(temp)); return(temp / scal); } case FV: case PV: case PMT: return(finfunc(e->op,eval(e->e.o.left), eval(e->e.o.right->e.o.left), eval(e->e.o.right->e.o.right))); case HOUR: return (dotime(HOUR, eval(e->e.o.right))); case MINUTE: return (dotime(MINUTE, eval(e->e.o.right))); case SECOND: return (dotime(SECOND, eval(e->e.o.right))); case MONTH: return (dotime(MONTH, eval(e->e.o.right))); case DAY: return (dotime(DAY, eval(e->e.o.right))); case YEAR: return (dotime(YEAR, eval(e->e.o.right))); case NOW: return (dotime(NOW, (double)0.0)); case DTS: return (dodts((int)eval(e->e.o.left), (int)eval(e->e.o.right->e.o.left), (int)eval(e->e.o.right->e.o.right))); case TTS: return (dotts((int)eval(e->e.o.left), (int)eval(e->e.o.right->e.o.left), (int)eval(e->e.o.right->e.o.right))); case STON: return (doston(seval(e->e.o.right))); case EQS: return (doeqs(seval(e->e.o.right),seval(e->e.o.left))); case LMAX: return dolmax(e); case LMIN: return dolmin(e); case NVAL: return (donval(seval(e->e.o.left),eval(e->e.o.right))); default: error ("Illegal numeric expression"); exprerr = 1; } return((double)0.0);}#ifdef SIGVOIDvoid#endifeval_fpe(signo) /* Trap for FPE errors in eval */int signo;{#ifdef IEEE_MATH (void)fpsetsticky((fp_except)0); /* Clear exception */#endif /* IEEE_MATH */ longjmp(fpe_save, 1);}double fn1_eval(fn, arg)double (*fn)();double arg;{ double res; errno = 0; res = (*fn)(arg); if(errno) eval_fpe(0); return res;}double fn2_eval(fn, arg1, arg2)double (*fn)();double arg1, arg2;{ double res; errno = 0; res = (*fn)(arg1, arg2); if(errno) eval_fpe(0); return res;}/* * Rules for string functions: * Take string arguments which they xfree. * All returned strings are assumed to be xalloced. */char *docat(s1, s2)register char *s1, *s2;{ register char *p; char *arg1, *arg2; if (!s1 && !s2) return((char *)0); arg1 = s1 ? s1 : ""; arg2 = s2 ? s2 : ""; p = xmalloc((unsigned)(strlen(arg1)+strlen(arg2)+1)); (void) strcpy(p, arg1); (void) strcat(p, arg2); if (s1) xfree(s1); if (s2) xfree(s2); return(p);}char *dodate(tloc)long tloc;{ char *tp; char *p; tp = ctime(&tloc); tp[24] = '\0'; p = xmalloc((unsigned)25); (void) strcpy(p, tp); return(p);}char *dofmt(fmtstr, v)char *fmtstr;double v;{ char buff[FBUFLEN]; char *p; if (!fmtstr) return((char *)0); (void)sprintf(buff, fmtstr, v); p = xmalloc((unsigned)(strlen(buff)+1)); (void) strcpy(p, buff); xfree(fmtstr); return(p);}/* * Given a command name and a value, run the command with the given value and * read and return its first output line (only) as an allocated string, always * a copy of prevstr, which is set appropriately first unless external * functions are disabled, in which case the previous value is used. The * handling of prevstr and freeing of command is tricky. Returning an * allocated string in all cases, even if null, insures cell expressions are * written to files, etc. */#ifdef VMSchar *doext(command, value)char *command;double value;{ error("Warning: External functions unavailable on VMS"); if (command) xfree(command); return (strcpy (xmalloc((unsigned) 1), "\0"));}#else /* VMS */char *doext (command, value)char *command;double value;{ static char *prevstr = (char *)0; /* previous result */ char buff[FBUFLEN]; /* command line/return, not permanently alloc */ if (!prevstr) { prevstr = xmalloc((unsigned)1); *prevstr = '\0'; } if (!extfunc) { error ("Warning: external functions disabled; using %s value", prevstr ? "previous" : "null"); if (command) xfree (command); } else { if (prevstr) xfree (prevstr); /* no longer needed */ prevstr = '\0'; if ((! command) || (! *command)) { error ("Warning: external function given null command name"); if (command) xfree (command); } else { FILE *pp; (void) sprintf (buff, "%s %g", command, value); /* build cmd line */ xfree (command); error ("Running external function..."); (void) refresh(); if ((pp = popen (buff, "r")) == (FILE *) NULL) /* run it */ error ("Warning: running \"%s\" failed", buff); else { if (fgets (buff, sizeof(buff)-1, pp) == NULL) /* one line */ error ("Warning: external function returned nothing"); else { char *cp; error (""); /* erase notice */ buff[sizeof(buff)-1] = '\0'; if (cp = strchr (buff, '\n')) /* contains newline */ *cp = '\0'; /* end string there */ (void) strcpy (prevstr = xmalloc ((unsigned) (strlen (buff) + 1)), buff); /* save alloc'd copy */ } (void) pclose (pp); } /* else */ } /* else */ } /* else */ return (strcpy (xmalloc ((unsigned) (strlen (prevstr) + 1)), prevstr));}#endif /* VMS *//* * Given a string representing a column name and a value which is a column * number, return the selected cell's string value, if any. Even if none, * still allocate and return a null string so the cell has a label value so * the expression is saved in a file, etc. */char *dosval (colstr, rowdoub) char *colstr; double rowdoub;{ struct ent *ep; char *label; label = (ep = getent (colstr, rowdoub)) ? (ep -> label) : ""; return (strcpy (xmalloc ((unsigned) (strlen (label) + 1)), label));}/* * Substring: Note that v1 and v2 are one-based to users, but zero-based * when calling this routine. */char *dosubstr(s, v1, v2)char *s;register int v1,v2;{ register char *s1, *s2; char *p; if (!s) return((char *)0); if (v2 >= strlen (s)) /* past end */ v2 = strlen (s) - 1; /* to end */ if (v1 < 0 || v1 > v2) { /* out of range, return null string */ xfree(s); p = xmalloc((unsigned)1); p[0] = '\0'; return(p); } s2 = p = xmalloc((unsigned)(v2-v1+2)); s1 = &s[v1]; for(; v1 <= v2; s1++, s2++, v1++) *s2 = *s1; *s2 = '\0'; xfree(s); return(p);}char *seval(se)register struct enode *se;{ register char *p; if (se == (struct enode *)0) return (char *)0; switch (se->op) { case O_SCONST: p = xmalloc((unsigned)(strlen(se->e.s)+1)); (void) strcpy(p, se->e.s); return(p); case O_VAR: { struct ent *ep; ep = se->e.v.vp; if (!ep->label) return((char *)0); p = xmalloc((unsigned)(strlen(ep->label)+1)); (void) strcpy(p, ep->label); return(p); } case '#': return(docat(seval(se->e.o.left), seval(se->e.o.right))); case 'f': return(seval(se->e.o.right)); case IF: case '?': return(eval(se->e.o.left) ? seval(se->e.o.right->e.o.left) : seval(se->e.o.right->e.o.right)); case DATE: return(dodate((long)(eval(se->e.o.right)))); case FMT: return(dofmt(seval(se->e.o.left), eval(se->e.o.right))); case STINDEX: { register r,c; register maxr, maxc; register minr, minc; maxr = se->e.o.right->e.r.right.vp -> row; maxc = se->e.o.right->e.r.right.vp -> col; minr = se->e.o.right->e.r.left.vp -> row; minc = se->e.o.right->e.r.left.vp -> col; if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; return dostindex(eval(se->e.o.left), minr, minc, maxr, maxc); } case EXT: return(doext(seval(se->e.o.left), eval(se->e.o.right))); case SVAL: return(dosval(seval(se->e.o.left), eval(se->e.o.right))); case SUBSTR: return(dosubstr(seval(se->e.o.left), (int)eval(se->e.o.right->e.o.left) - 1, (int)eval(se->e.o.right->e.o.right) - 1)); default: error ("Illegal string expression"); exprerr = 1; return((char *)0); }}/* * The graph formed by cell expressions which use other cells's values is not * evaluated "bottom up". The whole table is merely re-evaluated cell by cell, * top to bottom, left to right, in RealEvalAll(). Each cell's expression uses * constants in other cells. However, RealEvalAll() notices when a cell gets a * new numeric or string value, and reports if this happens for any cell. * EvalAll() repeats calling RealEvalAll() until there are no changes or the * evaluation count expires. */int propagation = 10; /* max number of times to try calculation */voidsetiterations(i)int i;{ if(i<1) { error("iteration count must be at least 1"); propagation = 1; } else propagation = i;}voidEvalAll () { int lastcnt, repct = 0; while ((lastcnt = RealEvalAll()) && (repct++ <= propagation)); if((propagation>1)&& (lastcnt >0 )) error("Still changing after %d iterations",propagation-1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -