/* SC A Spreadsheet Calculator * Expression interpreter and assorted support routines. * * James Gosling, September 1982 * */ #include "sc.h" #include double eval(e) register struct enode *e; { if (e==0) return 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 '/': { double denom = eval (e->e.o.right); return denom ? eval(e->e.o.left) / denom : 0; } 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 '?': 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)); case 'k': return (e->e.k); case 'v': return (e->e.v->v); case O_REDUCE('+'): { register r,c; register struct ent *p; register double v = 0; register maxr, maxc; register minr, minc; maxr = ((struct ent *) e->e.o.right) -> row; maxc = ((struct ent *) e->e.o.right) -> col; minr = ((struct ent *) e->e.o.left) -> row; minc = ((struct ent *) e->e.o.left) -> col; if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) if ((p = tbl[r][c]) && p->flags&is_valid) v += p->v; return v; } } } EvalAll () { register i,j; register struct ent *p; for (i=0; i<=maxrow; i++) for (j=0; j<=maxcol; j++) if ((p=tbl[i][j]) && p->expr) { double v = eval (p->expr); if (v != p->v) { p->v = v; p->flags |= (is_changed|is_valid); } } } struct enode *new(op,a1,a2) struct enode *a1, *a2; { register struct enode *p = (struct enode *) malloc (sizeof (struct enode)); p->op = op; switch (op) { case O_VAR: p->e.v = (struct ent *) a1; break; case O_CONST: p->e.k = *(double *)&a1; default: p->e.o.left = a1; p->e.o.right = a2; } return p; } let (v, e) struct ent *v; struct enode *e; { efree (v->expr); if (constant(e)) { v->v = eval(e); v->expr = 0; efree(e); } else v->expr = e; v->flags |= (is_changed|is_valid); changed++; } constant (e) register struct enode *e; { return e==0 || e->op == O_CONST || (e->op != O_VAR && (e->op&~0177) != O_REDUCE(0) && constant (e->e.o.left) && constant(e->e.o.right)); } efree (e) register struct enode *e; { if (e) { if (e->op != O_VAR && e->op !=O_CONST) { efree (e->e.o.left); efree (e->e.o.right); } free (e); } } label (v, s, flushdir) register struct ent *v; register char *s; { if (v) { if (flushdir==0 && v->flags&is_valid) { register struct ent *tv; if (v->col>0 && ((tv=lookat(v->row,v->col-1))->flags&is_valid)==0) v = tv, flushdir = 1; else if (((tv=lookat (v->row,v->col+1))->flags&is_valid)==0) v = tv, flushdir = -1; else flushdir = -1; } if (v->label) free(v->label); if (s && s[0]) { v->label = (char *) malloc (strlen(s)+1); strcpy (v->label, s); } else v->label = 0; v->flags |= is_lchanged; if (flushdir<0) v->flags |= is_leftflush; else v->flags &= ~is_leftflush; FullUpdate++; } } decodev (v) register struct ent *v; { if (v) sprintf (line+linelim,"r%dc%d",v->row,v->col); else sprintf (line+linelim,"VAR?"); linelim += strlen (line+linelim); } decompile(e, priority) register struct enode *e; { if (e) { int mypriority; switch (e->op) { default: mypriority = 99; break; case '?': mypriority = 1; break; case ':': mypriority = 2; break; case '|': mypriority = 3; break; case '&': mypriority = 4; break; case '<': case '=': case '>': mypriority = 6; break; case '+': case '-': mypriority = 8; break; case '*': case '/': mypriority = 10; break; } if (mypriorityop) { case 'f': { register char *s; for (s="fixed "; line[linelim++] = *s++;); linelim--; decompile (e->e.o.right, 30); break; } case 'm': line[linelim++] = '-'; decompile (e->e.o.right, 30); break; case '~': line[linelim++] = '~'; decompile (e->e.o.right, 30); break; case 'v': decodev (e->e.v); break; case 'k': sprintf (line+linelim,"%g",e->e.k); linelim += strlen (line+linelim); break; case O_REDUCE('+'): case O_REDUCE('*'): line[linelim++] = e->op&0177; line[linelim++] = '/'; decodev (e->e.o.left); line[linelim++] = ':'; decodev (e->e.o.right); break; default: decompile (e->e.o.left, mypriority); line[linelim++] = e->op; decompile (e->e.o.right, mypriority+1); break; } if (mypriorityv); linelim += strlen (line+linelim); } } printfile (fname) { FILE *f = fopen(fname, "w"); register row, col; register struct ent **p; if (f==0) { error ("Can't create %s", fname); return; } for (row=0;row<=maxrow; row++) { register c = 0; linelim = 0; for (p = &tbl[row][col=0]; col<=maxcol; col++, p++) { if (*p) { char *s; while (linelimflags&is_valid) { sprintf (line+linelim,"%*.*f",fwidth[col],precision[col], (*p)->v); linelim += strlen (line+linelim); } if (s = (*p)->label) { register char *d; d = line+((*p)->flags&is_leftflush ? c : c-strlen(s)+fwidth[col]); while (d>line+linelim) line[linelim++] = ' '; if (dlinelim) linelim = d-line; } } c += fwidth [col]; } fprintf (f,"%.*s\n",linelim,line); } fclose (f); } struct enode *copye (e, Rdelta, Cdelta) register struct enode *e; { register struct enode *ret; if (e==0) ret = 0; else { ret = (struct enode *) malloc (sizeof (struct enode)); *ret = *e; switch (ret->op) { case 'v': ret->e.v = lookat (ret->e.v->row+Rdelta, ret->e.v->col+Cdelta); break; case 'k': break; case 'f': ret->e.o.right = copye (ret->e.o.right,0,0); break; default: ret->e.o.right = copye (ret->e.o.right,Rdelta,Cdelta); ret->e.o.left = copye (ret->e.o.left,Rdelta,Cdelta); break; } } return ret; }