rgb@nscpdc.UUCP (01/27/87)
# This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #-----cut here-----cut here-----cut here-----cut here----- #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # sc.h # sc.c # lex.c # gram.y # interp.c # This archive created: Mon Jan 26 19:36:31 1987 # By: Robert Bond (NSC Portland, Oregon) echo shar: extracting sc.h '(1515 characters)' cat << \SHAR_EOF > sc.h /* VC A Table Calculator * Common definitions * * original by James Gosling, September 1982 * modified by Mark Weiser and Bruce Israel, * University of Maryland * */ #define MAXROWS 200 #define MAXCOLS 40 #define error move(1,0), clrtoeol(), printw struct ent { double v; char *label; struct enode *expr; short flags; short row, col; struct ent *next; }; struct enode { int op; union { double k; struct ent *v; struct { struct enode *left, *right; } o; } e; }; /* op values */ #define O_VAR 'v' #define O_CONST 'k' #define O_REDUCE(c) (c+0200) #define ACOS 0 #define ASIN 1 #define ATAN 2 #define CEIL 3 #define COS 4 #define EXP 5 #define FABS 6 #define FLOOR 7 #define HYPOT 8 #define LOG 9 #define LOG10 10 #define POW 11 #define SIN 12 #define SQRT 13 #define TAN 14 #define DTR 15 #define RTD 16 #define MIN 17 #define MAX 18 /* flag values */ #define is_valid 0001 #define is_changed 0002 #define is_lchanged 0004 #define is_leftflush 0010 #define is_deleted 0020 #define ctl(c) ('c'&037) struct ent *tbl[MAXROWS][MAXCOLS]; int strow, stcol; int currow, curcol; int savedrow, savedcol; int FullUpdate; int maxrow, maxcol; int fwidth[MAXCOLS]; int precision[MAXCOLS]; char hidden_col[MAXCOLS]; char hidden_row[MAXROWS]; char line[1000]; int linelim; int changed; struct ent *to_fix; struct enode *new(); struct enode *new_const(); struct enode *new_var(); struct ent *lookat(); struct enode *copye(); char *coltoa(); int modflg; SHAR_EOF if test 1515 -ne "`wc -c sc.h`" then echo shar: error transmitting sc.h '(should have been 1515 characters)' fi echo shar: extracting sc.c '(18976 characters)' cat << \SHAR_EOF > sc.c /* SC A Spreadsheet Calculator * Main driver * * original by James Gosling, September 1982 * modifications by Mark Weiser and Bruce Israel, * University of Maryland * * More mods Robert Bond, 12/86 * */ #include <signal.h> #include <curses.h> #ifdef BSD42 #include <strings.h> #else #ifndef SYSIII #include <string.h> #endif #endif #include <stdio.h> #include "sc.h" #if BSD42 || SYSIII #define cbreak crmode #define nocbreak nocrmode #endif char *malloc(); /* default column width */ #define DEFWIDTH 10 #define DEFPREC 2 #define RESCOL 4 /* columns reserved for row numbers */ #define RESROW 3 /* rows reserved for prompt, error, and column numbers */ char curfile[1024]; int linelim = -1; int showme = 1; /* 1 to display the current cell in the top line */ char *rev = "$Revision: 3.1 $"; int seenerr; yyerror (err) char *err; { if (seenerr) return; seenerr++; move (1,0); clrtoeol (); printw ("%s: %.*s<=%s",err,linelim,line,line+linelim); } struct ent * lookat(row,col){ register struct ent **p; if (row < 0) row = 0; else if (row > MAXROWS-1) row = MAXROWS-1; if (col < 0) col = 0; else if (col > MAXCOLS-1) col = MAXCOLS-1; p = &tbl[row][col]; if (*p==0) { *p = (struct ent *) malloc ((unsigned) sizeof (struct ent)); if (row>maxrow) maxrow = row; if (col>maxcol) maxcol = col; (*p)->label = 0; (*p)->flags = 0; (*p)->row = row; (*p)->col = col; (*p)->expr = 0; (*p)->v = (double) 0.0; } return *p; } /* * This structure is used to keep ent structs around before they * are deleted to allow the sync_refs routine a chance to fix the * variable references. * We also use it as a last-deleted buffer for the 'p' command. */ free_ent(p) register struct ent *p; { p->next = to_fix; to_fix = p; p->flags |= is_deleted; } flush_saved() { register struct ent *p; register struct ent *q; if (!(p = to_fix)) return; while (p) { clearent(p); q = p->next; free ((char *)p); p = q; } to_fix = 0; } update () { register row, col; register struct ent **p; static lastmx, lastmy; static char *under_cursor = " "; int maxcol; int maxrow; int rows; int cols; register r; while (hidden_row[currow]) /* You can't hide the last row or col */ currow++; while (hidden_col[curcol]) curcol++; if (curcol < stcol) stcol = curcol, FullUpdate++; if (currow < strow) strow = currow, FullUpdate++; while (1) { register i; for (i = stcol, cols = 0, col = RESCOL; (col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) { cols++; if (hidden_col[i]) continue; col += fwidth[i]; } if (curcol >= stcol + cols) stcol++, FullUpdate++; else break; } while (1) { register i; for (i = strow, rows = 0, row = RESROW; row < LINES && i < MAXROWS; i++) { rows++; if (hidden_row[i]) continue; row++; } if (currow >= strow + rows) strow++, FullUpdate++; else break; } maxcol = stcol + cols - 1; maxrow = strow + rows - 1; if (FullUpdate) { register int i; move (2, 0); clrtobot (); standout(); for (row=RESROW, i=strow; i <= maxrow; i++) { if (hidden_row[i]) continue; move(row,0); printw("%-*d", RESCOL, i); row++; } move (2,0); printw("%*s", RESCOL, " "); for (col=RESCOL, i = stcol; i <= maxcol; i++) { if (hidden_col[i]) continue; move(2, col); printw("%*s", fwidth[i], coltoa(i)); col += fwidth[i]; } standend(); } for (row = strow, r = RESROW; row <= maxrow; row++) { register c = RESCOL; if (hidden_row[row]) continue; for (p = &tbl[row][col = stcol]; col <= maxcol; col++, p++) { if (hidden_col[col]) continue; if (*p && ((*p) -> flags & is_changed || FullUpdate)) { char *s; move (r, c); (*p) -> flags &= ~is_changed; if ((*p) -> flags & is_valid) printw ("%*.*f", fwidth[col], precision[col], (*p) -> v); if (s = (*p) -> label) { char field[1024]; strncpy(field,s,fwidth[col]); field[fwidth[col]] = 0; mvaddstr (r, (*p) -> flags & is_leftflush ? c : c - strlen (field) + fwidth[col], field); } } c += fwidth[col]; } r++; } move(lastmy, lastmx); if (inch() == '<') addstr (under_cursor); lastmy = RESROW; for (row = strow; row < currow; row++) if (!hidden_row[row]) lastmy += 1; lastmx = RESCOL; for (col = stcol; col <= curcol; col++) if (!hidden_col[col]) lastmx += fwidth[col]; move(lastmy, lastmx); *under_cursor = inch(); addstr ("<"); move (0, 0); clrtoeol (); if (linelim >= 0) { addstr (">> "); addstr (line); } else { if (showme) { register struct ent *p; p = tbl[currow][curcol]; if (p && ((p->flags & is_valid) || p->label)) { if (p->expr || !p->label) { linelim = 0; editexp(currow, curcol); } else { sprintf(line, "%s", p->label); } addstr("["); addstr (line); addstr("]"); linelim = -1; } else { addstr("[]"); } } move (lastmy, lastmx); } FullUpdate = 0; } main (argc, argv) char **argv; { int inloop = 1; register int c; int edistate = -1; int arg = 1; int narg; int nedistate; int running; char revmsg[80]; char *revi; { register i; for (i = 0; i < MAXCOLS; i++) { fwidth[i] = DEFWIDTH; precision[i] = DEFPREC; } } curfile[0]=0; running = 1; signals(); initscr (); clear (); cbreak(); nonl(); noecho (); initkbd(); if (argc > 1) { strcpy(curfile,argv[1]); readfile (argv[1],0); } modflg = 0; strcpy(revmsg, argv[0]); for (revi=rev; *revi++ != ':';); strcat(revmsg, revi); revi = revmsg+strlen(revmsg); *--revi = 0; strcat(revmsg,"Type '?' for help."); error (revmsg); FullUpdate++; while (inloop) { running = 1; while (running) { nedistate = -1; narg = 1; if (edistate < 0 && linelim < 0 && (changed || FullUpdate)) EvalAll (), changed = 0; update (); refresh (); move (1, 0); clrtoeol (); fflush (stdout); seenerr = 0; if (((c = nmgetch ()) < ' ') || ( c == 0177 )) switch (c) { #if defined(BSD42) || defined (BSD43) case ctl (z): nocrmode (); nl (); echo (); kill(getpid(),SIGTSTP); /* the pc stops here */ crmode (); nonl (); noecho (); break; #endif case ctl (r): case ctl (l): FullUpdate++; clearok(stdscr,1); break; default: error ("No such command (^%c)", c + 0100); break; case ctl (b): while (--arg>=0) { if (curcol) curcol--; else error ("At column A"); while(hidden_col[curcol] && curcol) curcol--; } break; case ctl (c): running = 0; break; case ctl (f): while (--arg>=0) { if (curcol < MAXCOLS - 1) curcol++; else error ("The table can't be any wider"); while(hidden_col[curcol]&&(curcol<MAXCOLS-1)) curcol++; } break; case ctl (g): case ctl ([): linelim = -1; move (1, 0); clrtoeol (); break; case 0177: case ctl (h): while (--arg>=0) if (linelim > 0) line[--linelim] = 0; break; case ctl (m): case ctl (j): if (linelim < 0) line[linelim = 0] = 0; else { linelim = 0; yyparse (); linelim = -1; } break; case ctl (n): while (--arg>=0) { if (currow < MAXROWS - 1) currow++; else error ("The table can't be any longer"); while (hidden_row[currow] && (currow < MAXROWS - 1)) currow++; } break; case ctl (p): while (--arg>=0) { if (currow) currow--; else error ("At row zero"); while (hidden_row[currow] && currow) currow--; } break; case ctl (q): break; /* ignore flow control */ case ctl (s): break; /* ignore flow control */ case ctl (t): showme ^= 1; break; case ctl (u): narg = arg * 4; nedistate = 1; break; case ctl (v): /* insert variable name */ if (linelim > 0) { sprintf (line+linelim,"%s%d", coltoa(curcol), currow); linelim = strlen (line); } break; case ctl (e): /* insert variable expression */ if (linelim > 0) editexp(currow,curcol); break; case ctl (a): /* insert variable value */ if (linelim > 0) { struct ent *p = tbl[currow][curcol]; if (p && p -> flags & is_valid) { sprintf (line + linelim, "%.*f", precision[curcol],p -> v); linelim = strlen (line); } } break; } else if ('0' <= c && c <= '9' && (linelim < 0 || edistate >= 0)) { if (edistate != 0) { if (c == '0') /* just a '0' goes to left col */ curcol = 0; else { nedistate = 0; narg = c - '0'; } } else { nedistate = 0; narg = arg * 10 + (c - '0'); } } else if (linelim >= 0) { line[linelim++] = c; line[linelim] = 0; } else switch (c) { case '.': nedistate = 1; break; case ':': break; /* Be nice to vi users */ case '=': sprintf(line,"let %s%d = ",coltoa(curcol),currow); linelim = strlen (line); break; case '/': switch (nmgetch()) { case 'c': sprintf(line,"copy [to] %s%d [from] ", coltoa(curcol), currow); linelim = strlen(line); break; case 'x': sprintf(line,"erase [v:v] "); linelim = strlen(line); break; case 'f': sprintf(line,"fill [v:v start inc] "); linelim = strlen(line); break; default: error("Invalid region operation"); } break; case '$': curcol = MAXCOLS - 1; while (!tbl[currow][curcol] && curcol > 0) curcol--; break; case '#': currow = MAXROWS - 1; while (!tbl[currow][curcol] && currow > 0) currow--; break; case '^': currow = 0; break; case '?': help (); break; case '"': sprintf (line, "label %s%d = \"", coltoa(curcol), currow); linelim = strlen (line); break; case '<': sprintf (line, "leftstring %s%d = \"", coltoa(curcol), currow); linelim = strlen (line); break; case '>': sprintf (line, "rightstring %s%d = \"", coltoa(curcol), currow); linelim = strlen (line); break; case 'e': editv (currow, curcol); break; case 'E': edits (currow, curcol); break; case 'f': sprintf (line, "format [for column] %s [is] ", coltoa(curcol)); error("Current format is %d %d", fwidth[curcol],precision[curcol]); linelim = strlen (line); break; case 'g': sprintf (line, "goto [v] "); linelim = strlen (line); break; case 'P': sprintf (line, "put [database into] \""); if (*curfile) error("default file is '%s'",curfile); linelim = strlen (line); break; case 'M': sprintf (line, "merge [database from] \""); linelim = strlen (line); break; case 'G': sprintf (line, "get [database from] \""); if (*curfile) error("default file is '%s'",curfile); linelim = strlen (line); break; case 'W': sprintf (line, "write [listing to] \""); linelim = strlen (line); break; case 'T': /* tbl output */ sprintf (line, "tbl [listing to] \""); linelim = strlen (line); break; case 'i': switch (get_qual()) { case 'r': insertrow(arg); break; case 'c': insertcol(arg); break; default: error("Invalid insert command"); break; } break; case 'd': switch (get_qual()) { case 'r': deleterow(arg); break; case 'c': deletecol(arg); break; default: error("Invalid delete command"); break; } break; case 'v': switch (get_qual()) { case 'r': rowvalueize(arg); modflg++; break; case 'c': colvalueize(arg); modflg++; break; default: error("Invalid value command"); break; } break; case 'p': { register qual; qual = get_qual(); while (arg--) pullcells(qual); break; } case 'x': { register struct ent **p; register int c; flush_saved(); for (c = curcol; arg-- && c < MAXCOLS; c++) { p = &tbl[currow][c]; if (*p) { free_ent(*p); *p = 0; } } sync_refs(); FullUpdate++; } break; case 'Q': case 'q': running = 0; break; case 'h': while (--arg>=0) { if (curcol) curcol--; else error ("At column A"); while(hidden_col[curcol] && curcol) curcol--; } break; case 'j': while (--arg>=0) { if (currow < MAXROWS - 1) currow++; else error ("The table can't be any longer"); while (hidden_row[currow]&&(currow<MAXROWS-1)) currow++; } break; case 'k': while (--arg>=0) { if (currow) currow--; else error ("At row zero"); while (hidden_row[currow] && currow) currow--; } break; case 'l': while (--arg>=0) { if (curcol < MAXCOLS - 1) curcol++; else error ("The table can't be any wider"); while(hidden_col[curcol]&&(curcol<MAXCOLS-1)) curcol++; } break; case 'm': savedrow = currow; savedcol = curcol; break; case 'c': { register struct ent *p = tbl[savedrow][savedcol]; register c; register struct ent *n; if (!p) break; FullUpdate++; modflg++; for (c = curcol; arg-- && c < MAXCOLS; c++) { n = lookat (currow, c); clearent(n); n -> flags = p -> flags; n -> v = p -> v; n -> expr = copye(p->expr, currow - savedrow, c - savedcol); n -> label = 0; if (p -> label) { n -> label = malloc((unsigned)(strlen(p->label)+1)); strcpy (n -> label, p -> label); } } break; } case 'z': switch (get_qual()) { case 'r': hiderow(arg); break; case 'c': hidecol(arg); break; default: error("Invalid zap command"); break; } break; case 's': switch (get_qual()) { case 'r': rowshow_op(); break; case 'c': colshow_op(); break; default: error("Invalid show command"); break; } break; case 'a': switch (get_qual()) { case 'r': while (arg--) duprow(); break; case 'c': while (arg--) dupcol(); break; default: error("Invalid add row/col command"); break; } break; default: if ((c & 0177) != c) error("Weird character, decimal '%d'.\n", (int) c); else error ("No such command (%c)", c); break; } edistate = nedistate; arg = narg; } /* while (running) */ inloop = modcheck(" before exiting"); } /* while (inloop) */ move (LINES - 1, 0); clrtoeol(); refresh (); nocbreak(); nl(); echo (); resetkbd(); endwin (); } signals() { int quit(); int timeout(); signal(SIGINT, SIG_IGN); signal(SIGQUIT, quit); signal(SIGPIPE, quit); signal(SIGTERM, quit); signal(SIGALRM, timeout); signal(SIGFPE, quit); signal(SIGBUS, quit); } quit() { move (LINES - 1, 0); clrtoeol(); refresh(); nocbreak(); nl(); echo(); resetkbd(); endwin(); exit(1); } modcheck(endstr) char *endstr; { if (modflg && curfile[0]) { char ch, lin[100]; move (0, 0); clrtoeol (); sprintf (lin,"File '%s' is modified, save%s? ",curfile,endstr); addstr (lin); refresh(); ch = nmgetch(); if (ch != 'n' && ch != 'N') if (writefile(curfile) < 0) return (1); else if (ch == ctl (g) || ch == ctl([)) return(1); } else if (modflg) { char ch, lin[100]; move (0, 0); clrtoeol (); sprintf (lin,"Do you want a chance to save the data? "); addstr (lin); refresh(); ch = nmgetch(); if (ch == 'n' || ch == 'N') return(0); else return(1); } return(0); } writefile (fname) char *fname; { register FILE *f; register struct ent **p; register r, c; char save[1024]; if (*fname == 0) fname = &curfile[0]; strcpy(save,fname); f = fopen (fname, "w"); if (f==0) { error ("Can't create %s", fname); return (-1); } fprintf (f, "# This data file was generated by the Spreadsheet "); fprintf (f, "Calculator.\n"); fprintf (f, "# You almost certainly shouldn't edit it.\n\n"); for (c=0; c<MAXCOLS; c++) if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC) fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]); for (r=0; r<=maxrow; r++) { p = &tbl[r][0]; for (c=0; c<=maxcol; c++, p++) if (*p) { if ((*p)->label) fprintf (f, "%sstring %s%d = \"%s\"\n", (*p)->flags&is_leftflush ? "left" : "right", coltoa(c),r,(*p)->label); if ((*p)->flags&is_valid) { editv (r, c); fprintf (f, "%s\n",line); } } } fclose (f); strcpy(curfile,save); modflg = 0; error("File '%s' written.",curfile); return (0); } readfile (fname,eraseflg) char *fname; int eraseflg; { register FILE *f; char save[1024]; if (*fname == 0) fname = &curfile[0]; strcpy(save,fname); if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return; f = fopen (save, "r"); if (f==0) { error ("Can't read %s", save); return; } if (eraseflg) erasedb (); while (fgets(line,sizeof line,f)) { linelim = 0; if (line[0] != '#') yyparse (); } fclose (f); linelim = -1; modflg++; if (eraseflg) { strcpy(curfile,save); modflg = 0; } EvalAll(); } erasedb () { register r, c; for (c = 0; c<=maxcol; c++) { fwidth[c] = DEFWIDTH; precision[c] = DEFPREC; } for (r = 0; r<=maxrow; r++) { register struct ent **p = &tbl[r][0]; for (c=0; c++<=maxcol; p++) if (*p) { if ((*p)->expr) efree ((*p) -> expr); if ((*p)->label) free ((*p) -> label); free ((char *)*p); *p = 0; } } maxrow = 0; maxcol = 0; FullUpdate++; } #if DEBUG debugout(g,fmt,args) FILE *g; char *fmt; { int op; if (g == 0) g = fopen("debug","a"),op = 1; if (g == 0) return; _doprnt(fmt, &args, g); fflush(g); if (op) fclose(g); } #endif SHAR_EOF if test 18976 -ne "`wc -c sc.c`" then echo shar: error transmitting sc.c '(should have been 18976 characters)' fi echo shar: extracting lex.c '(9305 characters)' cat << \SHAR_EOF > lex.c /* SC A Spreadsheet Calculator * Lexical analyser * * original by James Gosling, September 1982 * modifications by Mark Weiser and Bruce Israel, * University of Maryland * * More mods Robert Bond, 12/86 * */ #if defined(BSD42) || defined(BSD43) #include <sys/ioctl.h> #endif #include <curses.h> #include <signal.h> #include <setjmp.h> #include "sc.h" #include <ctype.h> #ifdef BSD42 #include <strings.h> #else #ifndef SYSIII #include <string.h> #endif #endif #include "y.tab.h" char *strtof(); char *malloc(); jmp_buf wakeup; struct key { char *key; int val; }; struct key experres[] = { #include "experres.h" 0, 0}; struct key statres[] = { #include "statres.h" 0, 0}; #define ctl(x) ('x'&037) yylex () { register char *p = line+linelim; int ret; while (isspace(*p)) p++; if (*p==0) ret = -1; else if (isalpha(*p)) { char *tokenst = p; register tokenl; register struct key *tbl; while (isalpha(*p)) p++; if ((tokenl = p-tokenst) <= 2) { register col; /* a COL is 1 or 2 char alpha (and not pi or ln!) */ if (tokenl == 2 && tokenst[0] == 'p' && tokenst[1] == 'i') { ret = K_PI; } else if (tokenl == 2 && tokenst[0] == 'l' && tokenst[1] == 'n') { ret = K_LN; } else { ret = COL; col = ((tokenst[0] & 0137) - 'A'); if (p == tokenst+2) col = (col + 1)*26 + ((tokenst[1] & 0137) - 'A'); yylval.ival = col; } } else { ret = WORD; tokenl = p-tokenst; for (tbl = linelim ? experres : statres; tbl->key; tbl++) if (((tbl->key[0]^tokenst[0])&0137)==0 && tbl->key[tokenl]==0) { register i = 1; while (i<tokenl && ((tokenst[i]^tbl->key[i])&0137)==0) i++; if (i>=tokenl) { ret = tbl->val; break; } } if (ret==WORD) { linelim = p-line; yyerror ("Unintelligible word"); } } } else if ((*p == '.') || isdigit(*p)) { register long v = 0; char *nstart = p; if (*p != '.') { do v = v*10 + (*p-'0'); while (isdigit(*++p)); } if (*p=='.' || *p == 'e' || *p == 'E') { ret = FNUMBER; p = strtof(nstart, &yylval.fval); } else { if((int)v != v) { ret = FNUMBER; yylval.fval = v; } else { ret = NUMBER; yylval.ival = v; } } } else if (*p=='"') { /* This storage is never freed. Oh well. -MDW */ char *ptr; ptr = p+1; while(*ptr && *ptr++ != '"'); ptr = malloc((unsigned)(ptr-p)); yylval.sval = ptr; p += 1; while (*p && *p!='"') *ptr++ = *p++; *ptr = 0; if (*p) p += 1; ret = STRING; } else if (*p=='[') { while (*p && *p!=']') p++; if (*p) p++; linelim = p-line; return yylex(); } else ret = *p++; linelim = p-line; return ret; } #ifdef SIMPLE initkbd() {} resetkbd() {} nmgetch() { return (getchar() & 0x7f); } #else /*SIMPLE*/ #if defined(BSD42) || defined (SYSIII) || defined(BSD43) #define N_KEY 4 struct key_map { char *k_str; char k_val; char k_index; }; struct key_map km[N_KEY]; char keyarea[N_KEY*10]; char *tgetstr(); char *getenv(); #ifdef TIOCSLTC struct ltchars old_chars, new_chars; #endif char dont_use[] = { ctl(z), ctl(r), ctl(l), ctl(b), ctl(c), ctl(f), ctl(g), ctl([), ctl(h), ctl(m), ctl(j), ctl(n), ctl(p), ctl(q), ctl(s), ctl(t), ctl(u), ctl(v), ctl(e), ctl(a), 0, }; initkbd() { register struct key_map *kp; register i,j; char *ks; char *p = keyarea; static char buf[1024]; /* Why do I have to do this again? */ if (tgetent(buf, getenv("TERM")) <= 0) return; km[0].k_str = tgetstr("kl", &p); km[0].k_val = ctl(b); km[1].k_str = tgetstr("kr", &p); km[1].k_val = ctl(f); km[2].k_str = tgetstr("ku", &p); km[2].k_val = ctl(p); km[3].k_str = tgetstr("kd", &p); km[3].k_val = ctl(n); ks = tgetstr("ks",&p); if (ks) printf("%s",ks); /* Unmap arrow keys which conflict with our ctl keys */ /* Ignore unset, longer than length 1, and 1-1 mapped keys */ for (i = 0; i < N_KEY; i++) { kp = &km[i]; if (kp->k_str && (kp->k_str[1] == 0) && (kp->k_str[0] != kp->k_val)) for (j = 0; dont_use[j] != 0; j++) if (kp->k_str[0] == dont_use[j]) { kp->k_str = (char *)0; break; } } #ifdef TIOCSLTC ioctl(fileno(stdin), TIOCGLTC, (char *)&old_chars); new_chars = old_chars; if (old_chars.t_lnextc == ctl(v)) new_chars.t_lnextc = -1; if (old_chars.t_rprntc == ctl(r)) new_chars.t_rprntc = -1; ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars); #endif } resetkbd() { #ifdef TIOCSLTC ioctl(fileno(stdin), TIOCSLTC, (char *)&old_chars); #endif } nmgetch() { register int c; register struct key_map *kp; register struct key_map *biggest; register int i; int almost; int maybe; static char dumpbuf[10]; static char *dumpindex; int timeout(); if (dumpindex && *dumpindex) return (*dumpindex++); c = getchar() & 0x7f; biggest = 0; almost = 0; for (kp = &km[0]; kp < &km[N_KEY]; kp++) { if (!kp->k_str) continue; if (c == kp->k_str[kp->k_index]) { almost = 1; kp->k_index++; if (kp->k_str[kp->k_index] == 0) { c = kp->k_val; for (kp = &km[0]; kp < &km[N_KEY]; kp++) kp->k_index = 0; return(c); } } if (!biggest && kp->k_index) biggest = kp; else if (kp->k_index && biggest->k_index < kp->k_index) biggest = kp; } if (almost) { signal(SIGALRM, timeout); alarm(1); if (setjmp(wakeup) == 0) { maybe = nmgetch(); alarm(0); return(maybe); } } if (biggest) { for (i = 0; i<biggest->k_index; i++) dumpbuf[i] = biggest->k_str[i]; dumpbuf[i++] = c; dumpbuf[i] = 0; dumpindex = &dumpbuf[1]; for (kp = &km[0]; kp < &km[N_KEY]; kp++) kp->k_index = 0; return (dumpbuf[0]); } return(c); } #endif #ifdef SYSV initkbd() { keypad(stdscr, TRUE); } resetkbd() {} nmgetch() { register int c; c = getch(); switch (c) { case KEY_LEFT: c = ctl(b); break; case KEY_RIGHT: c = ctl(f); break; case KEY_UP: c = ctl(p); break; case KEY_DOWN: c = ctl(n); break; default: c = c & 0x7f; } return (c); } #endif /* SYSV */ #endif /* SIMPLE */ timeout() { longjmp(wakeup, -1); } int dbline; /*VARARGS*/ void debug (str) char *str; { mvprintw (2+(dbline++%22),80-70,str); clrtoeol(); } /* * This converts a floating point number of the form * [s]ddd[.d*][esd*] where s can be a + or - and e is E or e. * to floating point. * p is advanced. */ char * strtof(p, res) register char *p; double *res; { double acc; int sign; double fpos; int exp; int exps; acc = 0.0; sign = 1; exp = 0; exps = 1; if (*p == '+') p++; else if (*p == '-') { p++; sign = -1; } while (isdigit(*p)) { acc = acc * 10.0 + (double)(*p - '0'); p++; } if (*p == 'e' || *p == 'E') { p++; if (*p == '+') p++; else if (*p == '-') { p++; exps = -1; } while(isdigit(*p)) { exp = exp * 10 + (*p - '0'); p++; } } if (*p == '.') { fpos = 1.0/10.0; p++; while(isdigit(*p)) { acc += (*p - '0') * fpos; fpos *= 1.0/10.0; p++; } } if (*p == 'e' || *p == 'E') { exp = 0; exps = 1; p++; if (*p == '+') p++; else if (*p == '-') { p++; exps = -1; } while(isdigit(*p)) { exp = exp * 10 + (*p - '0'); p++; } } if (exp) { if (exps > 0) while (exp--) acc *= 10.0; else while (exp--) acc *= 1.0/10.0; } if (sign > 0) *res = acc; else *res = -acc; return(p); } help () { move(2,0); clrtobot(); dbline = 0; debug ("Cursor: ^n j next row ^p k prev. row ESC ^g erase cmd"); debug (" ^f l fwd col ^b h back col ^l ^r redraw screen"); debug (" 0 col A $ last col g goto "); debug (" ^ row 0 # last row"); debug ("Cell: \" < > enter label = enter value x clear cell"); debug (" c copy cell m mark cell ^t line 1 on/off"); debug (" ^a type value ^e type expr. ^v type vbl name"); debug ("Row, Col: ar ac dup ir ic insert sr sc show"); debug (" dr dc delete zr zc hide pr pc pull"); debug (" vr vc value only f format"); debug ("Region: /c copy /x clear /f fill"); debug ("File: G get database M merge database T write tbl fmt"); debug (" P put database W write listing"); debug ("Misc: Q q quit pm pull (merge)"); debug ("Expr: +-*/^ arithmetic ?e:e conditional & | booleans"); debug (" < = > relations <= >= relations != relations"); debug (" @sum(v1:v2) @avg(v1:v2) @prod(v1:v2)"); debug (" @func(e) - lots of other math functions"); } SHAR_EOF if test 9305 -ne "`wc -c lex.c`" then echo shar: error transmitting lex.c '(should have been 9305 characters)' fi echo shar: extracting gram.y '(4962 characters)' cat << \SHAR_EOF > gram.y /* SC A Spreadsheet Calculator * Command and expression parser * * original by James Gosling, September 1982 * modified by Mark Weiser and Bruce Israel, * University of Maryland * * more mods Robert Bond 12/86 * */ %{ #include <curses.h> #include "sc.h" %} %union { int ival; double fval; struct ent *ent; struct enode *enode; char *sval; } %type <ent> var %type <fval> num %type <enode> e term %token <sval> STRING %token <ival> NUMBER %token <fval> FNUMBER %token <sval> WORD %token <ival> COL %token S_FORMAT %token S_LABEL %token S_LEFTSTRING %token S_RIGHTSTRING %token S_GET %token S_PUT %token S_MERGE %token S_LET %token S_WRITE %token S_TBL %token S_PROGLET %token S_COPY %token S_SHOW %token S_ERASE %token S_FILL %token S_GOTO %token K_FIXED %token K_SUM %token K_PROD %token K_AVG %token K_ACOS %token K_ASIN %token K_ATAN %token K_CEIL %token K_COS %token K_EXP %token K_FABS %token K_FLOOR %token K_HYPOT %token K_LN %token K_LOG %token K_PI %token K_POW %token K_SIN %token K_SQRT %token K_TAN %token K_DTR %token K_RTD %token K_MAX %token K_MIN %left '?' ':' %left '|' %left '&' %nonassoc '<' '=' '>' %left '+' '-' %left '*' '/' %left '^' %% command: S_LET var '=' e { let ($2, $4); } | S_LABEL var '=' STRING { label ($2, $4, 0); } | S_LEFTSTRING var '=' STRING { label ($2, $4, -1); } | S_RIGHTSTRING var '=' STRING { label ($2, $4, 1); } | S_FORMAT COL NUMBER NUMBER { fwidth[$2] = $3; FullUpdate++; modflg++; precision[$2] = $4; } | S_GET STRING { readfile ($2,1); } | S_MERGE STRING { readfile ($2,0); } | S_PUT STRING { (void) writefile ($2); } | S_WRITE STRING { printfile ($2); } | S_TBL STRING { tblprintfile ($2); } | S_SHOW COL ':' COL { showcol( $2, $4); } | S_SHOW NUMBER ':' NUMBER { showrow( $2, $4); } | S_COPY var var ':' var { copy($2, $3, $5); } | S_ERASE var ':' var { eraser($2, $4); } | S_FILL var ':' var num num { fill($2, $4, $5, $6); } | S_GOTO var {moveto($2); } | /* nothing */ | error; term: var { $$ = new_var('v', $1); } | K_FIXED term { $$ = new ('f', (struct enode *)0, $2); } | '@' K_SUM '(' var ':' var ')' { $$ = new (O_REDUCE('+'), (struct enode *)$4, (struct enode *)$6); } | '@' K_PROD '(' var ':' var ')' { $$ = new (O_REDUCE('*'), (struct enode *)$4, (struct enode *)$6); } | '@' K_AVG '(' var ':' var ')' { $$ = new (O_REDUCE('a'), (struct enode *)$4, (struct enode *)$6); } | '@' K_ACOS '(' e ')' { $$ = new(ACOS, (struct enode *)0, $4); } | '@' K_ASIN '(' e ')' { $$ = new(ASIN, (struct enode *)0, $4); } | '@' K_ATAN '(' e ')' { $$ = new(ATAN, (struct enode *)0, $4); } | '@' K_CEIL '(' e ')' { $$ = new(CEIL, (struct enode *)0, $4); } | '@' K_COS '(' e ')' { $$ = new(COS, (struct enode *)0, $4); } | '@' K_EXP '(' e ')' { $$ = new(EXP, (struct enode *)0, $4); } | '@' K_FABS '(' e ')' { $$ = new(FABS, (struct enode *)0, $4); } | '@' K_FLOOR '(' e ')' { $$ = new(FLOOR, (struct enode *)0, $4); } | '@' K_HYPOT '(' e ',' e ')' { $$ = new(HYPOT, $4, $6); } | '@' K_LN '(' e ')' { $$ = new(LOG, (struct enode *)0, $4); } | '@' K_LOG '(' e ')' { $$ = new(LOG10, (struct enode *)0, $4); } | '@' K_POW '(' e ',' e ')' { $$ = new(POW, $4, $6); } | '@' K_SIN '(' e ')' { $$ = new(SIN, (struct enode *)0, $4); } | '@' K_SQRT '(' e ')' { $$ = new(SQRT, (struct enode *)0, $4); } | '@' K_TAN '(' e ')' { $$ = new(TAN, (struct enode *)0, $4); } | '@' K_DTR '(' e ')' { $$ = new(DTR, (struct enode *)0, $4); } | '@' K_RTD '(' e ')' { $$ = new(RTD, (struct enode *)0, $4); } | '@' K_MAX '(' e ',' e ')' { $$ = new(MAX, $4, $6); } | '@' K_MIN '(' e ',' e ')' { $$ = new(MIN, $4, $6); } | '(' e ')' { $$ = $2; } | '+' term { $$ = $2; } | '-' term { $$ = new ('m', (struct enode *)0, $2); } | NUMBER { $$ = new_const('k', (double) $1); } | FNUMBER { $$ = new_const('k', $1); } | K_PI { $$ = new_const('k', (double)3.14159265358979323846); } | '~' term { $$ = new ('~', (struct enode *)0, $2); } | '!' term { $$ = new ('~', (struct enode *)0, $2); } ; e: e '+' e { $$ = new ('+', $1, $3); } | e '-' e { $$ = new ('-', $1, $3); } | e '*' e { $$ = new ('*', $1, $3); } | e '/' e { $$ = new ('/', $1, $3); } | e '^' e { $$ = new ('^', $1, $3); } | term | e '?' e ':' e { $$ = new ('?', $1, new(':', $3, $5)); } | e '<' e { $$ = new ('<', $1, $3); } | e '=' e { $$ = new ('=', $1, $3); } | e '>' e { $$ = new ('>', $1, $3); } | e '&' e { $$ = new ('&', $1, $3); } | e '|' e { $$ = new ('|', $1, $3); } | e '<' '=' e { $$ = new ('~', (struct enode *)0, new ('>', $1, $4)); } | e '!' '=' e { $$ = new ('~', (struct enode *)0, new ('=', $1, $4)); } | e '>' '=' e { $$ = new ('~', (struct enode *)0, new ('<', $1, $4)); } ; var: COL NUMBER { $$ = lookat($2 , $1); }; num: NUMBER { $$ = (double) $1; } | FNUMBER { $$ = $1; } | '-' num { $$ = -$2; } | '+' num { $$ = $2; } ; SHAR_EOF if test 4962 -ne "`wc -c gram.y`" then echo shar: error transmitting gram.y '(should have been 4962 characters)' fi echo shar: extracting interp.c '(17239 characters)' cat << \SHAR_EOF > 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 */ #include <math.h> #include <stdio.h> #ifdef BSD42 #include <strings.h> #else #ifndef SYSIII #include <string.h> #endif #endif #include <curses.h> #include "sc.h" #define DEFCOLDELIM ':' char *malloc(); #define PI (double)3.14159265358979323846 #define dtr(x) ((x)*(PI/(double)180.0)) #define rtd(x) ((x)*(180.0/(double)PI)) double dosum(minr, minc, maxr, maxc) int minr, minc, maxr, maxc; { double v; register r,c; register struct ent *p; v = 0; 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; } double doprod(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 = tbl[r][c]) && p->flags&is_valid) v *= p->v; return v; } double doavg(minr, minc, maxr, maxc) int minr, minc, maxr, maxc; { double v; register r,c,count; register struct ent *p; v = 0; count = 0; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) if ((p = tbl[r][c]) && p->flags&is_valid) { v += p->v; count++; } if (count == 0) return ((double) 0); return (v / (double)count); } 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 (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 '?': 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 ((double)!(int)eval(e->e.o.right)); case 'k': return (e->e.k); case 'v': return (e->e.v->v); case O_REDUCE('+'): case O_REDUCE('*'): case O_REDUCE('a'): { register r,c; 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; switch (e->op) { case O_REDUCE('+'): return dosum(minr, minc, maxr, maxc); case O_REDUCE('*'): return doprod(minr, minc, maxr, maxc); case O_REDUCE('a'): return doavg(minr, minc, maxr, maxc); } } case ACOS: return (acos(eval(e->e.o.right))); case ASIN: return (asin(eval(e->e.o.right))); case ATAN: return (atan(eval(e->e.o.right))); case CEIL: return (ceil(eval(e->e.o.right))); case COS: return (cos(eval(e->e.o.right))); case EXP: return (exp(eval(e->e.o.right))); case FABS: return (fabs(eval(e->e.o.right))); case FLOOR: return (floor(eval(e->e.o.right))); case HYPOT: return (hypot(eval(e->e.o.left), eval(e->e.o.right))); case LOG: return (log(eval(e->e.o.right))); case LOG10: return (log10(eval(e->e.o.right))); case POW: return (pow(eval(e->e.o.left), eval(e->e.o.right))); case SIN: return (sin(eval(e->e.o.right))); case SQRT: return (sqrt(eval(e->e.o.right))) ^t line 1 on/off"); debug (" ^a type value ^e type expr. ^v type vbl name"); debug ("Row, Col: ar ac dup ir ic insert sr sc show"); debug (" dr dc delete zr zc hide pr pc pull"); debug (" vr vc value only f format"); debug ("Region: /c copy /x clear /f fill"); debug ("File: G get database M merge database T write tbl fmt"); debug (" P put database W write listing"); debug ("Misc: Q q quit pm pull (merge)"); debug ("Expr: +-*/^ arithmetic ?e:e conditional & | booleans"); debug (" < = > relations <= >= relations != relations"); debug (" @sum(v1:v2) @avg(v1:v2) @prod(v1:v2)"); debug (" @func(e) - lots of other math functions"); } SHAR_EOF if test 9305 -ne "`wc -c lex.c`" then echo shar: error transmitting lex.c '(should have been 9305 characters)' fi echo shar: extracting gram.y '(4962 characters)' cat << \SHAR_EOF > gram.y /* SC A Spreadsheet Calculator * Command and expression parser * * original by James Gosling, September 1982 * modified by Mark Weiser and Bruce Israel, * University of Maryland * * more mods Robert Bond 12/86 * */ %{ #include <curses.h> #include "sc.h" %} %union { int ival; double fval; struct ent *ent; struct enode *enode; char *sval; } %type <ent> var %type <fval> num %type <enode> e term %token <sval> STRING %token <ival> NUMBER %token <fval> FNUMBER %token <sval> WORD %token <ival> COL %token S_FORMAT %token S_LABEL %token S_LEFTSTRING %token S_RIGHTSTRING %token S_GET %token S_PUT %token S_MERGE %token S_LET %token S_WRITE %token S_TBL %token S_PROGLET %token S_COPY %token S_SHOW %token S_ERASE %token S_FILL %token S_GOTO %token K_FIXED %token K_SUM %token K_PROD %token K_AVG %token K_ACOS %token K_ASIN %token K_ATAN %token K_CEIL %token K_COS %token K_EXP %token K_FABS %token K_FLOOR %token K_HYPOT %token K_LN %token K_LOG %token K_PI %token K_POW %token K_SIN %token K_SQRT %token K_TAN %token K_DTR %token K_RTD %token K_MAX %token K_MIN %left '?' ':' %left '|' %left '&' %nonassoc '<' '=' '>' %left '+' '-' %left '*' '/' %left '^' %% command: S_LET var '=' e { let ($2, $4); } | S_LABEL var '=' STRING { label ($2, $4, 0); } | S_LEFTSTRING var '=' STRING { label ($2, $4, -1); } | S_RIGHTSTRING var '=' STRING { label ($2, $4, 1); } | S_FORMAT COL NUMBER NUMBER { fwidth[$2] = $3; FullUpdate++; modflg++; precision[$2] = $4; } | S_GET STRING { readfile ($2,1); } | S_MERGE STRING { readfile ($2,0); } | S_PUT STRING { (void) writefile ($2); } | S_WRITE STRING { printfile ($2); } | S_TBL STRING { tblprintfile ($2); } | S_SHOW COL ':' COL { showcol( $2, $4); } | S_SHOW NUMBER ':' NUMBER { showrow( $2, $4); } | S_COPY var var ':' var { copy($2, $3, $5); } | S_ERASE var ':' var { eraser($2, $4); } | S_FILL var ':' var num num { fill($2, $4, $5, $6); } | S_GOTO var {moveto($2); } | /* nothing */ | error; term: var { $$ = new_var('v', $1); } | K_FIXED term { $$ = new ('f', (struct enode *)0, $2); } | '@' K_SUM '(' var ':' var ')' { $$ = new (O_REDUCE('+'), (struct enode *)$4, (struct enode *)$6); } | '@' K_PROD '(' var ':' var ')' { $$ = new (O_REDUCE('*'), (struct enode *)$4, (struct enode *)$6); } | '@' K_AVG '(' var ':' var ')' { $$ = new (O_REDUCE('a'), (struct enode *)$4, (struct enode *)$6); } | '@' K_ACOS '(' e ')' { $$ = new(ACOS, (struct enode *)0, $4); } | '@' K_ASIN '(' e ')' { $$ = new(ASIN, (struct enode *)0, $4); } | '@' K_ATAN '(' e ')' { $$ = new(ATAN, (struct enode *)0, $4); } | '@' K_CEIL '(' e ')' { $$ = new(CEIL, (struct enode *)0, $4); } | '@' K_COS '(' e ')' { $$ = new(COS, (struct enode *)0, $4); } | '@' K_EXP '(' e ')' { $$ = new(EXP, (struct enode *)0, $4); } | '@' K_FABS '(' e ')' { $$ = new(FABS, (struct enode *)0, $4); } | '@' K_FLOOR '(' e ')' { $$ = new(FLOOR, (struct enode *)0, $4); } | '@' K_HYPOT '(' e ',' e ')' { $$ = new(HYPOT, $4, $6); } | '@' K_LN '(' e ')' { $$ = new(LOG, (struct enode *)0, $4); } | '@' K_LOG '(' e ')' { $$ = new(LOG10, (struct enode *)0, $4); } | '@' K_POW '(' e ',' e ')' { $$ = new(POW, $4, $6); } | '@' K_SIN '(' e ')' { $$ = new(SIN, (struct enode *)0, $4); } | '@' K_SQRT '(' e ')' { $$ = new(SQRT, (struct enode *)0, $4); } | '@' K_TAN '(' e ')' { $$ = new(TAN, (struct enode *)0, $4); } | '@' K_DTR '(' e ')' { $$ = new(DTR, (struct enode *)0, $4); } | '@' K_RTD '(' e ')' { $$ = new(RTD, (struct enode *)0, $4); } | '@' K_MAX '(' e ',' e ')' { $$ = new(MAX, $4, $6); } | '@' K_MIN '(' e ',' e ')' { $$ = new(MIN, $4, $6); } | '(' e ')' { $$ = $2; } | '+' term { $$ = $2; } | '-' term { $$ = new ('m', (struct enode *)0, $2); } | NUMBER { $$ = new_const('k', (double) $1); } | FNUMBER { $$ = new_const('k', $1); } | K_PI { $$ = new_const('k', (double)3.14159265358979323846); } | '~' term { $$ = new ('~', (struct enode *)0, $2); } | '!' term { $$ = new ('~', (struct enode *)0, $2); } ; e: e '+' e { $$ = new ('+', $1, $3); } | e '-' e { $$ = new ('-', $1, $3); } | e '*' e { $$ = new ('*', $1, $3); } | e '/' e { $$ = new ('/', $1, $3); } | e '^' e { $$ = new ('^', $1, $3); } | term | e '?' e ':' e { $$ = new ('?', $1, new(':', $3, $5)); } | e '<' e { $$ = new ('<', $1, $3); } | e '=' e { $$ = new ('=', $1, $3); } | e '>' e { $$ = new ('>', $1, $3); } | e '&' e { $$ = new ('&', $1, $3); } | e '|' e { $$ = new ('|', $1, $3); } | e '<' '=' e { $$ = new ('~', (struct enode *)0, new ('>', $1, $4)); } | e '!' '=' e { $$ = new ('~', (struct enode *)0, new ('=', $1, $4)); } | e '>' '=' e { $$ = new ('~', (struct enode *)0, new ('<', $1, $4)); } ; var: COL NUMBER { $$ = lookat($2 , $1); }; num: NUMBER { $$ = (double) $1; } | FNUMBER { $$ = $1; } | '-' num { $$ = -$2; } | '+' num { $$ = $2; } ; SHAR_EOF if test 4962 -ne "`wc -c gram.y`" then echo shar: error transmitting gram.y '(should have been 4962 characters)' fi echo shar: extracting interp.c '(17239 characters)' cat << \SHAR_EOF > 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 */ #include <math.h> #include <stdio.h> #ifdef BSD42 #include <strings.h> #else #ifndef SYSIII #include <string.h> #endif #endif #include <curses.h> #include "sc.h" #define DEFCOLDELIM ':' char *malloc(); #define PI (double)3.14159265358979323846 #define dtr(x) ((x)*(PI/(double)180.0)) #define rtd(x) ((x)*(180.0/(double)PI)) double dosum(minr, minc, maxr, maxc) int minr, minc, maxr, maxc; { double v; register r,c; register struct ent *p; v = 0; 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; } double doprod(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 = tbl[r][c]) && p->flags&is_valid) v *= p->v; return v; } double doavg(minr, minc, maxr, maxc) int minr, minc, maxr, maxc; { double v; register r,c,count; register struct ent *p; v = 0; count = 0; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) if ((p = tbl[r][c]) && p->flags&is_valid) { v += p->v; count++; } if (count == 0) return ((double) 0); return (v / (double)count); } 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 (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 '?': 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 ((double)!(int)eval(e->e.o.right)); case 'k': return (e->e.k); case 'v': return (e->e.v->v); case O_REDUCE('+'): case O_REDUCE('*'): case O_REDUCE('a'): { register r,c; 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; switch (e->op) { case O_REDUCE('+'): return dosum(minr, minc, maxr, maxc); case O_REDUCE('*'): return doprod(minr, minc, maxr, maxc); case O_REDUCE('a'): return doavg(minr, minc, maxr, maxc); } } case ACOS: return (acos(eval(e->e.o.right))); case ASIN: return (asin(eval(e->e.o.right))); case ATAN: return (atan(eval(e->e.o.right))); case CEIL: return (ceil(eval(e->e.o.right))); case COS: return (cos(eval(e->e.o.right))); case EXP: return (exp(eval(e->e.o.right))); case FABS: return (fabs(eval(e->e.o.right))); case FLOOR: return (floor(eval(e->e.o.right))); case HYPOT: return (hypot(eval(e->e.o.left), eval(e->e.o.right))); case LOG: return (log(eval(e->e.o.right))); case LOG10: return (log10(eval(e->e.o.right))); case POW: return (pow(eval(e->e.o.left), eval(e->e.o.right))); case SIN: return (sin(eval(e->e.o.right))); case SQRT: return (sqrt(eval(e->e.o.right))); case TAN: return (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 MIN: { double left, right; left = eval(e->e.o.left); right = eval(e->e.o.right); return (left < right ? left : right); } case MAX: { double left, right; left = eval(e->e.o.left); right = eval(e->e.o.right); return (left > right ? left : right); } } return((double) 0.0); /* safety net */ } #define MAXPROP 7 EvalAll () { int repct = 0; while (RealEvalAll() && (repct++ <= MAXPROP)); } int RealEvalAll () { register i,j; int chgct = 0; 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; chgct++; p->flags |= (is_changed|is_valid); } } return(chgct); } struct enode *new(op, a1, a2) struct enode *a1, *a2; { register struct enode *p = (struct enode *) malloc ((unsigned)sizeof (struct enode)); p->op = op; p->e.o.left = a1; p->e.o.right = a2; return p; } struct enode *new_var(op, a1) struct ent *a1; { register struct enode *p = (struct enode *) malloc ((unsigned)sizeof (struct enode)); p->op = op; p->e.v = a1; return p; } struct enode *new_const(op, a1) double a1; { register struct enode *p = (struct enode *) malloc ((unsigned)sizeof (struct enode)); p->op = op; p->e.k = a1; return p; } copy (dv, v1, v2) struct ent *dv, *v1, *v2; { register r,c; register struct ent *p; register struct ent *n; register deltar, deltac; int maxr, maxc; int minr, minc; int dr, dc; dr = dv->row; dc = dv->col; maxr = v2->row; maxc = v2->col; minr = v1->row; minc = v1->col; if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; if (dr+maxr-minr >= MAXROWS || dc+maxc-minc >= MAXCOLS) { error ("The table can't be any bigger"); return; } deltar = dr-minr; deltac = dc-minc; FullUpdate++; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) { n = lookat (r+deltar, c+deltac); clearent(n); if (p = tbl[r][c]) { n -> v = p -> v; n -> flags = p -> flags; n -> expr = copye(p->expr, deltar, deltac); n -> label = 0; if (p -> label) { n -> label = malloc ((unsigned)(strlen (p -> label) + 1)); strcpy (n -> label, p -> label); } } } } eraser(v1, v2) struct ent *v1, *v2; { FullUpdate++; flush_saved(); erase_area(v1->row, v1->col, v2->row, v2->col); } moveto(v) struct ent *v; { currow = v->row; curcol = v->col; } fill (v1, v2, start, inc) struct ent *v1, *v2; double start, inc; { register r,c; register struct ent *n; int maxr, maxc; int minr, minc; maxr = v2->row; maxc = v2->col; minr = v1->row; minc = v1->col; if (minr>maxr) r = maxr, maxr = minr, minr = r; if (minc>maxc) c = maxc, maxc = minc, minc = c; if (maxr >= MAXROWS) maxr = MAXROWS-1; if (maxc >= MAXCOLS) maxc = MAXCOLS-1; if (minr < 0) minr = 0; if (minr < 0) minr = 0; FullUpdate++; for (r = minr; r<=maxr; r++) for (c