📄 interp.c
字号:
/* SC A Spreadsheet Calculator * Expression interpreter and assorted support routines. * * original by James Gosling, September 1982 * modified by Mark Weiser and Bruce Israel, * University of Maryland * * More mods Robert Bond, 12/86 * More mods by Alan Silverstein, 3-4/88, see list of changes. * $Revision: 6.8 $ */#define DEBUGDTS 1 /* REMOVE ME *//* #define EXPRTREE /* expr. dependency tree stuff, not ready yet */#ifdef aiws#undef _C_func /* Fixes for undefined symbols on AIX */#endif#ifdef IEEE_MATH#include <ieeefp.h>#endif /* IEEE_MATH */#include <math.h>#include <signal.h>#include <setjmp.h>#include <stdio.h>extern int errno; /* set by math functions */#ifdef BSD42#include <strings.h>#include <sys/time.h>#ifndef strchr#define strchr index#endif#else#include <time.h>#ifndef SYSIII#include <string.h>#endif#endif#include <curses.h>#include "sc.h"#if defined(BSD42) || defined(BSD43)char *re_comp();#endif#if defined(SYSV2) || defined(SYSV3)char *regcmp();char *regex();#endif#ifdef SIGVOID void quit();#else int quit();#endif/* Use this structure to save the the last 'g' command */struct go_save { int g_type; double g_n; char *g_s; int g_row; int g_col;} gs;/* g_type can be: */#define G_NONE 0 /* Starting value - must be 0*/#define G_NUM 1#define G_STR 2#define G_CELL 3#define ISVALID(r,c) ((r)>=0 && (r)<maxrows && (c)>=0 && (c)<maxcols)extern FILE *popen();jmp_buf fpe_save;int exprerr; /* Set by eval() and seval() if expression errors */double prescale = 1.0; /* Prescale for constants in let() */int extfunc = 0; /* Enable/disable external functions */int loading = 0; /* Set when readfile() is active */double fn1_eval();double fn2_eval();struct ent *firstev = (struct ent *)0; /* first expr in the eval list */#define PI (double)3.14159265358979323846#define dtr(x) ((x)*(PI/(double)180.0))#define rtd(x) ((x)*(180.0/(double)PI))double finfunc(fun,v1,v2,v3)int fun;double v1,v2,v3;{ double answer,p; p = fn2_eval(pow, 1 + v2, v3); switch(fun) { case PV: answer = v1 * (1 - 1/p) / v2; break; case FV: answer = v1 * (p - 1) / v2; break; case PMT: answer = v1 * v2 / (1 - 1/p); break; default: error("Unknown function in finfunc"); return((double)0); } return(answer);}char *dostindex( val, minr, minc, maxr, maxc)double val;int minr, minc, maxr, maxc;{ register r,c; register struct ent *p; char *pr; int x; x = (int) val; r = minr; c = minc; p = (struct ent *)0; if ( minr == maxr ) { /* look along the row */ c = minc + x - 1; if (c <= maxc && c >=minc) p = *ATBL(tbl, r, c); } else if ( minc == maxc ) { /* look down the column */ r = minr + x - 1; if (r <= maxr && r >=minr) p = *ATBL(tbl, r, c); } else { error ("range specified to @stindex"); return((char *)0); } if (p && p->label) { pr = xmalloc((unsigned)(strlen(p->label)+1)); (void)strcpy(pr, p->label); return (pr); } else return((char *)0);}doubledoindex( val, minr, minc, maxr, maxc)double val;int minr, minc, maxr, maxc;{ double v; register r,c; register struct ent *p; int x; x = (int) val; v = (double)0; r = minr; c = minc; if ( minr == maxr ) { /* look along the row */ c = minc + x - 1; if (c <= maxc && c >=minc && (p = *ATBL(tbl, r, c)) && p->flags&is_valid ) return p->v; } else if ( minc == maxc ){ /* look down the column */ r = minr + x - 1; if (r <= maxr && r >=minr && (p = *ATBL(tbl, r, c)) && p->flags&is_valid ) return p->v; } else error(" range specified to @index"); return v;}doubledolookup( val, minr, minc, maxr, maxc, offr, offc)struct enode * val;int minr, minc, maxr, maxc, offr, offc;{ double v, ret = (double)0; register r,c; register struct ent *p = (struct ent *)0; int incr,incc,fndr,fndc; char *s; incr = (offc != 0); incc = (offr != 0); if (etype(val) == NUM) { v = eval(val); for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) { if ( (p = *ATBL(tbl, r, c)) && p->flags&is_valid ) { if (p->v <= v) { fndr = incc ? (minr + offr) : r; fndc = incr ? (minc + offc) : c; if (ISVALID(fndr,fndc)) p = *ATBL(tbl, fndr, fndc); else error(" range specified to @[hv]lookup"); if ( p && p->flags&is_valid) ret = p->v; } else break; } } } else { s = seval(val); for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) { if ( (p = *ATBL(tbl, r, c)) && p->label ) { if (strcmp(p->label,s) == 0) { fndr = incc ? (minr + offr) : r; fndc = incr ? (minc + offc) : c; if (ISVALID(fndr,fndc)) p = *ATBL(tbl, fndr, fndc); else error(" range specified to @[hv]lookup"); break; } } } if ( p && p->flags&is_valid) ret = p->v; xfree(s); } return ret;}doubledocount(minr, minc, maxr, maxc)int minr, minc, maxr, maxc;{ int v; register r,c; register struct ent *p; v = 0; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) v++; return v;}doubledosum(minr, minc, maxr, maxc)int minr, minc, maxr, maxc;{ double v; register r,c; register struct ent *p; v = (double)0; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) v += p->v; return v;}doubledoprod(minr, minc, maxr, maxc)int minr, minc, maxr, maxc;{ double v; register r,c; register struct ent *p; v = 1; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) v *= p->v; return v;}doubledoavg(minr, minc, maxr, maxc)int minr, minc, maxr, maxc;{ double v; register r,c,count; register struct ent *p; v = (double)0; count = 0; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) { v += p->v; count++; } if (count == 0) return ((double) 0); return (v / (double)count);}doubledostddev(minr, minc, maxr, maxc)int minr, minc, maxr, maxc;{ double lp, rp, v, nd; register r,c,n; register struct ent *p; n = 0; lp = 0; rp = 0; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) { v = p->v; lp += v*v; rp += v; n++; } if ((n == 0) || (n == 1)) return ((double) 0); nd = (double)n; return (sqrt((nd*lp-rp*rp)/(nd*(nd-1))));}doubledomax(minr, minc, maxr, maxc)int minr, minc, maxr, maxc;{ double v = (double)0; register r,c,count; register struct ent *p; count = 0; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) { if (!count) { v = p->v; count++; } else if (p->v > v) v = p->v; } if (count == 0) return ((double) 0); return (v);}doubledomin(minr, minc, maxr, maxc)int minr, minc, maxr, maxc;{ double v = (double)0; register r,c,count; register struct ent *p; count = 0; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) { if (!count) { v = p->v; count++; } else if (p->v < v) v = p->v; } if (count == 0) return ((double) 0); return (v);}#define sec_min 60#define sec_hr 3600L#define sec_day 86400L#define sec_yr 31471200L /* 364.25 days/yr */#define sec_mo 2622600L /* sec_yr/12: sort of an average */int mdays[12]={ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };doubledodts(mo, day, yr)int mo, day, yr;{ long trial; register struct tm *tp; register int i; register long jdate; mdays[1] = 28 + (yr%4 == 0); if (mo < 1 || mo > 12 || day < 1 || day > mdays[--mo] || yr > 1999 || yr < 1970) { error("@dts: invalid argument"); return(0.0); } jdate = day-1; for (i=0; i<mo; i++) jdate += mdays[i]; for (i = 1970; i < yr; i++) jdate += 365 + (i%4 == 0); trial = jdate * sec_day; yr -= 1900; tp = localtime(&trial); if (tp->tm_year != yr) { /* * We may fail this test once a year because of time zone * and daylight savings time errors. This bounces the * trial time past the boundary. The error introduced is * corrected below. */ trial += sec_day*(yr - tp->tm_year); tp = localtime(&trial); } if (tp->tm_mon != mo) { /* We may fail this test once a month. */ trial += sec_day*(mo - tp->tm_mon); tp = localtime(&trial); } if (tp->tm_mday + tp->tm_hour + tp->tm_min + tp->tm_sec != day) { trial -= (tp->tm_mday - day)*sec_day + tp->tm_hour*sec_hr + tp->tm_min*sec_min + tp->tm_sec; }#ifdef DEBUGDTS tp = localtime(&trial); if (tp->tm_mday + tp->tm_hour + tp->tm_min + tp->tm_sec + tp->tm_year + tp->tm_mon != yr+mo+day) error("Dts broke down");#endif return ((double)trial);}doubledotts(hr, min, sec)int hr, min, sec;{ if (hr < 0 || hr > 23 || min < 0 || min > 59 || sec < 0 || sec > 59) { error ("@tts: Invalid argument"); return ((double)0); } return ((double)(sec+min*60+hr*3600));}doubledotime(which, when)int which;double when;{ long time(); static long t_cache; static struct tm tm_cache; struct tm *tp; long tloc; if (which == NOW) return (double)time((long *)0); tloc = (long)when; if (tloc != t_cache) { tp = localtime(&tloc); tm_cache = *tp; tm_cache.tm_mon += 1; tm_cache.tm_year += 1900; t_cache = tloc; } switch (which) { case HOUR: return((double)(tm_cache.tm_hour)); case MINUTE: return((double)(tm_cache.tm_min)); case SECOND: return((double)(tm_cache.tm_sec)); case MONTH: return((double)(tm_cache.tm_mon)); case DAY: return((double)(tm_cache.tm_mday)); case YEAR: return((double)(tm_cache.tm_year)); } /* Safety net */ return ((double)0);}doubledoston(s)char *s;{ char *strtof(); double v; if (!s) return((double)0); (void)strtof(s, &v); xfree(s); return(v);}doubledoeqs(s1, s2)char *s1, *s2;{ double v; if (!s1 && !s2) return((double)1.0); if (!s1 || !s2) v = 0.0; else if (strcmp(s1, s2) == 0) v = 1.0; else v = 0.0; if (s1) xfree(s1); if (s2) xfree(s2); return(v);}/* * Given a string representing a column name and a value which is a column * number, return a pointer to the selected cell's entry, if any, else 0. Use * only the integer part of the column number. Always free the string. */struct ent *getent (colstr, rowdoub) char *colstr; double rowdoub;{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -