v13i017: SC spreadsheet program, version 5.1, Part02/03

Rich Salz rsalz at bbn.com
Fri Feb 5 08:13:33 AEST 1988


Submitted-by: nscpdc.nsc.com!rgb
Posting-number: Volume 13, Issue 17
Archive-name: sc5.1/part02

# This is a shell archive.  Remove anything before this line
# then unpack it by saving it in a file and typing "sh file"
# (Files unpacked will be owned by you and have default permissions).
# This archive contains the following files:
#	./psc.doc
#	./tutorial.sc
#	./sc.h
#	./sc.c
#	./lex.c
#	./gram.y
#
if `test ! -s ./psc.doc`
then
echo "Extracting ./psc.doc"
cat > ./psc.doc << '\SHAR\EOF\'
.TH PPNAME 1
.SH NAME
ppname \- prepare pname files
.SH SYNOPSIS
.B ppname
[
.I -Lkr
]
[
.I -s cell
]
[
.I -R n
]
[
.I -C n
]
[
.I -n n
]
[
.I -d c
]

.SH DESCRIPTION
.I Ppname
is used to prepare data for input to the spread sheet calculator
.I pname(1).
It accepts normal ascii data on standard input.  Standard output
is a
.I pname
file.
With no options, 
.I ppname
starts the spread sheet in cell A0.  Strings are right justified.
All data on a line is entered on the same row; new input lines
cause the output row number to increment by one.  The default delimiters
are tab and space.  The column formats are set to one larger
than the number of columns required to hold the largest value
in the column.

Options:

.IP "\-L"
Left justify strings.

.IP "\-k"
Keep all delimiters.  This option causes the output cell to change on
each new delimiter encountered in the input stream.   The default
action is to condense multiple delimters to one, so that the cell only
changes once per input data item.

.IP "\-r"
Output the data by row first then column.  For input consisting of a single
column, this
option will result in output of one row with multiple columns
instead of a single
column spread sheet.

.IP "\-s cell"
Start the top left corner of the spread sheet in 
.I cell.
For example, 
.I "-s B33"
will arrange the output data so that the
spread sheet starts in column B, row 33.

.IP "\-R n"
Increment by
.I n 
on each new output row.

.IP "\-C n"
Increment by
.I n 
on each new output column.

.IP "\-n n"
Output 
.I n
rows before advancing to the next column.  This option is used when
the input is arranged in a single column and the spread sheet is to
have multiple columns, each of which is to be length
.I n.

.IP "\-d c"
Use the single character
.I c
as the delimiter between input fields.

.SH SEE ALSO
pname(1)

.SH AUTHOR

Robert Bond
\SHAR\EOF\
else
  echo "will not over write ./psc.doc"
fi
if [ `wc -c ./psc.doc | awk '{printf $1}'` -ne 1855 ]
then
echo `wc -c ./psc.doc | awk '{print "Got " $1 ", Expected " 1855}'`
fi
if `test ! -s ./tutorial.sc`
then
echo "Extracting ./tutorial.sc"
cat > ./tutorial.sc << '\SHAR\EOF\'
# This data file was generated by the Spreadsheet Calculator.
# You almost certainly shouldn't edit it.

define "page4" A70
define "page3" A49
define "page2" A29
define "page1" A9
define "page5" A89
leftstring A1 = "This is a brief sc tutorial."
leftstring A3 = "Cells are named by their column and row number.  For example,"
leftstring A4 = "Cell A4"
leftstring B4 = "Cell B4"
leftstring C4 = "Cell C4"
leftstring A5 = "Cell A5"
leftstring A6 = "Cell A6"
leftstring C6 = "Cell C6"
leftstring A7 = "Cells range from A0 to AN199."
leftstring A8 = "Cells can also be named by the user.  See 'range names' in the manual."
leftstring page1 = "You can move the cursor a couple of different ways:"
leftstring A11 = "^n, j and the <DOWN> arrow key go down"
leftstring A12 = "^p, k and the <UP> arrow key go up"
leftstring A13 = "^b, h and the <LEFT> arrow key go left"
leftstring A14 = "^f, l and the <RIGHT> arrow key go right"
leftstring A15 = "You can go directly to a cell by typing 'g' and the cell name. "
leftstring A16 = "'g c6' will take you to cell c6."
leftstring A18 = "Cells can contain numbers, formulas, or text."
leftstring A19 = "Most of the cells on this page contain text."
leftstring C20 = "<Type 'g page2' to continue>"
leftstring A22 = "Cell d22 contains text"
leftstring D22 = "Text "
leftstring A23 = "Cell d23 contains a number"
let D23 = 123.34
leftstring A24 = "Cell d24 contains a formula"
let D24 = D23+88
leftstring A26 = "To see what the cell contains, just move the cursor"
leftstring A27 = "onto the cell.  The contents will show up on line 1 in the brackets."
leftstring page2 = "You can enter data into cells like this:"
leftstring B30 = "'<text' enters left justified text."
leftstring B31 = "'>text' enters right justified text."
leftstring B32 = "'=number' enters a number"
leftstring B33 = "'=formula' enters a formula."
leftstring A35 = "Try duplicating d22 through d24 in e22 though e24."
leftstring A37 = "You erase a cell by typing 'x' with the cursor on the cell."
leftstring C40 = "<Type 'g page3' to continue>"
leftstring A42 = "Here is a typical use for numbers and formulas:"
let A44 = 10.3
let B44 = 1877.5
let C44 = 234.7
let E44 = @sum(A44:C44)
let A45 = 44.56
let B45 = 44.3
let C45 = -3
let E45 = @sum(A45:C45)
let A46 = 88.74
let B46 = 8000
let C46 = -9
let E46 = @sum(A46:C46)
let A47 = 99.2
let B47 = -88
let C47 = -44.6
let E47 = @sum(A47:C47)
let page3 = @sum(A44:A47)
let B49 = @sum(B44:B47)
let C49 = @sum(C44:C47)
let E49 = @sum(A44:C47)
leftstring A51 = "The data is entered in a44 through c47."
leftstring A52 = "Cells a49, b49 and c49 sum their respective columns."
leftstring A53 = "Cells e44, e45, e46, and e47 sum their respective rows."
leftstring A54 = "Cell E49 is a grand total."
leftstring A55 = "Try changing some of the data cells and watch the sums change."
leftstring A57 = "You can also edit cells by putting the cursor on the cell and typing:"
leftstring B58 = "'e' to edit the numeric portion."
leftstring B59 = "'E' to edit the string portion."
leftstring C60 = "<Type 'g page4' to continue>"
leftstring A62 = "Since you are reading this, you know that you can load "
leftstring A63 = "a data base from a file by typing the file name as an"
leftstring A64 = "argument to the program.  You can also load or save a "
leftstring A65 = "data base using the file commands:"
leftstring B67 = "'G file'"
leftstring C67 = "Gets the data from an sc file."
leftstring B68 = "'P file'"
leftstring C68 = "Puts the data from the spreadsheet into a file."
leftstring page4 = "Try 'P foo.sc' to write this to the file foo.sc"
leftstring A71 = "The Get command erases the current spreadsheet.  "
leftstring A72 = "To merge a spreadsheet with the one currently in"
leftstring A73 = "the machine, use:"
leftstring B75 = "'M file'"
leftstring C75 = "Merge the data from a saved sc file."
leftstring A77 = "You can also get human readable versions of the data"
leftstring A78 = "by using the Write command:"
leftstring C80 = "<Type 'g page5' to continue>"
leftstring A82 = "Try 'W tut.txt' for a clear text version of the tutorial."
leftstring A85 = "This is the end of the tutorial.  We have explored"
leftstring A86 = "The basic commands.  Much more detail is available"
leftstring A87 = "in the man page."
leftstring D91 = "GOOD LUCK!"
\SHAR\EOF\
else
  echo "will not over write ./tutorial.sc"
fi
if [ `wc -c ./tutorial.sc | awk '{printf $1}'` -ne 4292 ]
then
echo `wc -c ./tutorial.sc | awk '{print "Got " $1 ", Expected " 4292}'`
fi
if `test ! -s ./sc.h`
then
echo "Extracting ./sc.h"
cat > ./sc.h << '\SHAR\EOF\'
/*	SC	A Table Calculator
 *		Common definitions
 *
 *		original by James Gosling, September 1982
 *		modified by Mark Weiser and Bruce Israel,
 *			University of Maryland
 *		R. Bond  12/86
 *
 */



#define MAXROWS 200
#define MAXCOLS 40
#define RESCOL 4  /* columns reserved for row numbers */
#define RESROW 3  /* rows reserved for prompt, error, and column numbers */
#define error move(1,0), clrtoeol(), (void) printw

struct ent_ptr {
    int vf;
    struct ent *vp;
};

struct range_s {
	struct ent_ptr left, right;
};

/*
 * If you want to save room, make row and col below into unsigned
 * chars and make sure MAXROWS and MAXCOLS above are both less
 * than 256.  (128 if your compiler doesn't support unsigned char).
 *
 * Some not too obvious things about the flags:
 *    is_valid means there is a valid number in v.
 *    label set means it points to a valid constant string.
 *    is_strexpr set means expr yields a string expression.
 *    If is_strexpr is not set, and expr points to an expression tree, the
 *        expression yields a numeric expression.
 *    So, either v or label can be set to a constant. 
 *        Either (but not both at the same time) can be set from an expression.
 */

#define VALID_CELL(p, r, c) ((p = tbl[r][c])&&((p->flags&is_valid)||p->label))

struct ent {
    double v;
    char *label;
    struct enode *expr;
    short flags;
    short row, col;
    struct ent *next;
};

struct range {
    struct ent_ptr r_left, r_right;
    char *r_name;
    struct range *r_next, *r_prev;
    int r_is_range;
};

#define FIX_ROW 1
#define FIX_COL 2

struct enode {
    int op;
    union {
	double k;
	struct ent_ptr v;
	struct range_s r;
	char *s;
	struct {
	    struct enode *left, *right;
	} o;
    } e;
};

/* op values */
#define O_VAR 'v'
#define O_CONST 'k'
#define O_SCONST '$'
#define O_REDUCE(c) (c+0200)

#define ACOS 0
#define ASIN 1
#define ATAN 2
#define CEIL 3
#define COS 4
#define EXP 5 
#define FABS 6 
#define FLOOR 7
#define HYPOT 8
#define LOG 9
#define LOG10 10
#define POW 11
#define SIN 12
#define SQRT 13
#define TAN 14
#define DTR 15
#define RTD 16
#define MIN 17
#define MAX 18
#define RND 19
#define HOUR 20
#define MINUTE 21
#define SECOND 22
#define MONTH 23
#define DAY 24
#define YEAR 25
#define NOW 26
#define DATE 27
#define FMT 28
#define SUBSTR 29
#define STON 30
#define EQS 31

/* flag values */
#define is_valid     0001
#define is_changed   0002
#define is_strexpr   0004
#define is_leftflush 0010
#define is_deleted   0020

#define ctl(c) ('c'&037)

extern struct ent *tbl[MAXROWS][MAXCOLS];

extern int strow, stcol;
extern int currow, curcol;
extern int savedrow, savedcol;
extern int FullUpdate;
extern int maxrow, maxcol;
extern int fwidth[MAXCOLS];
extern int precision[MAXCOLS];
extern char col_hidden[MAXCOLS];
extern char row_hidden[MAXROWS];
extern char line[1000];
extern int linelim;
extern int changed;
extern struct ent *to_fix;
extern int showsc, showsr;
extern struct enode *new();
extern struct enode *new_const();
extern struct enode *new_var();
extern struct enode *new_str();
extern struct enode *new_range();
extern struct ent *lookat();
extern struct enode *copye();
extern char *coltoa();
extern FILE *openout();
extern struct range *find_range();
extern char *v_name();
extern char *r_name();
extern double eval();
extern char *seval();
extern int modflg;
extern int Crypt;
extern char *mdir;
extern char *xmalloc();
extern int xfree();

#if BSD42 || SYSIII

#ifndef cbreak
#define	cbreak		crmode
#define	nocbreak	nocrmode
#endif

#endif

\SHAR\EOF\
else
  echo "will not over write ./sc.h"
fi
if [ `wc -c ./sc.h | awk '{printf $1}'` -ne 3542 ]
then
echo `wc -c ./sc.h | awk '{print "Got " $1 ", Expected " 3542}'`
fi
if `test ! -s ./sc.c`
then
echo "Extracting ./sc.c"
cat > ./sc.c << '\SHAR\EOF\'
/*	SC	A Spreadsheet Calculator
 *		Main driver
 *
 *		original by James Gosling, September 1982
 *		modifications by Mark Weiser and Bruce Israel,
 *			University of Maryland
 *
 *              More mods Robert Bond, 12/86
 *
 */


#include <signal.h>
#include <curses.h>

#ifdef BSD42
#include <strings.h>
#else
#ifndef SYSIII
#include <string.h>
#endif
#endif

#include <stdio.h>
#include "sc.h"

char *getenv();

#ifdef SYSV3
void exit();
#endif

/* default column width */

#define DEFWIDTH 10
#define DEFPREC   2

#define MAXCMD 160	/* for ! command below */

/* Globals defined in sc.h */

struct ent *tbl[MAXROWS][MAXCOLS];
int strow, stcol;
int currow, curcol;
int savedrow, savedcol;
int FullUpdate;
int maxrow, maxcol;
int fwidth[MAXCOLS];
int precision[MAXCOLS];
char col_hidden[MAXCOLS];
char row_hidden[MAXROWS];
char line[1000];
int changed;
struct ent *to_fix;
int modflg;
int numeric;
char *mdir;
int showsc, showsr;	/* Starting cell for highlighted range */

char curfile[1024];
char    revmsg[80];

int  linelim = -1;
int  showme = 1;	/* 1 to display the current cell in the top line */
int  showrange;		/* Causes ranges to be highlighted */
int  lastmx, lastmy;	/* Screen address of the cursor */
int  lastcol;		/* Spreadsheet Column the cursor was in last */
char *under_cursor = " "; /* Data under the < cursor */
char *rev = "$Revision: 5.1 $";

int seenerr;

yyerror (err)
char *err; {
    if (seenerr) return;
    seenerr++;
    (void) move (1,0);
    (void) clrtoeol ();
    (void) printw ("%s: %.*s<=%s",err,linelim,line,line+linelim);
}

struct ent *
lookat(row,col){
    register struct ent **p;
    if (row < 0)
	row = 0;
    else if (row > MAXROWS-1) 
	row = MAXROWS-1;
    if (col < 0) 
	col = 0;
    else if (col > MAXCOLS-1)
	col = MAXCOLS-1;
    p = &tbl[row][col];
    if (*p==0) {
	*p = (struct ent *) xmalloc ((unsigned)sizeof (struct ent));
	if (row>maxrow) maxrow = row;
	if (col>maxcol) maxcol = col;
	(*p)->label = 0;
	(*p)->flags = 0;
	(*p)->row = row;
	(*p)->col = col;
	(*p)->expr = 0;
	(*p)->v = (double) 0.0;
    }
    return *p;
}

/*
 * This structure is used to keep ent structs around before they
 * are deleted to allow the sync_refs routine a chance to fix the
 * variable references.
 * We also use it as a last-deleted buffer for the 'p' command.
 */

free_ent(p)
register struct ent *p;
{
    p->next = to_fix;
    to_fix = p;
    p->flags |= is_deleted;
}

flush_saved()
{
    register struct ent *p;
    register struct ent *q;

    if (!(p = to_fix))
	return;
    while (p) {
	(void) clearent(p);
	q = p->next;
	xfree((char *)p);
	p = q;
    }
    to_fix = 0;
}

update () {
    register    row,
                col;
    register struct ent **p;
    int     mxcol;
    int     mxrow;
    int     rows;
    int     cols;
    int     minsr, minsc, maxsr, maxsc;
    register r;
    register i;

    while (row_hidden[currow])   /* You can't hide the last row or col */
	currow++;
    while (col_hidden[curcol])
	curcol++;
    /* First see if the last display still covers curcol */
    if (stcol <= curcol) { 
	for (i = stcol, cols = 0, col = RESCOL;
			(col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) {
	    cols++;
	    if (col_hidden[i])
		continue;
	    col += fwidth[i];
	}
    }
    while (stcol + cols - 1 < curcol || curcol < stcol) {
	FullUpdate++;
	if (stcol - 1 == curcol) {    /* How about back one? */
	    stcol--;
	} else if (stcol + cols == curcol) {   /* Forward one? */
	    stcol++;
	} else {
	    /* Try to put the cursor in the center of the screen */
	    col = (COLS - RESCOL - fwidth[curcol]) / 2 + RESCOL; 
	    stcol = curcol;
	    for (i=curcol-1; i >= 0 && col-fwidth[i] > RESCOL; i--) {
		stcol--;
		if (col_hidden[i])
		    continue;
		col -= fwidth[i];
	    }
	}
	/* Now pick up the counts again */
	for (i = stcol, cols = 0, col = RESCOL;
			(col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) {
	    cols++;
	    if (col_hidden[i])
		continue;
	    col += fwidth[i];
	}
    }
    /* Now - same process on the rows */
    if (strow <= currow) { 
	for (i = strow, rows = 0, row=RESROW; row<LINES && i<MAXROWS; i++) {
	    rows++;
	    if (row_hidden[i])
		continue;
	    row++;
	}
    }
    while (strow + rows - 1 < currow || currow < strow) {
	FullUpdate++;
	if (strow - 1 == currow) {    /* How about up one? */
	    strow--;
	} else if (strow + rows == currow) {   /* Down one? */
	    strow++;
	} else {
	    /* Try to put the cursor in the center of the screen */
	    row = (LINES - RESROW) / 2 + RESROW; 
	    strow = currow;
	    for (i=currow-1; i >= 0 && row-1 > RESROW; i--) {
		strow--;
		if (row_hidden[i])
		    continue;
		row--;
	    }
	}
	/* Now pick up the counts again */
	for (i = strow, rows = 0, row=RESROW; row<LINES && i<MAXROWS; i++) {
	    rows++;
	    if (row_hidden[i])
		continue;
	    row++;
	}
    }
    mxcol = stcol + cols - 1;
    mxrow = strow + rows - 1;
    if (FullUpdate) {
	(void) move (2, 0);
	(void) clrtobot ();
	(void) standout();
	for (row=RESROW, i=strow; i <= mxrow; i++) {
	    if (row_hidden[i]) 
		continue;
	    (void) move(row,0);
#if MAXROW < 1000
	    (void) printw("%-*d", RESCOL-1, i);
#else
	    (void) printw("%-*d", RESCOL, i);
#endif
	    row++;
	}
	(void) move (2,0);
	(void) printw("%*s", RESCOL, " ");
	for (col=RESCOL, i = stcol; i <= mxcol; i++) {
	    register int k;
	    if (col_hidden[i])
		continue;
	    (void) move(2, col);
	    k = fwidth[i]/2;
	    if (k == 0)
		(void) printw("%1s", coltoa(i));
	    else
	        (void) printw("%*s%-*s", k, " ", fwidth[i]-k, coltoa(i));
	    col += fwidth[i];
	}
	(void) standend();
    }

    /* Get rid of the cursor standout */
    (void) move(lastmx, lastmy);
    if (showme)
        repaint(lastmx, lastmy, fwidth[lastcol]);

    if (showrange && showme) {
	minsr = showsr < currow ? showsr : currow;
	minsc = showsc < curcol ? showsc : curcol;
	maxsr = showsr > currow ? showsr : currow;
	maxsc = showsc > curcol ? showsc : curcol;
	(void) move(1,0);
	(void) clrtoeol();
        (void) printw("Default range - %s", r_name(minsr, minsc, maxsr, maxsc));
    }

    /* Repaint the visible screen */
    for (row = strow, r = RESROW; row <= mxrow; row++) {
	register c = RESCOL;
	int do_stand = 0;
	int fieldlen;
	int nextcol;

	if (row_hidden[row])
	    continue;
	for (p = &tbl[row][col = stcol]; col <= mxcol;
	         p += nextcol - col,  col = nextcol, c += fieldlen) {

	    nextcol = col+1;
	    if (col_hidden[col]) {
		fieldlen = 0;
		continue;
	    }

	    fieldlen = fwidth[col];
	    if (showrange && showme && (row >= minsr) && (row <= maxsr) &&
			       (col >= minsc) && (col <= maxsc)) {
		do_stand = 1;
	    }
	    if (*p && ((*p) -> flags & is_changed || FullUpdate) || do_stand) {
		char   *s;
		(void) move (r, c);
		if (!*p)
		    *p = lookat(row, col);
		if (do_stand) {
		    (void) standout();
		    (*p) -> flags |= is_changed; 
		} else {
		    (*p) -> flags &= ~is_changed;
		}
		if ((*p) -> flags & is_valid) {
		    char field[1024];
		    (void)sprintf(field,"%*.*f", fwidth[col],
					         precision[col], (*p)->v);
		    if(strlen(field) > fwidth[col]) {
			for(i = 0; i<fwidth[col]; i++)
			    (void)addch('*');
		    } else {
			(void)addstr(field);
		    }
		}
		if (s = (*p) -> label) {
		    char field[1024];
		    int  slen;
		    char *start, *last;
		    register char *fp;
		    struct ent *nc;

		    /* This figures out if the label is allowed to
		       slop over into the next blank field */
		    slen = strlen(s);
		    while(slen>fieldlen && nextcol<=mxcol &&
			   !((nc = lookat(row,nextcol))->flags & is_valid) &&
			   !(nc->label)) {

			if (!col_hidden[nextcol])
			    fieldlen += fwidth[nextcol];

		        nextcol++;
		    }
		    if (slen > fieldlen)
			slen = fieldlen;

		    /* Now justify and print */
		    start = (*p)->flags & is_leftflush ? field 
		    			: field + fieldlen - slen;
		    last = field+fieldlen;
		    fp = field;
		    while (fp < start)
			*fp++ = ' ';
		    while (slen--)
			*fp++ = *s++;
		    if (!((*p)->flags & is_valid) || fieldlen != fwidth[col]) 
		        while (fp < last)
			    *fp++ = ' ';
		    *fp = 0;
		    (void) mvaddstr(r, c, field);
		}
		if (!((*p)->flags & is_valid) && !(*p)->label) {
		    /* Need to repaint a blank cell */
		    (void) printw ("%*s", fwidth[col], " ");
		}
		if (do_stand) {
		    (void) standend();
		    do_stand = 0;
		}
	    }
	}
	r++;
    }
	    
    (void) move(lastmy, lastmx+fwidth[lastcol]);
    if((inch() & 0x7f) == '<')
        (void) addstr(under_cursor);
    lastmy =  RESROW;
    for (row = strow; row < currow; row++)
	if (!row_hidden[row])
		lastmy += 1;
    lastmx = RESCOL;
    for (col = stcol; col < curcol; col++)
	if (!col_hidden[col])
		lastmx += fwidth[col];
    lastcol = curcol;
    (void) move(lastmx, lastmy);
    if (showme) {
        (void) standout();
        repaint(lastmx, lastmy, fwidth[lastcol]);
        (void) standend();
    }
    (void) move(lastmy, lastmx+fwidth[lastcol]);
    *under_cursor = (inch() & 0x7f);
    (void) addstr("<");

    (void) move (0, 0);
    (void) clrtoeol ();
    if (linelim >= 0) {
	(void) addstr (">> ");
	(void) addstr (line);
    } else {
	if (showme) {
	    register struct ent *p1;

            (void) printw("%s%d", coltoa(curcol), currow);
	    p1 = tbl[currow][curcol];
	    if (p1 && ((p1->flags & is_valid) || p1->label)) {
		if (p1->expr) {
		    linelim = 0;
		    editexp(currow, curcol);
		} else if (p1->label) {
		    (void) sprintf(line, "%s", p1->label);
		} else {
		    (void) sprintf(line, "%.15g", p1->v);
		}
		(void) addstr("[");
		(void) addstr (line);
		(void) addstr("]");
		linelim = -1;
	    } else {
		(void) addstr("[]");
	    }
	}
	(void) move (lastmy, lastmx + fwidth[lastcol]);
    }
    if (revmsg[0]) {
	(void) move(0, 0);
	(void) printw(revmsg);
	revmsg[0] = 0;
	(void) move (lastmy, lastmx + fwidth[lastcol]);
    }
    FullUpdate = 0;
}

repaint(x, y, len)
{
    char *buf;

    buf = " ";

    while(len-- > 0) {
	(void) move(y,x);
	*buf = inch() & 0x7f;
	(void) addstr(buf);
	x++;
    }
}

main (argc, argv)
char  **argv; {
    int     inloop = 1;
    register int   c;
    int     edistate = -1;
    int     arg = 1;
    int     narg;
    int     nedistate;
    int	    running;
    char    *revi;
    char    *pname;

    pname = argv[0];
    while (argc > 1 && argv[1][0] == '-') {
	argv++;
	argc--;
    	switch (argv[0][1]) {
	    case 'x':
		    Crypt = 1;
		    break;
	    case 'n':
		    numeric = 1;
		    break;
	    default:
		    (void) fprintf(stderr,"%s: unrecognized flag: %c\n",
			pname,argv[0][1]);
		    exit(1);
	}
    }

    {
	register    i;
	for (i = 0; i < MAXCOLS; i++) {
	    fwidth[i] = DEFWIDTH;
	    precision[i] = DEFPREC;
	}
    }
    curfile[0]=0;

    signals();
    (void) initscr();
    (void) clear();
    nonl();
    noecho ();
    cbreak();
    initkbd();
    (void) strcpy(revmsg, pname);
    for (revi=rev; *revi++ != ':';);
    (void) strcat(revmsg, revi);
    revi = revmsg+strlen(revmsg);
    *--revi = 0;
    (void) strcat(revmsg,"Type '?' for help.");
    if (argc > 1) {
	(void) strcpy(curfile,argv[1]);
	readfile (argv[1], 0);
    }
    modflg = 0;
#ifdef VENIX
    setbuf (stdin, NULL);
#endif
    FullUpdate++;
    while (inloop) { running = 1;
    while (running) {
	nedistate = -1;
	narg = 1;
	if (edistate < 0 && linelim < 0 && (changed || FullUpdate))
	    EvalAll (), changed = 0;
	update();
#ifndef SYSV3
	(void) refresh(); /* 5.3 does a refresh in getch */ 
#endif
	c = nmgetch();
	(void) move (1, 0);
	(void) clrtoeol ();
	(void) fflush (stdout);
	seenerr = 0;
	if ((c < ' ') || ( c == 0177 ))
	    switch (c) {
#if defined(BSD42) || defined (BSD43)
		case ctl (z):
		    deraw();
#ifndef V7
		    (void) kill(getpid(),SIGTSTP);
#endif

		    /* the pc stops here */

		    goraw();
		    break;
#endif
		case ctl (r):
		case ctl (l):
		    FullUpdate++;
		    (void) clearok(stdscr,1);
		    break;
		default:
		    error ("No such command  (^%c)", c + 0100);
		    break;
		case ctl (b):
		    while (--arg>=0) {
			if (curcol)
			    curcol--;
			else
			    error ("At column A");
			while(col_hidden[curcol] && curcol)
			    curcol--;
		    }
		    break;
		case ctl (c):
		    running = 0;
		    break;
		case ctl (e):
		    switch (nmgetch()) {
		    case 'j':
		    case ctl(n):
			doend(1,0);
			break;
		    case 'k':
		    case ctl(p):
			doend(-1,0);
			break;
		    case 'h':
		    case ctl(b):
			doend(0,-1);
			break;
		    case 'l':
		    case ctl(f):
			doend(0,1);
			break;
		    default:
			error("Invalid end command");
			break;
		    }
		    break;
		case ctl (f):
		    while (--arg>=0) {
			if (curcol < MAXCOLS - 1)
			    curcol++;
			else
			    error ("The table can't be any wider");
			while(col_hidden[curcol]&&(curcol<MAXCOLS-1))
			    curcol++;
		    }
		    break;
		case ctl (g):
		case ctl ([):
		    showrange = 0;
		    linelim = -1;
		    (void) move (1, 0);
		    (void) clrtoeol ();
		    break;
		case 0177:
		case ctl (h):
		    while (--arg>=0) if (linelim > 0)
			line[--linelim] = 0;
		    break;
		case ctl (i): 		/* tab */
		    if (linelim > 0) {
			if (!showrange) {
			    startshow();
			} else {
			    showdr();
			    linelim = strlen(line);
			    line[linelim++] = ' ';
			    line[linelim] = 0;
			    showrange = 0;
			}
			linelim = strlen (line);
		    }
		    break;
		case ctl (m):
		case ctl (j):
		    showrange = 0;
		    if (linelim < 0)
			line[linelim = 0] = 0;
		    else {
			linelim = 0;
			(void) yyparse ();
			linelim = -1;
		    }
		    break;
		case ctl (n):
		    while (--arg>=0) {
			if (currow < MAXROWS - 1)
			    currow++;
			else
			    error ("The table can't be any longer");
			while (row_hidden[currow] && (currow < MAXROWS - 1))
			    currow++;
		    }
		    break;
		case ctl (p):
		    while (--arg>=0) {
			if (currow)
			    currow--;
			else
			    error ("At row zero");
			while (row_hidden[currow] && currow)
			    currow--;
		    }
		    break;
		case ctl (q):
		    break;	/* ignore flow control */
		case ctl (s):
		    break;	/* ignore flow control */
		case ctl (t):
		    error("Toggle - n:numeric  t:top row  x:encryption");
		    (void) refresh();
		    switch (nmgetch()) {
			case 't': case 'T':
			    showme ^= 1;
			    repaint(lastmx, lastmy, fwidth[lastcol]);
			    break;
			case 'n': case 'N':
			    numeric ^= 1;
			    error("Numeric input %sabled.",numeric? "en":"dis");
			    break;
			case 'x': case 'X':
			    Crypt ^= 1;
			    error("Encryption %sabled.",Crypt? "en":"dis");
			    break;
			default:
			    error("Bad toggle switch");
		    }
		    break;
		case ctl (u):
		    narg = arg * 4;
		    nedistate = 1;
		    break;
		case ctl (v):	/* insert variable name */
		    if (linelim > 0) {
		    (void) sprintf (line+linelim,"%s", v_name(currow, curcol));
			linelim = strlen (line);
		    }
		    break;
		case ctl (w):	/* insert variable expression */
		    if (linelim > 0) editexp(currow,curcol);
		    break;
		case ctl (a):	/* insert variable value */
		    if (linelim > 0) {
			struct ent *p = tbl[currow][curcol];

			if (p && p -> flags & is_valid) {
			    (void) sprintf (line + linelim, "%.*f",
					precision[curcol],p -> v);
			    linelim = strlen (line);
			}
		    }
		    break;
		}
	else
	    if ('0' <= c && c <= '9' && ( (numeric && edistate >= 0) ||
			(!numeric && (linelim < 0 || edistate >= 0))))
	    {
		if (edistate != 0) {
		    if (c == '0')      /* just a '0' goes to left col */
			curcol = 0;
		    else {
		        nedistate = 0;
		        narg = c - '0';
		    }
		} else {
		    nedistate = 0;
		    narg = arg * 10 + (c - '0');
		}
	    }
	    else
		if (linelim >= 0) {     /* Editing line */
		    switch(c) {
			case ')':
			    if (showrange) {
				showdr();
			        showrange = 0;
			        linelim = strlen (line);
			    }
			    break;
		       default:
			    break;
		    }
		    line[linelim++] = c;
		    line[linelim] = 0;
		}
		else
		    switch (c) {
			case ':':
			    break;	/* Be nice to vi users */

			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
			case '-': case '.': case '+':
			    (void) sprintf(line,"let %s = %c",
					v_name(currow, curcol), c);
			    linelim = strlen (line);
			    break;

			case '=':
			    (void) sprintf(line,"let %s = ",
						v_name(currow, curcol));
			    linelim = strlen (line);
			    break;

			case '!':
			    {
			    /*
			     *  "! command"  executes command
			     *  "!"	forks a shell
			     *  "!!" repeats last command
			     */
			    char *shl;
			    int pid, temp;
			    char cmd[MAXCMD];
			    static char lastcmd[MAXCMD];

			    if (!(shl = getenv("SHELL")))
				shl = "/bin/sh";

			    deraw();
			    (void) fputs("! ", stdout);
			    (void) fflush(stdout);
			    (void) fgets(cmd, MAXCMD, stdin);
			    cmd[strlen(cmd) - 1] = '\0';	/* clobber \n */
			    if(strcmp(cmd,"!") == 0)		/* repeat? */
				    (void) strcpy(cmd, lastcmd);
			    else
				    (void) strcpy(lastcmd, cmd);

			    if (!(pid = fork()))
			    {
			        if(strlen(cmd))
					(void)execl(shl,shl,"-c",cmd,(char *)0);
				else
					(void) execl(shl, shl, (char *)0);
				exit(-127);
			    }

			    while (pid != wait(&temp));

			    (void) printf("Press <return> to continue\n");
			    (void)nmgetch();
			    goraw();
			    break;
			    }

			case '/':
			    error("c:copy x:erase v:value f:fill d:define u:undefine s:show");
			    (void) refresh();
			    switch (nmgetch()) {
			    case 'c':
				(void) sprintf(line,"copy [dest_range src_range] ");
				linelim = strlen(line);
				startshow();
				break;
			    case 'x':
				(void) sprintf(line,"erase [range] ");
				linelim = strlen(line);
				startshow();
				break;
			    case 'v':
				(void) sprintf(line, "value [range] ");
				linelim = strlen(line);
				startshow();
				break;
			    case 'f':
				(void) sprintf(line,"fill [range start inc] ");
				linelim = strlen(line);
				startshow();
				break;
			    case 'd':
				(void) sprintf(line,"define [string range] \"");
				linelim = strlen(line);
				startshow();
				modflg++;
				break;
			    case 'u':
				(void) sprintf(line,"undefine [range] ");
				linelim = strlen(line);
				modflg++;
				break;
			    case 's':
				{
				FILE *f;
				int pid;
				f = openout("| sort | less", &pid);
				if (!f) {
				    error("Cant open pipe to sort");
				    break;
				}
				list_range(f);
				closeout(f, pid);
				break;
				}
			   default:
				error("Invalid region operation");
			    }
			    break;
			case '$':
			    {
			    register struct ent *p;

			    curcol = MAXCOLS - 1;
			    while (!VALID_CELL(p, currow, curcol) && curcol > 0)
				curcol--;
			    break;
			    }
			case '#':
			    {
			    register struct ent *p;

			    currow = MAXROWS - 1;
			    while (!VALID_CELL(p, currow, curcol) && currow > 0)
				currow--;
			    break;
			    }
			case 'w':
			    {
			    register struct ent *p;

			    while (--arg>=0) {
				do {
				    if (curcol < MAXCOLS - 1)
					curcol++;
				    else {
					if (currow < MAXROWS - 1) {
					    while(++currow < MAXROWS - 1 &&
					            row_hidden[currow]) /* */;
					    curcol = 0;
					} else {
					    error("End of the table");
					    break;
					}
				    }
				} while(col_hidden[curcol] ||
					!VALID_CELL(p, currow, curcol));
			    }
			    break;
			    }
			case 'b':
			    {
			    register struct ent *p;

			    while (--arg>=0) {
				do {
				    if (curcol) 
					curcol--;
				    else {
					if (currow) {
					    while(--currow &&
						row_hidden[currow]) /* */;
					    curcol = MAXCOLS - 1;
					} else {
					    error ("At start of table");
					    break;
					}
				    }
				} while(col_hidden[curcol] ||
					!VALID_CELL(p, currow, curcol));
			    }
			    break;
			    }
			case '^':
			    currow = 0;
			    break;
			case '?':
			    help ();
			    break;
			case '"':
			    (void) sprintf (line, "label %s = \"",
						v_name(currow, curcol));
			    linelim = strlen (line);
			    break;
			case '<':
			    (void) sprintf (line, "leftstring %s = \"",
				    v_name(currow, curcol));
			    linelim = strlen (line);
			    break;
			case '>':
			    (void) sprintf (line, "rightstring %s = \"",
				   v_name(currow, curcol));
			    linelim = strlen (line);
			    break;
			case 'e':
			    editv (currow, curcol);
			    break;
			case 'E':
			    edits (currow, curcol);
			    break;
			case 'f':
			    if (arg == 1)
			        (void) sprintf (line, "format [for column] %s ",
					coltoa(curcol));
			    else {
				(void) sprintf(line, "format [for columns] %s:",
					coltoa(curcol));
				(void) sprintf(line+strlen(line), "%s ",
					coltoa(curcol+arg-1));
			    }
			    error("Current format is %d %d",
					fwidth[curcol],precision[curcol]);
			    linelim = strlen (line);
			    break;
			case 'g':
			    (void) sprintf (line, "goto [v] ");
			    linelim = strlen (line);
			    break;
			case 'P':
			    (void) sprintf (line, "put [\"dest\" range] \"");
			    if (*curfile)
			        error("Default path is '%s'",curfile);
			    linelim = strlen (line);
			    break;
			case 'M':
			    (void) sprintf (line, "merge [\"source\"] \"");
			    linelim = strlen (line);
			    break;
			case 'R':
			    (void) sprintf (line,"merge [\"macro_file\"] \"%s/", mdir);
			    linelim = strlen (line);
			    break;
			case 'D':
			    (void) sprintf (line, "mdir [\"macro_directory\"] \"");
			    linelim = strlen (line);
			    break;
			case 'G':
			    (void) sprintf (line, "get [\"source\"] \"");
			    if (*curfile)
			        error("Default file is '%s'",curfile);
			    linelim = strlen (line);
			    break;
			case 'W':
			    (void) sprintf (line, "write [\"dest\" range] \"");
			    linelim = strlen (line);
			    break;
			case 'T':	/* tbl output */
			    (void) sprintf (line, "tbl [\"dest\" range] \"");
			    linelim = strlen (line);
			    break;
			case 'i':
			    switch (get_qual()) {
			    case 'r':
				insertrow(arg);
				break;
			    case 'c':
				insertcol(arg);
				break;
			    default:
				error("Invalid insert command");
				break;
			    }
			    break;
			case 'd':
			    switch (get_qual()) {
			    case 'r':
				deleterow(arg);
				break;
			    case 'c':
				deletecol(arg);
				break;
			    default:
				error("Invalid delete command");
				break;
			    }
			    break;
			case 'v':
			    switch (get_qual()) {
			    case 'r':
				rowvalueize(arg);
				modflg++;
				break;
			    case 'c':
				colvalueize(arg);
				modflg++;
				break;
			    default:
				error("Invalid value command");
				break;
			    }
			    break;
			case 'p':
			    {
			    register qual;
			    qual = get_qual();
			    while (arg--)
			        pullcells(qual);
			    break;
			    }
			case 'x':
			    {
			    register struct ent **p;
			    register int c1;

			    flush_saved();
			    for (c1 = curcol; arg-- && c1 < MAXCOLS; c1++) {
				p = &tbl[currow][c1];
				if (*p) {
			            free_ent(*p);
			            *p = 0;
				}
			    }
			    sync_refs();
			    FullUpdate++;
			    }
			    break;
			case 'Q':
			case 'q':
			    running = 0;
			    break;
			case 'h':
			    while (--arg>=0) {
				if (curcol)
				    curcol--;
				else
				    error ("At column A");
				while(col_hidden[curcol] && curcol)
				    curcol--;
			    }
			    break;
			case 'j':
			    while (--arg>=0) {
				if (currow < MAXROWS - 1)
				    currow++;
				else
				    error ("The table can't be any longer");
				while (row_hidden[currow]&&(currow<MAXROWS-1))
				    currow++;
			    }
			    break;
			case 'k':
			    while (--arg>=0) {
				if (currow)
				    currow--;
				else
				    error ("At row zero");
				while (row_hidden[currow] && currow)
				    currow--;
			    }
			    break;
			case ' ':
			case 'l':
			    while (--arg>=0) {
				if (curcol < MAXCOLS - 1)
				    curcol++;
				else
				    error ("The table can't be any wider");
				while(col_hidden[curcol]&&(curcol<MAXCOLS-1))
				    curcol++;
			    }
			    break;
			case 'm':
			    savedrow = currow;
			    savedcol = curcol;
			    break;
			case 'c': {
			    register struct ent *p = tbl[savedrow][savedcol];
			    register c1;
			    register struct ent *n;
			    if (!p)
				break;
			    FullUpdate++;
			    modflg++;
			    for (c1 = curcol; arg-- && c1 < MAXCOLS; c1++) {
				n = lookat (currow, c1);
				(void) clearent(n);
				n -> flags = p -> flags;
				n -> v = p -> v;
				n -> expr = copye(p->expr,
					    currow - savedrow,
					    c1 - savedcol);
				n -> label = 0;
				if (p -> label) {
				    n -> label = (char *)
						 xmalloc((unsigned)strlen(p->label)+1);
				(void) strcpy (n -> label, p -> label);
				}
			    }
			    break;
			}
			case 'z':
			    switch (get_qual()) {
			    case 'r':
				hiderow(arg);
				break;
			    case 'c':
				hidecol(arg);
				break;
			    default:
				error("Invalid zap command");
				break;
			    }
			    break;
			case 's':
			    switch (get_qual()) {
			    case 'r':
				rowshow_op();
				break;
			    case 'c':
				colshow_op();
				break;
			    default:
				error("Invalid show command");
				break;
			    }
			    break;
			case 'a':
			    switch (get_qual()) {
			    case 'r':
				while (arg--)
				    duprow();
				break;
			    case 'c':
				while (arg--)
				    dupcol();
				break;
			    default:
				error("Invalid add row/col command");
				break;
			    }
			    break;
			default:
			    if ((c & 0177) != c)
				error("Weird character, decimal '%d'.\n",
					(int) c);
			    else
				    error ("No such command  (%c)", c);
			    break;
		    }
	edistate = nedistate;
	arg = narg;
    }				/* while (running) */
    inloop = modcheck(" before exiting");
    }				/*  while (inloop) */
    deraw();
    endwin();
    exit(0);
    /*NOTREACHED*/
}

startshow()
{
    showrange = 1;
    showsr = currow;
    showsc = curcol;
}

showdr()
{
    int     minsr, minsc, maxsr, maxsc;

    minsr = showsr < currow ? showsr : currow;
    minsc = showsc < curcol ? showsc : curcol;
    maxsr = showsr > currow ? showsr : currow;
    maxsc = showsc > curcol ? showsc : curcol;
    (void) sprintf (line+linelim,"%s", r_name(minsr, minsc, maxsr, maxsc));
}


goraw()
{
#if SYSV2 || SYSV3
    fixterm();
#else
    cbreak();
    nonl();
    noecho ();
#endif
    kbd_again();
    (void) clear();
    FullUpdate++;
}

deraw()
{
    (void) move (LINES - 1, 0);
    (void) clrtoeol();
    (void) refresh();
#if SYSV2 || SYSV3
    resetterm();
#else
    nocbreak();
    nl();
    echo();
#endif
    resetkbd();
}

signals()
{
#ifdef SYSV3
    void quit();
    void timeout();
#else
    int quit();
    int timeout();
#endif

    (void) signal(SIGINT, SIG_IGN);
    (void) signal(SIGQUIT, quit);
    (void) signal(SIGPIPE, quit);
    (void) signal(SIGTERM, quit);
    (void) signal(SIGALRM, timeout);
    (void) signal(SIGFPE, quit);
    (void) signal(SIGBUS, quit);
}

#ifdef SYSV3
void
#endif
quit()
{
    deraw();
    resetkbd();
    endwin();
    exit(1);
}

modcheck(endstr)
char *endstr;
{
    if (modflg && curfile[0]) {
	char ch, lin[100];

	(void) move (0, 0);
	(void) clrtoeol ();
	(void) sprintf (lin,"File '%s' is modified, save%s? ",curfile,endstr);
	(void) addstr (lin);
	(void) refresh();
	ch = nmgetch();
 	if (ch != 'n' && ch != 'N')
 	    if (writefile(curfile, 0, 0, maxrow, maxcol) < 0)
 		return (1);
	else if (ch == ctl (g) || ch == ctl([)) return(1);
    } else if (modflg) {
	char ch, lin[100];

	(void) move (0, 0);
	(void) clrtoeol ();
	(void) sprintf (lin,"Do you want a chance to save the data? ");
	(void) addstr (lin);
	(void) refresh();
	ch = nmgetch();
	if (ch == 'n' || ch == 'N') return(0);
	else return(1);
      }
    return(0);
}

    
writefile (fname, r0, c0, rn, cn)
char *fname;
{
    register FILE *f;
    register struct ent **p;
    register r, c;
    char save[1024];
    int pid;

    if (Crypt) {
	return (cwritefile(fname, r0, c0, rn, cn));
    }

    if (*fname == 0) fname = &curfile[0];

    (void) strcpy(save,fname);

    f = openout(fname, &pid);
    if (f == 0) {
	error ("Can't create %s", fname);
	return (-1);
    }

    (void) fprintf (f, "# This data file was generated by the Spreadsheet ");
    (void) fprintf (f, "Calculator.\n");
    (void) fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
    for (c=0; c<MAXCOLS; c++)
	if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
	    (void) fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
    write_range(f);
    if (mdir) 
	    (void) fprintf(f, "mdir \"%s\"\n", mdir);
    for (r=r0; r<=rn; r++) {
	p = &tbl[r][0];
	for (c=c0; c<=cn; c++, p++)
	    if (*p) {
		if ((*p)->label) {
		    edits(r,c);
		    (void) fprintf(f, "%s\n",line);
		}
		if ((*p)->flags&is_valid) {
		    editv (r, c);
		    (void) fprintf (f, "%s\n",line);
		}
	    }
    }

    closeout(f, pid);

    if (!pid) {
        (void) strcpy(curfile, save);
        modflg = 0;
        error("File '%s' written.",curfile);
    }

    return (0);
}

readfile (fname,eraseflg)
char *fname;
int eraseflg;
{
    register FILE *f;
    char save[1024];

    if (*fname == '*' && mdir) { 
       (void) strcpy(save, mdir);
       *fname = '/';
       (void) strcat(save, fname);
    } else {
        if (*fname == 0)
	    fname = &curfile[0];
        (void) strcpy(save,fname);
    }

    if (Crypt)  {
	creadfile(save, eraseflg);
	return;
    }

    if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;

    f = fopen (save, "r");
    if (f==0) {
	error ("Can't read %s", save);
	return;
    }

    if (eraseflg) erasedb ();

    while (fgets(line,sizeof line,f)) {
	linelim = 0;
	if (line[0] != '#') (void) yyparse ();
    }
    (void) fclose (f);
    linelim = -1;
    modflg++;
    if (eraseflg) {
	(void) strcpy(curfile,save);
	modflg = 0;
    }
    EvalAll();
}

erasedb () {
    register r, c;
    for (c = 0; c<=maxcol; c++) {
	fwidth[c] = DEFWIDTH;
	precision[c] = DEFPREC;
    }

    for (r = 0; r<=maxrow; r++) {
	register struct ent **p = &tbl[r][0];
	for (c=0; c++<=maxcol; p++)
	    if (*p) {
		if ((*p)->expr) efree ((*p) -> expr);
		if ((*p)->label) xfree ((char *)((*p) -> label));
		xfree ((char *)(*p));
		*p = 0;
	    }
    }
    maxrow = 0;
    maxcol = 0;
    clean_range();
    FullUpdate++;
}

#if DEBUG
debugout(g,fmt,args) FILE *g; char *fmt; {
    int op;

    if (g == 0) g = fopen("debug","a"),op = 1;
    if (g == 0) return;

    _doprnt(fmt, &args, g);

    (void) fflush(g);
    if (op) (void) fclose(g);
}
#endif
\SHAR\EOF\
else
  echo "will not over write ./sc.c"
fi
if [ `wc -c ./sc.c | awk '{printf $1}'` -ne 30534 ]
then
echo `wc -c ./sc.c | awk '{print "Got " $1 ", Expected " 30534}'`
fi
if `test ! -s ./lex.c`
then
echo "Extracting ./lex.c"
cat > ./lex.c << '\SHAR\EOF\'
/*	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();

jmp_buf wakeup;
jmp_buf fpe_buf;

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 *tblp;
	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 (tblp = linelim ? experres : statres; tblp->key; tblp++)
		    if (((tblp->key[0]^tokenst[0])&0137)==0
		     && tblp->key[tokenl]==0) {
			register i = 1;
			while (i<tokenl && ((tokenst[i]^tblp->key[i])&0137)==0)
			    i++;
			if (i>=tokenl) {
			    ret = tblp->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;
		    if (r->r_is_range)
		        ret = RANGE;
		    else
			ret = VAR;
		} else {
		    linelim = p-line;
		    yyerror ("Unintelligible word");
		}
	    }
	}
    } else if ((*p == '.') || isdigit(*p)) {
	double v = 0;
	int 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 {
	    /* A NUMBER must hold at least MAXROW and MAXCOL */
	    /* This is consistent with a short row and col in struct ent */
	    if (v > (double)32767 || v < (double)-32768) {
		ret = FNUMBER;
		yylval.fval = v;
	    } else {
		temp = (int)v;
		if((double)temp != v) {
		    ret = FNUMBER;
		    yylval.fval = v;
		} else {
		    ret = NUMBER;
		    yylval.ival = temp;
		}
	    }
	}
    } else if (*p=='"') {
	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()
{}

kbd_again()
{}

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();
char *ks;
char ks_buf[20];
char *ke;
char ke_buf[20];

#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), ctl(i), ctl(w), 0,
};

charout(c)
int c;
{
	(void)putchar(c);
}

initkbd()
{
    register struct key_map *kp;
    register i,j;
    char *p = keyarea;
    char *ktmp;
    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);
    ktmp = tgetstr("ks",&p);
    if (ktmp)  {
	(void) strcpy(ks_buf, ktmp);
	ks = ks_buf;
	tputs(ks, 1, charout);
    }
    ktmp = tgetstr("ke",&p);
    if (ktmp)  {
	(void) strcpy(ke_buf, ktmp);
	ke = ke_buf;
    }

    /* 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
    (void)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;
    (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
#endif
}

kbd_again()
{
    if (ks) 
	tputs(ks, 1, charout);

#ifdef TIOCSLTC
    (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
#endif
}

resetkbd()
{
    if (ke) 
	tputs(ke, 1, charout);

#ifdef TIOCSLTC
    (void)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;

#ifdef SYSV3
    void timeout();
#else
    int timeout();
#endif

    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) { 

        (void) signal(SIGALRM, timeout);
        (void) alarm(1);

	if (setjmp(wakeup) == 0) { 
	    maybe = nmgetch();
	    (void) 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);
}

kbd_again()
{
    keypad(stdscr, TRUE);
}

resetkbd()
{
    keypad(stdscr, FALSE);
}

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 */

#ifdef SYSV3
void
#endif
timeout()
{
    longjmp(wakeup, -1);
}

int dbline;

/*VARARGS*/
void
debug (str)
char *str;
{
	(void) mvprintw (2+(dbline++%22),80-70,str);
	(void) clrtoeol();
}

#ifdef SYSV3
void
#endif
fpe_trap()
{
    longjmp(fpe_buf, 1);
}

/*
 * 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;
#ifdef SYSV3
    void quit();
#else
    int quit();
#endif

    (void) signal(SIGFPE, fpe_trap);
    if (setjmp(fpe_buf)) {
	error("Floating point exception\n");
	*res = 0.0; 
        (void) signal(SIGFPE, quit);
	return(p);
    }
    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;

    (void) signal(SIGFPE, quit);
    return(p);
}

help () {
    (void) move(1,0);
    (void) 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 ("               w fwd to next       b back to next   ^e <dir> end");
    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       ^w 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 ("Ranges:       /u undefine range   /s show ranges    /d define range");
    debug ("              /c copy range       /x clear range    /f fill range");
    debug ("              /v values only");
    debug ("File:          G get database      M merge database  T write tbl fmt");
    debug ("               P put database      W write listing   R run macros");
    debug ("               D define directory");
    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");
    error("Hit any key to continue ");
    (void) refresh();
    (void) nmgetch();
    FullUpdate++;
    (void) move(1,0);
    (void) clrtobot();
}
\SHAR\EOF\
else
  echo "will not over write ./lex.c"
fi
if [ `wc -c ./lex.c | awk '{printf $1}'` -ne 11396 ]
then
echo `wc -c ./lex.c | awk '{print "Got " $1 ", Expected " 11396}'`
fi
if `test ! -s ./gram.y`
then
echo "Extracting ./gram.y"
cat > ./gram.y << '\SHAR\EOF\'
/*	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"

#define ENULL (struct enode *)0

char *strcpy();
%}

%union {
    int ival;
    double fval;
    struct ent_ptr ent;
    struct enode *enode;
    char *sval;
    struct range_s rval;
}

%type <ent> var
%type <fval> num
%type <rval> range
%type <rval> var_or_range
%type <sval> strarg
%type <enode> e term
%token <sval> STRING
%token <ival> NUMBER
%token <fval> FNUMBER
%token <rval> RANGE
%token <rval> VAR
%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 S_VALUE
%token S_MDIR

%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
%token K_HOUR
%token K_MINUTE
%token K_SECOND
%token K_MONTH
%token K_DAY
%token K_YEAR
%token K_NOW
%token K_DATE
%token K_FMT
%token K_LBL
%token K_SUBSTR
%token K_STON
%token K_EQS

%left '?' ':'
%left '|'
%left '&'
%nonassoc '<' '=' '>' '!'
%left '+' '-' '#'
%left '*' '/'
%left '^'

%%
command:	S_LET var_or_range '=' e
				{ let($2.left.vp, $4); }
	|	S_LABEL var_or_range '=' e
				{ slet($2.left.vp, $4, 0); }
	|	S_LEFTSTRING var_or_range '=' e
				{ slet($2.left.vp, $4, -1); }
	|	S_RIGHTSTRING var_or_range '=' e
				{ slet($2.left.vp, $4, 1); }
	|	S_FORMAT COL ':' COL NUMBER NUMBER
				{ doformat($2,$4,$5,$6); }
	|	S_FORMAT COL NUMBER NUMBER
				{ doformat($2,$2,$3,$4); }
	|	S_GET strarg	{  /* This tmp hack is because readfile
				    * recurses back through yyparse. */
				  char *tmp;
				  tmp = $2;
				  readfile (tmp, 1);
				  xfree(tmp);
				}
	|	S_MERGE strarg	{
				  char *tmp;
				  tmp = $2;
				  readfile (tmp, 0);
				  xfree(tmp);
				}
	|	S_MDIR strarg	
				{ if (mdir) xfree(mdir); mdir = $2; }
	|       S_PUT strarg range
				{ (void) writefile($2, ($3.left.vp)->row, 
			 	($3.left.vp)->col, ($3.right.vp)->row,
			 	($3.right.vp)->col);
			 	xfree($2); }
	|	S_PUT strarg	
				{ (void) writefile ($2, 0, 0, maxrow, maxcol);
			 	xfree($2); }
	|       S_WRITE strarg range { (void) printfile($2, ($3.left.vp)->row, 
			 ($3.left.vp)->col, ($3.right.vp)->row,
			 ($3.right.vp)->col);
			 xfree($2); }
	|	S_WRITE strarg	{ (void) printfile ($2, 0, 0, maxrow, maxcol);
			 xfree($2); }
	|       S_TBL strarg range { (void) tblprintfile($2, ($3.left.vp)->row, 
			 ($3.left.vp)->col, ($3.right.vp)->row,
			 ($3.right.vp)->col);
			 xfree($2); }
	|	S_TBL strarg	{ (void)tblprintfile ($2, 0, 0, maxrow, maxcol);
			 xfree($2); }
	|       S_SHOW COL ':' COL
					{ showcol( $2, $4); }
	|       S_SHOW NUMBER ':' NUMBER
					{ showrow( $2, $4); }
	|	S_COPY range var_or_range 
					{ copy($2.left.vp,$2.right.vp,
					$3.left.vp,$3.right.vp); }
	|	S_ERASE       
					{ eraser(lookat(showsr, showsc),
				        lookat(currow, curcol)); }
	|	S_ERASE var_or_range 
					{ eraser($2.left.vp, $2.right.vp); }
	|	S_VALUE       { valueize_area(showsr, showsc, currow, curcol);
				 modflg++; }
	|	S_VALUE var_or_range { valueize_area(($2.left.vp)->row,
				($2.left.vp)->col,
				($2.right.vp)->row,
				($2.right.vp)->col); modflg++; }
	|	S_FILL num num  { fill(lookat(showsr, showsc),
				      lookat(currow, curcol), $2, $3); }
	|	S_FILL var_or_range num num
				 { fill($2.left.vp, $2.right.vp, $3, $4); }
	|	S_GOTO var_or_range {(void) moveto($2.left.vp); }
	|	S_DEFINE strarg       { struct ent_ptr arg1, arg2;
					arg1.vp = lookat(showsr, showsc);
					arg1.vf = 0;
					arg2.vp = lookat(currow, curcol);
					arg2.vf = 0;
					add_range($2, arg1, arg2, 1); }

	|	S_DEFINE strarg range { add_range($2, $3.left, $3.right, 1); }
	|	S_DEFINE strarg var   { add_range($2, $3, $3, 0); }
	|	S_UNDEFINE var_or_range { del_range($2.left.vp, $2.right.vp); }
	|	/* nothing */
	|	error;

term: 		var		{ $$ = new_var('v', $1); }
	|	K_FIXED term	{ $$ = new ('f', ENULL, $2); }
	|       '@' K_SUM '(' var_or_range ')' 
				{ $$ = new_range(O_REDUCE('+'), $4); }
	|       '@' K_PROD '(' var_or_range ')' 
				{ $$ = new_range (O_REDUCE('*'), $4); }
	|       '@' K_AVG '(' var_or_range ')' 
				{ $$ = new_range (O_REDUCE('a'), $4); }
	|       '@' K_STDDEV '(' var_or_range ')' 
				{ $$ = new_range (O_REDUCE('s'), $4); }
	|       '@' K_MAX '(' var_or_range ')' 
				{ $$ = new_range (O_REDUCE(MAX), $4); }
	|       '@' K_MIN '(' var_or_range ')' 
				{ $$ = new_range (O_REDUCE(MIN), $4); }
	| '@' K_ACOS '(' e ')'
			{ $$ = new(ACOS, ENULL, $4); }
	| '@' K_ASIN '(' e ')'	 { $$ = new(ASIN, ENULL, $4); }
	| '@' K_ATAN '(' e ')'	 { $$ = new(ATAN, ENULL, $4); }
	| '@' K_CEIL '(' e ')'	 { $$ = new(CEIL, ENULL, $4); }
	| '@' K_COS '(' e ')'	 { $$ = new(COS, ENULL, $4); }
	| '@' K_EXP '(' e ')'	 { $$ = new(EXP, ENULL, $4); }
	| '@' K_FABS '(' e ')'	 { $$ = new(FABS, ENULL, $4); }
	| '@' K_FLOOR '(' e ')'	 { $$ = new(FLOOR, ENULL, $4); }
	| '@' K_HYPOT '(' e ',' e ')'	{ $$ = new(HYPOT, $4, $6); }
	| '@' K_LN '(' e ')'	 { $$ = new(LOG, ENULL, $4); }
	| '@' K_LOG '(' e ')'	 { $$ = new(LOG10, ENULL, $4); }
	| '@' K_POW '(' e ',' e ')'	{ $$ = new(POW, $4, $6); }
	| '@' K_SIN '(' e ')'	 { $$ = new(SIN, ENULL, $4); }
	| '@' K_SQRT '(' e ')'	 { $$ = new(SQRT, ENULL, $4); }
	| '@' K_TAN '(' e ')'	 { $$ = new(TAN, ENULL, $4); }
	| '@' K_DTR '(' e ')'	 { $$ = new(DTR, ENULL, $4); }
	| '@' K_RTD '(' e ')'	 { $$ = new(RTD, ENULL, $4); }
	| '@' K_RND '(' e ')'	 { $$ = new(RND, ENULL, $4); }
	| '@' K_HOUR '(' e ')' 	 { $$ = new(HOUR,ENULL, $4); }
	| '@' K_MINUTE '(' e ')' { $$ = new(MINUTE,ENULL, $4); }
	| '@' K_SECOND '(' e ')' { $$ = new(SECOND,ENULL, $4); }
	| '@' K_MONTH '(' e ')'	 { $$ = new(MONTH,ENULL,$4); }
	| '@' K_DAY '(' e ')'    { $$ = new(DAY, ENULL, $4); }
	| '@' K_YEAR '(' e ')'   { $$ = new(YEAR, ENULL, $4); }
	| '@' K_NOW              { $$ = new(NOW, ENULL, ENULL);}
	| '@' K_STON '(' e ')'   { $$ = new(STON, ENULL, $4); }
	| '@' K_EQS '(' e ',' e ')' { $$ = new (EQS, $4, $6); }
	| '@' K_DATE '(' e ')'	 { $$ = new(DATE, ENULL, $4); }
	| '@' K_FMT  '(' e ',' e ')' { $$ = new(FMT, $4, $6); }
	| '@' K_SUBSTR '(' e ',' e ',' e ')'
				 { $$ = new(SUBSTR, $4, new(',', $6, $8)); }
	|	'(' e ')'	 { $$ = $2; }
	|	'+' term	 { $$ = $2; }
	|	'-' term	 { $$ = new ('m', ENULL, $2); }
	|	NUMBER		 { $$ = new_const('k', (double) $1); }
	|	FNUMBER		 { $$ = new_const('k', $1); }
	|	K_PI	{ $$ = new_const('k', (double)3.14159265358979323846); }
	|	STRING	         { $$ = new_str($1); }
	|	'~' term	 { $$ = new ('~', ENULL, $2); }
	|	'!' term	 { $$ = new ('~', ENULL, $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 ('~', ENULL, new ('>', $1, $4)); }
	|	e '!' '=' e	{ $$ = new ('~', ENULL, new ('=', $1, $4)); }
	|	e '>' '=' e	{ $$ = new ('~', ENULL, new ('<', $1, $4)); }
	|	e '#' e		{ $$ = new ('#', $1, $3); }
	;

range:		var ':' var	{ $$.left = $1; $$.right = $3; }
	| 	RANGE		{ $$ = $1; }
	;

var:		COL NUMBER	{ $$.vp = lookat($2 , $1); $$.vf = 0;}
	|	'$' COL NUMBER	{ $$.vp = lookat($3 , $2);
					$$.vf = FIX_COL;}
	|	COL '$' NUMBER	{ $$.vp = lookat($3 , $1);
					$$.vf = FIX_ROW;}
	|	'$' COL '$' NUMBER { $$.vp = lookat($4 , $2);
					$$.vf = FIX_ROW | FIX_COL;}
	|	VAR		{ $$ = $1.left; }
	;

var_or_range:	range		{ $$ = $1; }
	|	var		{ $$.left = $1; $$.right = $1; }
	;

num:		NUMBER		{ $$ = (double) $1; }
	|	FNUMBER		{ $$ = $1; }
	|	'-' num		{ $$ = -$2; }
	|	'+' num		{ $$ = $2; }
	;

strarg:		STRING		{ $$ = $1; }
	|	var		{
				    char *s, *s1;
				    s1 = $1.vp->label;
				    if (!s1)
					s1 = "NULL_STRING";
				    s = xmalloc((unsigned)strlen(s1)+1);
				    (void) strcpy(s, s1);
				    $$ = s;
				}
\SHAR\EOF\
else
  echo "will not over write ./gram.y"
fi
if [ `wc -c ./gram.y | awk '{printf $1}'` -ne 8571 ]
then
echo `wc -c ./gram.y | awk '{print "Got " $1 ", Expected " 8571}'`
fi
echo "Finished archive 2 of 3"
# if you want to concatenate archives, remove anything after this line
exit
-- 
For comp.sources.unix stuff, mail to sources at uunet.uu.net.



More information about the Comp.sources.unix mailing list