sword@vu-vlsi.UUCP (Ronin) (01/28/88)
This is SC, and updated version of VC, of which I earlier spoke. I have not written this, so I can't help with bug fixes or problems. The sources are broken into two parts (a shar file). Concatenate the two parts together, then unshar them using /bin/sh. Have fun. ..lar ----- Larry Esmonde, Director of SWORD (Students Working On R & D) Computer Science Dept. Villanova University Villanova, Pa. 19085 UUCP: {bpa,cbmvax,psuvax1}!vu-vlsi!sword / BITNET: sword@vuvaxcom ----------------------CUT HERE, PART 01------------------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # Makefile # README # cmds.c # crypt.c # cvt.sed # eres.sed # gram.y # interp.c # lex.c # make.log # makefile.dist # range.c # sc.c # sc.doc # sc.h # sres.sed # xmalloc.c # This archive created: Wed Jan 27 22:39:33 1988 export PATH; PATH=/bin:$PATH if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat << \SHAR_EOF > 'Makefile' # Specify the name of the program. # All documentation and installation keys on this value. # name=vcalc NAME=VCALC # This is where the install step puts it. EXDIR=/usr/local/bin # This is where the man page goes. MANDIR=/usr/man/manl # All of the source files SRC=sc.h sc.c lex.c gram.y interp.c cmds.c crypt.c xmalloc.c range.c eres.sed\ sres.sed makefile cvt.sed # The documents in the Archive DOCS=README $(name).man sc.doc # Set SIMPLE for lex.c if you don't want arrow keys or lex.c blows up #SIMPLE=-DSIMPLE # Set QUICK if you want to enter numbers without "=" first #QUICK=-DQUICK # Use this for system V.2 #CFLAGS= -O -DSYSV2 #LDFLAGS= #LIB=-lm -lcurses # Use this for system V.3 #CFLAGS= -O -DSYSV3 #LDFLAGS= #LIB=-lm -lcurses # Use this for BSD 4.2 CFLAGS= -O -DBSD42 LDFLAGS= LIB=-lm -lcurses -ltermcap # Use this for BSD 4.3 #CFLAGS= -O -DBSD43 #LDFLAGS= #LIB=-lm -lcurses -ltermcap # Use this for system III (XENIX) #CFLAGS= -O -DSYSIII #LDFLAGS= -i #LIB=-lm -lcurses -ltermcap # Use this for VENIX #CFLAGS= -DVENIX -DBSD42 -DV7 #LDFLAGS= -z -i #LIB=-lm -lcurses -ltermcap # The objects OBJS=sc.o lex.o gram.o interp.o cmds.o crypt.o xmalloc.o range.o $(name): $(OBJS) cc ${CFLAGS} ${LDFLAGS} ${OBJS} ${LIB} -o $(name) diff_to_sc: diff_to_sc.c cc ${CFLAGS} -o dtv diff_to_sc.c pvc: pvc.c cc ${CFLAGS} -o pvc pvc.c cp pvc $(EXDIR)/pvc lex.o: sc.h y.tab.h gram.o cc ${CFLAGS} ${SIMPLE} -c lex.c sc.o: sc.h sc.c cc ${CFLAGS} ${QUICK} -c sc.c interp.o: interp.c sc.h gram.o: sc.h y.tab.h cmds.o: cmds.c sc.h crypt.o: crypt.c sc.h range.o: range.c sc.h y.tab.h: gram.y gram.o: sc.h y.tab.h gram.c cc ${CFLAGS} -c gram.c sed<gram.y >experres.h -f eres.sed;sed < gram.y > statres.h -f sres.sed gram.c: gram.y yacc -d gram.y; mv y.tab.c gram.c clean: rm -f *.o *res.h y.tab.h $(name) debug core gram.c $(name).1 shar: ${SRC} ${DOCS} shar -c -m 55000 -f shar ${DOCS} ${SRC} lint: sc.h sc.c lex.c gram.c interp.c cmds.c crypt.c lint ${CFLAGS} ${SIMPLE} ${QUICK} sc.c lex.c gram.c interp.c cmds.c crypt.c range.c -lcurses -lm print: sc.h gram.y sc.c lex.c interp.c cmds.c crypt.c prc sc.h gram.y sc.c lex.c interp.c cmds.c crypt.c | lpr $(name).1: sc.doc sed -e s/pname/$(name)/g -e s/PNAME/$(NAME)/g sc.doc > $(name).1 $(name).man: $(name).1 -mv $(name).man $(name).mold nroff -man $(name).1 > $(name).man install: $(EXDIR)/$(name) inst-man: $(MANDIR)/$(name).1 $(EXDIR)/$(name): $(name) -mv $(EXDIR)/$(name) $(EXDIR)/$(name).old strip $(name) cp $(name) $(EXDIR) $(MANDIR)/$(name).l: $(name).1 cp $(name).1 $(MANDIR)/$(name).l SHAR_EOF if test 2595 -ne "`wc -c < 'Makefile'`" then echo shar: error transmitting "'Makefile'" '(should have been 2595 characters)' fi fi # end of overwriting check if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' This is a much modified version of the public domain spread sheet sc, posted a year or two ago by Mark Weiser as vc, originally by James Gosling. Changes since my last version (3.1): 1) More portable external declarations 2) Range names 3) Encryption (Thanks to Bradley Williams) 4) @rnd rounding operator 5) 5.3 compatibility (%$#@% curses!) 6) @stddev standard deviation function 7) max, min changed to range functions (NOT COMPATIBLE WITH LAST RELEASE!) 8) Clean up and bug fixes Thanks to Larry Campbell for the xmalloc stuff, Eric Goldman, Carl Clawson, Narayan Mohanram, Greg Franks, Rick Daley and Nick (lai@ucla) for bug reports and enhancements. I had several requests for a modification that I don't personally like. Since Larry Campbell sent the mods, I compromised and added them under the compilation flag "QUICK". If you want to enter numeric constants into cell locations by just typing the number without a leading "=", set "QUICK" in the makefile. The down side of the change is you must always type ^U before you can enter a leading count parameter for a command or before "0" to return to column 0. Since many of the commands allow a leading count, I felt the change was not a win. I did not document the mod in the man page since I don't use it. I have modified the makefile to make it easy for you to call the program what you want (I saw at least five different names in correspondence and on the net). Just change "name=sc" and "NAME=SC" to "name=myfavoritename" and "NAME=MYFAVORITENAME" and try "make myfavoritename". Similarly, you can make the documentation with "make myfavoritename.man". "make install" will make and install the code in EXDIR. The installation steps and documentation all key off of the name. The makefile even changes the name in the nroffable man page. If you don't have nroff, you will have to change sc.man yourself. The code has been tested against a Vax running 4.2 and 4.3 and a National ICM-3216 with system V.2 and V.3. The ICM has a National Semi 32016. Just check the makefile for the system flags. I have heard reports of lots of other machines that work. I have added ifdefs for system III and for Berkeley 4.3. If you have problems with lex.c, and don't care about arrow keys, define SIMPLE (-DSIMPLE in the makefile). SIMPLE causes the arrow keys to not be used. Disclaimer: Sc is not a product of National Semiconductor. It is supplied as is with no warranty, express or implied, as a service to Usenet readers. Bob Bond Robert Bond ihnp4!nsc!nscpdc!rgb National Semiconductor tektronix!nscpdc!rgb SHAR_EOF if test 2613 -ne "`wc -c < 'README'`" then echo shar: error transmitting "'README'" '(should have been 2613 characters)' fi fi # end of overwriting check if test -f 'cmds.c' then echo shar: will not over-write existing file "'cmds.c'" else cat << \SHAR_EOF > 'cmds.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 <curses.h> #include "sc.h" #ifdef BSD42 #include <strings.h> #else #ifndef SYSIII #include <string.h> #endif #endif char *xmalloc(); duprow() { if (currow >= MAXROWS - 1 || maxrow >= MAXROWS - 1) { error ("The table can't be any bigger"); return; } modflg++; currow++; openrow (currow); for (curcol = 0; curcol <= maxcol; curcol++) { register struct ent *p = tbl[currow - 1][curcol]; if (p) { register struct ent *n; n = lookat (currow, curcol); n -> v = p -> v; n -> flags = p -> flags; n -> expr = copye (p -> expr, 1, 0); n -> label = 0; if (p -> label) { n -> label = (char *) xmalloc ((unsigned)(strlen (p -> label) + 1)); strcpy (n -> label, p -> label); } } } for (curcol = 0; curcol <= maxcol; curcol++) { register struct ent *p = tbl[currow][curcol]; if (p && (p -> flags & is_valid) && !p -> expr) break; } if (curcol > maxcol) curcol = 0; } dupcol() { if (curcol >= MAXCOLS - 1 || maxcol >= MAXCOLS - 1) { error ("The table can't be any wider"); return; } modflg++; curcol++; opencol (curcol); for (currow = 0; currow <= maxrow; currow++) { register struct ent *p = tbl[currow][curcol - 1]; if (p) { register struct ent *n; n = lookat (currow, curcol); n -> v = p -> v; n -> flags = p -> flags; n -> expr = copye (p -> expr, 0, 1); n -> label = 0; if (p -> label) { n -> label = (char *) xmalloc ((unsigned) (strlen (p -> label) + 1)); strcpy (n -> label, p -> label); } } } for (currow = 0; currow <= maxrow; currow++) { register struct ent *p = tbl[currow][curcol]; if (p && (p -> flags & is_valid) && !p -> expr) break; } if (currow > maxrow) currow = 0; } insertrow(arg) { while (--arg>=0) openrow (currow); } deleterow(arg) { flush_saved(); erase_area(currow, 0, currow + arg - 1, maxcol); currow += arg; while (--arg>=0) closerow (--currow); sync_refs(); } insertcol(arg) { while (--arg>=0) opencol(curcol); } deletecol(arg) { flush_saved(); erase_area(0, curcol, maxrow, curcol + arg - 1); curcol += arg; while (--arg>=0) closecol (--curcol); sync_refs(); } rowvalueize(arg) { valueize_area(currow, 0, currow + arg - 1, maxcol); } colvalueize(arg) { valueize_area(0, curcol, maxrow, curcol + arg - 1); } erase_area(sr, sc, er, ec) int sr, sc, er, ec; { register int r, c; register struct ent **p; if (sr > er) { r = sr; sr = er; er= r; } if (sc > ec) { c = sc; sc = ec; ec= c; } if (sr < 0) sr = 0; if (sc < 0) sc = 0; if (er >= MAXROWS) er = MAXROWS-1; if (ec >= MAXCOLS) ec = MAXCOLS-1; for (r = sr; r <= er; r++) { for (c = sc; c <= ec; c++) { p = &tbl[r][c]; if (*p) { free_ent(*p); *p = 0; } } } } valueize_area(sr, sc, er, ec) int sr, sc, er, ec; { register int r, c; register struct ent *p; if (sr > er) { r = sr; sr = er; er= r; } if (sc > ec) { c = sc; sc = ec; ec= c; } if (sr < 0) sr = 0; if (sc < 0) sc = 0; if (er >= MAXROWS) er = MAXROWS-1; if (ec >= MAXCOLS) ec = MAXCOLS-1; for (r = sr; r <= er; r++) { for (c = sc; c <= ec; c++) { p = tbl[r][c]; if (p && p->expr) { efree(p->expr); p->expr = 0; } } } } pullcells(to_insert) { register struct ent *p, *n; register int deltar, deltac; int minrow, mincol; int maxrow, maxcol; int numrows, numcols; if (!to_fix) return; switch (to_insert) { case 'm': case 'r': case 'c': break; default: error("Invalid pull command"); return; } minrow = MAXROWS; mincol = MAXCOLS; maxrow = 0; maxcol = 0; for (p = to_fix; p; p = p->next) { if (p->row < minrow) minrow = p->row; if (p->row > maxrow) maxrow = p->row; if (p->col < mincol) mincol = p->col; if (p->col > maxcol) maxcol = p->col; } numrows = maxrow - minrow + 1; numcols = maxcol - mincol + 1; deltar = currow - minrow; deltac = curcol - mincol; if (to_insert == 'r') { insertrow(numrows); deltac = 0; } else if (to_insert == 'c') { insertcol(numcols); deltar = 0; } FullUpdate++; modflg++; for (p = to_fix; p; p = p->next) { n = lookat (p->row + deltar, p->col + deltac); clearent(n); n -> flags = p -> flags & ~is_deleted; n -> v = p -> v; n -> expr = copye(p->expr, deltar, deltac); n -> label = 0; if (p -> label) { n -> label = (char *) xmalloc((unsigned)(strlen(p->label)+1)); strcpy (n -> label, p -> label); } } } colshow_op() { register int i,j; for (i=0; i<MAXCOLS; i++) if (col_hidden[i]) break; for(j=i; j<MAXCOLS; j++) if (!col_hidden[j]) break; j--; if (i<MAXCOLS) { sprintf(line,"show %s:", coltoa(i)); sprintf(line + strlen(line),"%s",coltoa(j)); linelim = strlen (line); } } rowshow_op() { register int i,j; for (i=0; i<MAXROWS; i++) if (row_hidden[i]) break; for(j=i; j<MAXROWS; j++) if (!row_hidden[j]) { break; } j--; if (i<MAXROWS) { sprintf(line,"show %d:%d", i, j); linelim = strlen (line); } } get_qual() { register int c; c = nmgetch(); switch (c) { case 'c': case 'j': case 'k': case ctl(p): case ctl(n): return('c'); case 'r': case 'l': case 'h': case ctl(f): case ctl(b): return('r'); default: return(c); } /*NOTREACHED*/ } openrow (rs) { register r; register struct ent **p; register c; register i; if (rs > maxrow) maxrow = rs; if (maxrow >= MAXROWS - 1 || rs > MAXROWS - 1) { error ("The table can't be any longer"); return; } for (i = maxrow+1; i > rs; i--) { row_hidden[i] = row_hidden[i-1]; } for (r = ++maxrow; r > rs; r--) for (c = maxcol + 1, p = &tbl[r][0]; --c >= 0; p++) if (p[0] = p[-MAXCOLS]) p[0] -> row++; p = &tbl[rs][0]; for (c = maxcol + 1; --c >= 0;) *p++ = 0; FullUpdate++; modflg++; } closerow (r) register r; { register struct ent **p; register c; register int i; if (r > maxrow) return; p = &tbl[r][0]; for (c=maxcol+1; --c>=0; ) { if (*p) free_ent(*p); *p++ = 0; } for (i = r; i < MAXROWS - 1; i++) { row_hidden[i] = row_hidden[i+1]; } while (r<maxrow) { for (c = maxcol+1, p = &tbl[r][0]; --c>=0; p++) if (p[0] = p[MAXCOLS]) p[0]->row--; r++; } p = &tbl[maxrow][0]; for (c=maxcol+1; --c>=0; ) *p++ = 0; maxrow--; FullUpdate++; modflg++; } opencol (cs) { register r; register struct ent **p; register c; register lim = maxcol-cs+1; int i; if (cs > maxcol) maxcol = cs; if (maxcol >= MAXCOLS - 1 || cs > MAXCOLS - 1) { error ("The table can't be any wider"); return; } for (i = maxcol+1; i > cs; i--) { fwidth[i] = fwidth[i-1]; precision[i] = precision[i-1]; col_hidden[i] = col_hidden[i-1]; } /* fwidth[cs] = DEFWIDTH; precision[i] = DEFPREC; */ for (r=0; r<=maxrow; r++) { p = &tbl[r][maxcol+1]; for (c=lim; --c>=0; p--) if (p[0] = p[-1]) p[0]->col++; p[0] = 0; } maxcol++; FullUpdate++; modflg++; } closecol (cs) { register r; register struct ent **p; register struct ent *q; register c; register lim = maxcol-cs; int i; if (lim < 0) return; for (r=0; r<=maxrow; r++) if (q = tbl[r][cs]) { free_ent(q); } for (r=0; r<=maxrow; r++) { p = &tbl[r][cs]; for (c=lim; --c>=0; p++) if (p[0] = p[1]) p[0]->col--; p[0] = 0; } for (i = cs; i < MAXCOLS - 1; i++) { fwidth[i] = fwidth[i+1]; precision[i] = precision[i+1]; col_hidden[i] = col_hidden[i+1]; } maxcol--; FullUpdate++; modflg++; } SHAR_EOF if test 8123 -ne "`wc -c < 'cmds.c'`" then echo shar: error transmitting "'cmds.c'" '(should have been 8123 characters)' fi fi # end of overwriting check if test -f 'crypt.c' then echo shar: will not over-write existing file "'crypt.c'" else cat << \SHAR_EOF > 'crypt.c' /* * Encryption utilites * Bradley Williams * {allegra,ihnp4,uiucdcs,ctvax}!convex!williams */ #include <stdio.h> #include <curses.h> #if defined(BSD42) || defined(BSD43) #include <sys/file.h> #else #include <sys/fcntl.h> #endif #include "sc.h" extern char curfile[]; char *strcpy(); int Crypt = 0; #define DEFWIDTH 10 #define DEFPREC 2 creadfile (fname, eraseflg) char *fname; { register FILE *f; int pipefd[2]; int fildes; int pid; char save[1024]; if (*fname == 0) fname = &curfile[0]; strcpy(save,fname); if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return; fildes = open (save, O_RDONLY, 0); if (fildes < 0) { error ("Can't read %s", save); return; } if (eraseflg) erasedb (); pipe (pipefd); /* make pipe to child */ deraw(); if ((pid=fork()) == 0) /* if child */ { close (0); /* close stdin */ close (1); /* close stdout */ close (pipefd[0]); /* close pipe input */ dup (fildes); /* standard in from file */ dup (pipefd[1]); /* connect to pipe */ fprintf (stderr, " "); execl ("/bin/sh", "sh", "-c", "crypt", 0); exit (-127); } else /* else parent */ { close (fildes); close (pipefd[1]); /* close pipe output */ f = fdopen (pipefd[0], "r"); if (f == 0) { kill (pid, -9); error ("Can't fdopen file %s", save); close (pipefd[0]); return; } } while (fgets(line,sizeof line,f)) { linelim = 0; if (line[0] != '#') yyparse (); } fclose (f); close (pipefd[0]); while (pid != wait(&fildes)) /**/; goraw(); linelim = -1; modflg++; if (eraseflg) { strcpy (curfile,save); modflg = 0; } EvalAll(); } cwritefile (fname) char *fname; { register FILE *f; register struct ent **p; register r, c; int pipefd[2]; int fildes; int pid; char save[1024]; if (*fname == 0) fname = &curfile[0]; strcpy(save,fname); fildes = open (save, O_WRONLY|O_CREAT, 0600); if (fildes < 0) { error ("Can't create %s", save); return(-1); } pipe (pipefd); /* make pipe to child */ deraw(); if ((pid=fork()) == 0) /* if child */ { close (0); /* close stdin */ close (1); /* close stdout */ close (pipefd[1]); /* close pipe output */ dup (pipefd[0]); /* connect to pipe input */ dup (fildes); /* standard out to file */ fprintf (stderr, " "); execl ("/bin/sh", "sh", "-c", "crypt", 0); exit (-127); } else /* else parent */ { close (fildes); close (pipefd[0]); /* close pipe input */ f = fdopen (pipefd[1], "w"); if (f == 0) { kill (pid, -9); error ("Can't fdopen file %s", save); close (pipefd[1]); 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); close (pipefd[1]); while (pid != wait(&fildes)) /**/; strcpy(curfile,save); modflg = 0; error("File '%s' written.",curfile); goraw(); return(0); } SHAR_EOF if test 3654 -ne "`wc -c < 'crypt.c'`" then echo shar: error transmitting "'crypt.c'" '(should have been 3654 characters)' fi fi # end of overwriting check if test -f 'cvt.sed' then echo shar: will not over-write existing file "'cvt.sed'" else cat << \SHAR_EOF > 'cvt.sed' s!+/\(r.*c.*:r.*c[0-9]*\)!@sum(\1)! s/\(r[0-9]*\)\(c[0-9]*\)/\2\1/g s/c10/k/g s/c11/l/g s/c12/m/g s/c13/n/g s/c14/o/g s/c15/p/g s/c16/q/g s/c17/r/g s/c18/s/g s/c19/t/g s/c20/u/g s/c21/v/g s/c22/w/g s/c23/x/g s/c24/y/g s/c25/z/g s/c26/aa/g s/c27/ab/g s/c28/ac/g s/c29/ad/g s/c30/ae/g s/c31/af/g s/c32/ag/g s/c33/ah/g s/c34/ai/g s/c35/aj/g s/c36/ak/g s/c37/al/g s/c38/am/g s/c39/an/g s/c0/a/g s/c1/b/g s/c2/c/g s/c3/d/g s/c4/e/g s/c5/f/g s/c6/g/g s/c7/h/g s/c8/i/g s/c9/j/g s/r\([0-9][0-9]*\)/\1/g s/format 10/format k/g s/format 11/format l/g s/format 12/format m/g s/format 13/format n/g s/format 14/format o/g s/format 15/format p/g s/format 16/format q/g s/format 17/format r/g s/format 18/format s/g s/format 19/format t/g s/format 20/format u/g s/format 21/format v/g s/format 22/format w/g s/format 23/format x/g s/format 24/format y/g s/format 25/format z/g s/format 26/format aa/g s/format 27/format ab/g s/format 28/format ac/g s/format 29/format ad/g s/format 30/format ae/g s/format 31/format af/g s/format 32/format ag/g s/format 33/format ah/g s/format 34/format ai/g s/format 35/format aj/g s/format 36/format ak/g s/format 37/format al/g s/format 38/format am/g s/format 39/format an/g s/format 0/format a/g s/format 1/format b/g s/format 2/format c/g s/format 3/format d/g s/format 4/format e/g s/format 5/format f/g s/format 6/format g/g s/format 7/format h/g s/format 8/format i/g s/format 9/format j/g SHAR_EOF if test 1420 -ne "`wc -c < 'cvt.sed'`" then echo shar: error transmitting "'cvt.sed'" '(should have been 1420 characters)' fi fi # end of overwriting check if test -f 'eres.sed' then echo shar: will not over-write existing file "'eres.sed'" else cat << \SHAR_EOF > 'eres.sed' /%token.*K_/!d /%token.*K_\(.*\)/s// "\1", K_\1,/ SHAR_EOF if test 50 -ne "`wc -c < 'eres.sed'`" then echo shar: error transmitting "'eres.sed'" '(should have been 50 characters)' fi fi # end of overwriting check if test -f 'gram.y' then echo shar: will not over-write existing file "'gram.y'" else 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; RANGE_S rval; } %type <ent> var %type <fval> num %type <rval> range %type <enode> e term %token <sval> STRING %token <ival> NUMBER %token <fval> FNUMBER %token <rval> RANGE %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_COPY %token S_SHOW %token S_ERASE %token S_FILL %token S_GOTO %token S_DEFINE %token S_UNDEFINE %token K_FIXED %token K_SUM %token K_PROD %token K_AVG %token K_STDDEV %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 %token K_RND %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 ':' COL NUMBER NUMBER { int i; for(i = $2; i<=$4; i++) fwidth[i] = $5, precision[i] = $6; FullUpdate++; modflg++;} | 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 range { copy($2, $3.left, $3.right); } | S_ERASE range { eraser($2.left, $2.right); } | S_FILL range num num { fill($2.left, $2.right, $3, $4); } | S_GOTO var {moveto($2); } | S_DEFINE STRING range { add_range($2, $3.left, $3.right); } | S_DEFINE STRING var { add_range($2, $3, $3); } | S_UNDEFINE range { del_range($2.left, $2.right); } | /* nothing */ | error; term: var { $$ = new_var('v', $1); } | K_FIXED term { $$ = new ('f', (struct enode *)0, $2); } | '@' K_SUM '(' range ')' { $$ = new (O_REDUCE('+'), (struct enode *)$4.left, (struct enode *)$4.right); } | '@' K_PROD '(' range ')' { $$ = new (O_REDUCE('*'), (struct enode *)$4.left, (struct enode *)$4.right); } | '@' K_AVG '(' range ')' { $$ = new (O_REDUCE('a'), (struct enode *)$4.left, (struct enode *)$4.right); } | '@' K_STDDEV '(' range ')' { $$ = new (O_REDUCE('s'), (struct enode *)$4.left, (struct enode *)$4.right); } | '@' K_MAX '(' range ')' { $$ = new (O_REDUCE(MAX), (struct enode *)$4.left, (struct enode *)$4.right); } | '@' K_MIN '(' range ')' { $$ = new (O_REDUCE(MIN), (struct enode *)$4.left, (struct enode *)$4.right); } | '@' 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_RND '(' e ')' { $$ = new(RND, (struct enode *)0, $4); } | '(' 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)); } ; range: var ':' var { $$.left = $1; $$.right = $3; } | RANGE { $$ = $1; } ; var: COL NUMBER { $$ = lookat($2 , $1); } | RANGE { $$ = $1.left; } ; num: NUMBER { $$ = (double) $1; } | FNUMBER { $$ = $1; } | '-' num { $$ = -$2; } | '+' num { $$ = $2; } ; SHAR_EOF if test 5891 -ne "`wc -c < 'gram.y'`" then echo shar: error transmitting "'gram.y'" '(should have been 5891 characters)' fi fi # end of overwriting check if test -f 'interp.c' then echo shar: will not over-write existing file "'interp.c'" else 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 *xmalloc(); #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 dostddev(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 = 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)))); } double domax(minr, minc, maxr, maxc) int minr, minc, maxr, maxc; { double v; register r,c,count; register struct ent *p; count = 0; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) if ((p = 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); } double domin(minr, minc, maxr, maxc) int minr, minc, maxr, maxc; { double v; register r,c,count; register struct ent *p; count = 0; for (r = minr; r<=maxr; r++) for (c = minc; c<=maxc; c++) if ((p = 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); } 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'): case O_REDUCE('s'): case O_REDUCE(MAX): case O_REDUCE(MIN): { 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 O_REDUCE('s'): return dostddev(minr, minc, maxr, maxc); case O_REDUCE(MAX): return domax(minr, minc, maxr, maxc); case O_REDUCE(MIN): return domin(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: { double arg = eval(e->e.o.right); return arg ? log(arg) : 0; } case LOG10: { double arg = eval(e->e.o.right); return arg ? log10(arg) : 0; } 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 RND: { double temp; temp = eval(e->e.o.right); return(temp-floor(temp) < 0.5 ? floor(temp) : ceil(temp)); } } 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 *) xmalloc ((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 *) xmalloc ((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 *) xmalloc ((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 = xmalloc ((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); sync_refs(); } 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 = minc; c<=maxc; c++) { n = lookat (r, c); clearent(n); n->v = start; start += inc; n->flags |= (is_changed|is_valid); } } 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++; modflg++; } clearent (v) struct ent *v; { if (!v) return; label(v,"",-1); v->v = 0; if (v->expr) efree(v->expr); v->expr = 0; v->flags |= (is_changed); v->flags &= ~(is_valid); changed++; modflg++; } 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 && (e->op&~0177) != O_REDUCE(0)) { efree (e->e.o.left); efree (e->e.o.right); } xfree ((char *)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) xfree((char *)(v->label)); if (s && s[0]) { v->label = xmalloc ((unsigned)(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++; modflg++; } } decodev (v) register struct ent *v; { register struct range *r; if (!v) sprintf (line+linelim,"VAR?"); else if (r = find_range((char *)0, 0, v, v)) sprintf(line+linelim, "%s", r->r_name); else sprintf (line+linelim, "%s%d", coltoa(v->col), v->row); linelim += strlen (line+linelim); } char * coltoa(col) int col; { static char rname[3]; register char *p = rname; if (col > 25) { *p++ = col/26 + 'A' - 1; col %= 26; } *p++ = col+'A'; *p = 0; return(rname); } decompile(e, priority) register struct enode *e; { register char *s; 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; case '^': mypriority = 12; break; } if (mypriority<priority) line[linelim++] = '('; switch (e->op) { case 'f': { 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,"%.15g",e->e.k); linelim += strlen (line+linelim); break; case O_REDUCE('+'): s = "@sum("; goto more; case O_REDUCE('*'): s = "@prod("; goto more; case O_REDUCE('s'): s = "@stddev("; goto more; case O_REDUCE(MAX): s = "@max("; goto more; case O_REDUCE(MIN): s = "@min("; goto more; case O_REDUCE('a'): s = "@avg("; /* fall though to more; */ more: { struct range *r; for (; line[linelim++] = *s++;); linelim--; if (r = find_range((char *)0, 0, (struct ent *) e->e.o.left, (struct ent *) e->e.o.right)) { sprintf(line+linelim, "%s", r->r_name); linelim += strlen(line+linelim); } else { decodev ((struct ent *) e->e.o.left); line[linelim++] = ':'; decodev ((struct ent *) e->e.o.right); } line[linelim++] = ')'; break; } case ACOS: s = "@acos("; goto more1; case ASIN: s = "@asin("; goto more1; case ATAN: s = "@atan("; goto more1; case CEIL: s = "@ceil("; goto more1; case COS: s = "@cos("; goto more1; case EXP: s = "@exp("; goto more1; case FABS: s = "@fabs("; goto more1; case FLOOR: s = "@floor("; goto more1; case HYPOT: s = "@hypot("; goto more2; case LOG: s = "@ln("; goto more1; case LOG10: s = "@log("; goto more1; case POW: s = "@pow("; goto more2; case SIN: s = "@sin("; goto more1; case SQRT: s = "@sqrt("; goto more1; case TAN: s = "@tan("; goto more1; case DTR: s = "@dtr("; goto more1; case RTD: s = "@rtd("; goto more1; case RND: s = "@rnd("; goto more1; more1: for (; line[linelim++] = *s++;); linelim--; decompile (e->e.o.right, 0); line[linelim++] = ')'; break; more2: for (; line[linelim++] = *s++;); linelim--; decompile (e->e.o.left, 0); line[linelim++] = ','; decompile (e->e.o.right, 0); line[linelim++] = ')'; break; default: decompile (e->e.o.left, mypriority); line[linelim++] = e->op; decompile (e->e.o.right, mypriority+1); break; } if (mypriority<priority) line[linelim++] = ')'; } else line[linelim++] = '?'; } editv (row, col) { sprintf (line, "let %s = ", v_name(row, col)); linelim = strlen(line); editexp(row,col); } editexp(row,col) { register struct ent *p; p = lookat (row, col); if (p->flags&is_valid) if (p->expr) { decompile (p->expr, 0); line[linelim] = 0; } else { sprintf (line+linelim, "%.15g", p->v); linelim += strlen (line+linelim); } } edits (row, col) { register struct ent *p = lookat (row, col); sprintf (line, "%sstring %s = \"", ((p->flags&is_leftflush) ? "left" : "right"), v_name(row, col)); linelim = strlen(line); if (p->label) { sprintf (line+linelim, "%s", p->label); linelim += strlen (line+linelim); } } printfile (fname) char *fname; { FILE *f; char pline[1000]; int plinelim; int pid; register row, col; register struct ent **p; f = openout(fname, &pid); if (f==0) { error ("Can't create %s", fname); return; } for (row=0;row<=maxrow; row++) { register c = 0; pline[plinelim=0] = '\0'; for (p = &tbl[row][col=0]; col<=maxcol; col++, p++) { if (*p) { char *s; while (plinelim<c) pline[plinelim++] = ' '; plinelim = c; if ((*p)->flags&is_valid) { sprintf (pline+plinelim,"%*.*f",fwidth[col],precision[col], (*p)->v); plinelim += strlen (pline+plinelim); } if (s = (*p)->label) { register char *d; d = pline+((*p)->flags&is_leftflush ? c : c-strlen(s)+fwidth[col]); while (d>pline+plinelim) pline[plinelim++] = ' '; if (d<pline) d = pline; while (*s) *d++ = *s++; if (d-pline>plinelim) plinelim = d-pline; } } c += fwidth [col]; } fprintf (f,"%.*s\n",plinelim,pline); } closeout(f, pid); } tblprintfile (fname) char *fname; { FILE *f; char pline[1000]; int pid; register row, col; register struct ent **p; char coldelim = DEFCOLDELIM; f = openout(fname, &pid); if (f==0) { error ("Can't create %s", fname); return; } for (row=0;row<=maxrow; row++) { for (p = &tbl[row][col=0]; col<=maxcol; col++, p++) { if (*p) { char *s; if ((*p)->flags&is_valid) { fprintf (f,"%.*f",precision[col], (*p)->v); } if (s = (*p)->label) { fprintf (f,"%s",s); } } fprintf(f,"%c",coldelim); } fprintf (f,"\n",pline); } closeout(f, pid); } struct enode *copye (e, Rdelta, Cdelta) register struct enode *e; { register struct enode *ret; if (e==0) ret = 0; else { ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode)); ret->op = e->op; switch (ret->op) { case 'v': ret->e.v = lookat (e->e.v->row+Rdelta, e->e.v->col+Cdelta); break; case 'k': ret->e.k = e->e.k; break; case 'f': ret->e.o.right = copye (e->e.o.right,0,0); ret->e.o.left = 0; break; case O_REDUCE('+'): case O_REDUCE('*'): case O_REDUCE('a'): case O_REDUCE('s'): case O_REDUCE(MAX): case O_REDUCE(MIN): ret->e.o.right = (struct enode *) lookat ( ((struct ent *)e->e.o.right)->row+Rdelta, ((struct ent *)e->e.o.right)->col+Cdelta ); ret->e.o.left = (struct enode *) lookat ( ((struct ent *)e->e.o.left)->row+Rdelta, ((struct ent *)e->e.o.left)->col+Cdelta ); break; default: ret->e.o.right = copye (e->e.o.right,Rdelta,Cdelta); ret->e.o.left = copye (e->e.o.left,Rdelta,Cdelta); break; } } return ret; } /* * sync_refs and syncref are used to remove references to * deleted struct ents. Note that the deleted structure must still * be hanging around before the call, but not referenced by an entry * in tbl. Thus the free_ent, fix_ent calls in sc.c */ sync_refs () { register i,j; register struct ent *p; sync_ranges(); for (i=0; i<=maxrow; i++) for (j=0; j<=maxcol; j++) if ((p=tbl[i][j]) && p->expr) syncref(p->expr); } syncref(e) register struct enode *e; { if (e==0) return; else { switch (e->op) { case 'v': e->e.v = lookat(e->e.v->row, e->e.v->col); break; case 'k': break; case O_REDUCE('+'): case O_REDUCE('*'): case O_REDUCE('a'): case O_REDUCE('s'): case O_REDUCE(MAX): case O_REDUCE(MIN): e->e.o.right = (struct enode *) lookat ( ((struct ent *)e->e.o.right)->row, ((struct ent *)e->e.o.right)->col ); e->e.o.left = (struct enode *) lookat ( ((struct ent *)e->e.o.left)->row, ((struct ent *)e->e.o.left)->col ); break; default: syncref(e->e.o.right); syncref(e->e.o.left); break; } } } hiderow(arg) { register int r1; register int r2; r1 = currow; r2 = r1 + arg - 1; if (r1 < 0 || r1 > r2) { error("Invalid Range"); return; } if (r2 > MAXROWS-2) { error("You can't hide the last row"); return; } FullUpdate++; while (r1 <= r2) row_hidden[r1++] = 1; } hidecol(arg) { register int c1; register int c2; c1 = curcol; c2 = c1 + arg - 1; if (c1 < 0 || c1 > c2) { error("Invalid Range"); return; } if (c2 > MAXCOLS-2) { error("You can't hide the last col"); return; } FullUpdate++; while (c1 <= c2) col_hidden[c1++] = 1; } showrow(r1, r2) { if (r1 < 0 || r1 > r2) { error("Invalid Range"); return; } if (r2 > MAXROWS-1) { r2 = MAXROWS-1; } FullUpdate++; while (r1 <= r2) row_hidden[r1++] = 0; } showcol(c1, c2) { if (c1 < 0 || c1 > c2) { error("Invalid Range"); return; } if (c2 > MAXCOLS-1) { c2 = MAXCOLS-1; } FullUpdate++; while (c1 <= c2) col_hidden[c1++] = 0; } /* Open the output file, setting up a pipe if needed */ FILE * openout(fname, rpid) char *fname; int *rpid; { int pipefd[2]; int pid; FILE *f; while (*fname && (*fname == ' ')) /* Skip leading blanks */ fname++; if (*fname != '|') { /* Open file if not pipe */ *rpid = 0; return(fopen(fname, "w")); } fname++; /* Skip | */ deraw(); pipe (pipefd); /* make pipe to child */ if ((pid=fork()) == 0) /* if child */ { close (0); /* close stdin */ close (pipefd[1]); dup (pipefd[0]); /* connect to pipe input */ execl ("/bin/sh", "sh", "-c", fname, 0); exit (-127); } else /* else parent */ { *rpid = pid; f = fdopen (pipefd[1], "w"); if (f == 0) { kill (pid, -9); error ("Can't fdopen output"); close (pipefd[1]); *rpid = 0; return(0); } } return(f); } closeout(f, pid) FILE *f; int pid; { int temp; fclose (f); if (pid) { while (pid != wait(&temp)) /**/; printf("Press <return> to continue\n"); (void)nmgetch(); goraw(); } } SHAR_EOF if test 20553 -ne "`wc -c < 'interp.c'`" then echo shar: error transmitting "'interp.c'" '(should have been 20553 characters)' fi fi # end of overwriting check if test -f 'lex.c' then echo shar: will not over-write existing file "'lex.c'" else 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 *xmalloc(); 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; tokenl = 0; /* * This picks up either 1 or 2 alpha characters (a column) or * tokens with at least three leading alphas and '_' or digits * (a function or token or command or a range name) */ while (isalpha(*p) || ((*p == '_') || isdigit(*p)) && (tokenl > 2)) { p++; tokenl++; } if (tokenl <= 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; 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) { struct range *r; if (r = find_range(tokenst, tokenl, (struct ent *)0, (struct ent *)0)) { yylval.rval.left = r->r_left; yylval.rval.right = r->r_right; ret = RANGE; } else { linelim = p-line; yyerror ("Unintelligible word"); } } } } else if ((*p == '.') || isdigit(*p)) { double v = 0; long temp; char *nstart = p; if (*p != '.') { do v = v*10 + (double)(*p-'0'); while (isdigit(*++p)); } if (*p=='.' || *p == 'e' || *p == 'E') { ret = FNUMBER; p = strtof(nstart, &yylval.fval); } else { temp = (int)v; if((double)temp != 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 = xmalloc((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 #if defined(SYSV2) || defined(SYSV3) 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 /* SYSV2 || SYSV3 */ #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 (" /u undefine range /s show ranges /d define range"); 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(range) @avg(range) @prod(range)"); debug (" @func(e) - lots of other math functions"); } SHAR_EOF if test 9916 -ne "`wc -c < 'lex.c'`" then echo shar: error transmitting "'lex.c'" '(should have been 9916 characters)' fi fi # end of overwriting check