[alt.sources] SC - PD Unix Spreadsheet, Part 01/02

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