/* 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 * * More mods by Alan Silverstein, 3/88, see list of changes. * * $Revision: 7.16 $ */ %{ #include #include #include "sc.h" #ifdef USELOCALE #include #endif #ifndef MSDOS #include #endif #define ENULL (struct enode *)0 %} %union { int ival; double fval; struct ent_ptr ent; struct enode *enode; char *sval; struct range_s rval; } %type var %type num %type range %type var_or_range %type strarg %type e term expr_list %token STRING %token NUMBER %token FNUMBER %token RANGE %token VAR %token WORD %token PLUGIN %token COL /* * When adding new commands, make sure that any commands that may take * COL as an argument precede S_FORMAT in the %token list. All other * commands must come after S_FORMAT. This is necessary so that range * names can be less than three letters without being parsed as column * names. */ %token S_SHOW %token S_HIDE %token S_INSERTCOL %token S_OPENCOL %token S_DELETECOL %token S_YANKCOL %token S_GETFORMAT %token S_FORMAT %token S_FMT %token S_LET %token S_LABEL %token S_LEFTSTRING %token S_RIGHTSTRING %token S_LEFTJUSTIFY %token S_RIGHTJUSTIFY %token S_CENTER %token S_COLOR %token S_ADDNOTE %token S_DELNOTE %token S_GET %token S_PUT %token S_MERGE %token S_WRITE %token S_TBL %token S_COPY %token S_MOVE %token S_ERASE %token S_YANK %token S_FILL %token S_SORT %token S_LOCK %token S_UNLOCK %token S_GOTO %token S_DEFINE %token S_UNDEFINE %token S_ABBREV %token S_UNABBREV %token S_FRAME %token S_FRAMETOP %token S_FRAMEBOTTOM %token S_FRAMELEFT %token S_FRAMERIGHT %token S_UNFRAME %token S_VALUE %token S_MDIR %token S_AUTORUN %token S_FKEY %token S_SCEXT %token S_ASCEXT %token S_TBL0EXT %token S_TBLEXT %token S_LATEXEXT %token S_SLATEXEXT %token S_TEXEXT %token S_SET %token S_UP %token S_DOWN %token S_LEFT %token S_RIGHT %token S_ENDUP %token S_ENDDOWN %token S_ENDLEFT %token S_ENDRIGHT %token S_SELECT %token S_INSERTROW %token S_OPENROW %token S_DELETEROW %token S_YANKROW %token S_PULL %token S_PULLMERGE %token S_PULLROWS %token S_PULLCOLS %token S_PULLXCHG %token S_PULLTP %token S_PULLFMT %token S_PULLCOPY %token S_WHEREAMI %token S_GETNUM %token S_FGETNUM %token S_GETSTRING %token S_GETEXP %token S_GETFMT %token S_GETFRAME %token S_GETRANGE %token S_EVAL %token S_SEVAL %token S_QUERY %token S_GETKEY %token S_ERROR %token S_RECALC %token S_REDRAW %token S_QUIT %token S_STATUS %token S_RUN %token S_PLUGIN %token S_PLUGOUT %token K_ERROR %token K_INVALID %token K_FIXED %token K_SUM %token K_PROD %token K_AVG %token K_STDDEV %token K_COUNT %token K_ROWS %token K_COLS %token K_ABS %token K_ACOS %token K_ASIN %token K_ATAN %token K_ATAN2 %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_ROUND %token K_IF %token K_PV %token K_FV %token K_PMT %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_DTS %token K_TTS %token K_FMT %token K_SUBSTR %token K_UPPER %token K_LOWER %token K_CAPITAL %token K_STON %token K_EQS %token K_EXT %token K_NVAL %token K_SVAL %token K_LOOKUP %token K_HLOOKUP %token K_VLOOKUP %token K_INDEX %token K_STINDEX %token K_AUTO %token K_AUTOCALC %token K_AUTOINSERT %token K_AUTOWRAP %token K_CSLOP %token K_BYROWS %token K_BYCOLS %token K_OPTIMIZE %token K_ITERATIONS %token K_NUMERIC %token K_PRESCALE %token K_EXTFUN %token K_CELLCUR %token K_TOPROW %token K_COLOR %token K_COLORNEG %token K_COLORERR %token K_BRAILLE %token K_BLACK %token K_RED %token K_GREEN %token K_YELLOW %token K_BLUE %token K_MAGENTA %token K_CYAN %token K_WHITE %token K_TBLSTYLE %token K_TBL %token K_LATEX %token K_SLATEX %token K_TEX %token K_FRAME %token K_RNDTOEVEN %token K_FILENAME %token K_MYROW %token K_MYCOL %token K_LASTROW %token K_LASTCOL %token K_COLTOA %token K_CRACTION %token K_CRROW %token K_CRCOL %token K_ROWLIMIT %token K_COLLIMIT %token K_PAGESIZE %token K_NUMITER %token K_ERR %token K_SCRC %token K_LOCALE %right ';' %left '?' ':' %left '|' %left '&' %nonassoc '<' '=' '>' '!' %left '+' '-' '#' %left '*' '/' '%' %left '^' %% command: S_LET var_or_range '=' e { let($2.left.vp, $4); } | S_LET var_or_range '=' { $2.left.vp->v = (double) 0.0; if ($2.left.vp->expr && !($2.left.vp->flags & is_strexpr)) { efree($2.left.vp->expr); $2.left.vp->expr = NULL; } $2.left.vp->cellerror = CELLOK; $2.left.vp->flags &= ~is_valid; $2.left.vp->flags |= is_changed; changed++; FullUpdate++; modflg++; } | 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_LEFTJUSTIFY var_or_range { ljustify($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } | S_LEFTJUSTIFY { if (showrange) ljustify(showsr, showsc, currow, curcol); } | S_RIGHTJUSTIFY var_or_range { rjustify($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } | S_RIGHTJUSTIFY { if (showrange) rjustify(showsr, showsc, currow, curcol); } | S_CENTER var_or_range { center($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } | S_CENTER { if (showrange) center(showsr, showsc, currow, curcol); } | S_ADDNOTE var { if (showrange) { $2.vp->nrow=currowncol=curcolnlastrow=currownlastcol=curcolnrow=currow; $2.vp->ncol=curcol; $2.vp->nlastrow=currow; $2.vp->nlastcol=curcol; } $2.vp->flags |= is_changed; FullUpdate++; modflg++; } | S_ADDNOTE var var_or_range { $2.vp->nrow = $3.left.vp->row; $2.vp->ncol = $3.left.vp->col; $2.vp->nlastrow = $3.right.vp->row; $2.vp->nlastcol = $3.right.vp->col; $2.vp->flags |= is_changed; FullUpdate++; modflg++; } | S_DELNOTE var { $2.vp->nrow = $2.vp->ncol = -1; } | S_DELNOTE { struct ent *p; p = lookat(currow, curcol); p->nrow = p->ncol = -1; p->flags |= is_changed; modflg++; } | S_FORMAT COL ':' COL NUMBER NUMBER NUMBER { doformat($2,$4,$5,$6,$7); } | S_FORMAT COL NUMBER NUMBER NUMBER { doformat($2,$2,$3,$4,$5); } | S_FORMAT COL ':' COL NUMBER NUMBER { doformat($2,$4,$5,$6, REFMTFIX); } | S_FORMAT COL NUMBER NUMBER { doformat($2,$2,$3,$4, REFMTFIX); } | S_FORMAT NUMBER '=' STRING { if ($2 >= 0 && $2 < 10) { if (colformat[$2]) scxfree(colformat[$2]); if (strlen($4)) colformat[$2] = $4; else colformat[$2] = NULL; FullUpdate++; modflg++; } else error("Invalid format number"); } | S_GET strarg { /* This tmp hack is because readfile * recurses back through yyparse. */ char *tmp; tmp = $2; readfile(tmp, 1); scxfree(tmp); } | S_MERGE strarg { char *tmp; tmp = $2; readfile(tmp, 0); scxfree(tmp); } | S_MDIR strarg { if (mdir) scxfree(mdir); if (strlen($2)) mdir = $2; modflg++; } | S_AUTORUN strarg { if (autorun) scxfree(autorun); if (strlen($2)) autorun = $2; modflg++; } | S_FKEY NUMBER '=' strarg { if ($2 > 0 && $2 <= FKEYS) { if (fkey[$2 - 1]) { scxfree(fkey[$2 - 1]); fkey[$2 - 1] = NULL; } if (strlen($4)) fkey[$2 - 1] = $4; modflg++; } else error("Invalid function key"); } | S_SCEXT strarg { if (scext) scxfree(scext); scext = $2; } | S_ASCEXT strarg { if (ascext) scxfree(ascext); ascext = $2; } | S_TBL0EXT strarg { if (tbl0ext) scxfree(tbl0ext); tbl0ext = $2; } | S_TBLEXT strarg { if (tblext) scxfree(tblext); tblext = $2; } | S_LATEXEXT strarg { if (latexext) scxfree(latexext); latexext = $2; } | S_SLATEXEXT strarg { if (slatexext) scxfree(slatexext); slatexext = $2; } | S_TEXEXT strarg { if (texext) scxfree(texext); texext = $2; } | S_PUT strarg range { (void) writefile($2, ($3.left.vp)->row, ($3.left.vp)->col, ($3.right.vp)->row, ($3.right.vp)->col); scxfree($2); } | S_PUT strarg { (void) writefile($2, 0, 0, maxrow, maxcol); scxfree($2); } | S_PUT range { (void) write_cells(stdout, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $2.left.vp->row, $2.left.vp->col); } | S_PUT range '/' var_or_range { (void) write_cells(stdout, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $4.left.vp->row, $4.left.vp->col); } | S_PUT '%' '/' var_or_range { (void) write_cells(stdout, 0, 0, maxrow, maxcol, $4.left.vp->row, $4.left.vp->col); } | S_PUT '/' var_or_range { (void) write_cells(stdout, showsr, showsc, currow, curcol, $3.left.vp->row, $3.left.vp->col); } | S_PUT '%' { (void) write_cells(stdout, 0, 0, maxrow, maxcol, 0, 0); } | S_PUT { (void) write_cells(stdout, 0, 0, maxrow, maxcol, 0, 0); } | S_WRITE strarg range { (void) printfile($2, ($3.left.vp)->row, ($3.left.vp)->col, ($3.right.vp)->row, ($3.right.vp)->col); scxfree($2); } | S_WRITE strarg { (void) printfile($2, 0, 0, maxrow, maxcol); scxfree($2); } | S_WRITE range { (void) printfile(NULL, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col); } | S_WRITE '%' { (void) printfile(NULL, 0, 0, maxrow, maxcol); } | S_WRITE { (void) printfile(NULL, 0, 0, maxrow, maxcol); } | S_TBL strarg range { (void) tblprintfile($2, ($3.left.vp)->row, ($3.left.vp)->col, ($3.right.vp)->row, ($3.right.vp)->col); scxfree($2); } | S_TBL strarg { (void)tblprintfile($2, 0, 0, maxrow, maxcol); scxfree($2); } | S_SHOW COL ':' COL { showcol($2, $4); } | S_SHOW NUMBER ':' NUMBER { showrow($2, $4); } | S_HIDE { int arg; if (showrange == SHOWROWS) { if (showsr < currow) { int r = currow; currow = showsr; showsr = r; } arg = showsr - currow + 1; hiderow(arg); } else if (showrange == SHOWCOLS) { if (showsc < curcol) { int c = curcol; curcol = showsc; showsc = c; } arg = showsc - curcol + 1; hidecol(arg); } else arg = 1; } | S_HIDE COL { hide_col($2); } | S_HIDE COL ':' COL { int c = curcol, arg; if ($2 < $4) { curcol = $2; arg = $4 - $2 + 1; } else { curcol = $4; arg = $2 - $4 + 1; } hidecol(arg); curcol = c < curcol ? c : c < curcol + arg ? curcol : c - arg; } | S_HIDE NUMBER { hide_row($2); } | S_HIDE NUMBER ':' NUMBER { int r = currow, arg; if ($2 < $4) { currow = $2; arg = $4 - $2 + 1; } else { currow = $4; arg = $2 - $4 + 1; } hiderow(arg); currow = r < currow ? r : r < currow + arg ? currow : r - arg; } | S_COPY { if (showrange) { showrange = 0; copy(lookat(showsr, showsc), lookat(currow, curcol), NULL, NULL); } else copy(lookat(currow, curcol), lookat(currow, curcol), NULL, NULL); } | S_COPY range { copy($2.left.vp, $2.right.vp, NULL, NULL); } | S_COPY range var_or_range { copy($2.left.vp, $2.right.vp, $3.left.vp, $3.right.vp); } | S_MOVE var { mover($2.vp, lookat(showsr, showsc), lookat(currow, curcol)); } | S_MOVE var var_or_range { mover($2.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_YANK { yankr(lookat(showsr, showsc), lookat(currow, curcol)); } | S_YANK var_or_range { yankr($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 var_or_range num num { fill($2.left.vp, $2.right.vp, $3, $4); } | S_SORT { sortrange(lookat(showsr, showsc), lookat(currow, curcol), NULL); } | S_SORT range { sortrange($2.left.vp, $2.right.vp, NULL); } | S_SORT range strarg { sortrange($2.left.vp, $2.right.vp, $3); } | S_FMT var_or_range STRING { format_cell($2.left.vp, $2.right.vp, $3); } | S_LOCK { lock_cells(lookat(showsr, showsc), lookat(currow, curcol)); } | S_LOCK var_or_range { lock_cells($2.left.vp, $2.right.vp); } | S_UNLOCK { unlock_cells(lookat(showsr, showsc), lookat(currow, curcol)); } | S_UNLOCK var_or_range { unlock_cells($2.left.vp, $2.right.vp); } | S_GOTO var_or_range var_or_range { moveto($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $3.left.vp->row, $3.left.vp->col); } | S_GOTO var_or_range { moveto($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, -1, -1); } | S_GOTO num range { num_search($2, $3.left.vp->row, $3.left.vp->col, $3.right.vp->row, $3.right.vp->col, 0); } | S_GOTO num { num_search($2, 0, 0, maxrow, maxcol, 0); } | S_GOTO errlist | S_GOTO STRING range { str_search($2, $3.left.vp->row, $3.left.vp->col, $3.right.vp->row, $3.right.vp->col, 0); } | S_GOTO '#' STRING range { str_search($3, $4.left.vp->row, $4.left.vp->col, $4.right.vp->row, $4.right.vp->col, 1); } | S_GOTO '%' STRING range { str_search($3, $4.left.vp->row, $4.left.vp->col, $4.right.vp->row, $4.right.vp->col, 2); } | S_GOTO STRING { str_search($2, 0, 0, maxrow, maxcol, 0); } | S_GOTO '#' STRING { str_search($3, 0, 0, maxrow, maxcol, 1); } | S_GOTO '%' STRING { str_search($3, 0, 0, maxrow, maxcol, 2); } | S_GOTO { go_last(); } | S_GOTO WORD { /* don't repeat last goto on "unintelligible word" */ ; } | S_DEFINE strarg { struct ent_ptr arg1, arg2; arg1.vp = lookat(showsr, showsc); arg1.vf = 0; arg2.vp = lookat(currow, curcol); arg2.vf = 0; if (arg1.vp == arg2.vp || !showrange) add_range($2, arg2, arg2, 0); else 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); } | S_ABBREV STRING { add_abbr($2); } | S_ABBREV { add_abbr(NULL); } | S_UNABBREV STRING { del_abbr($2); } | S_FRAME range range { add_frange($2.left.vp, $2.right.vp, $3.left.vp, $3.right.vp, 0, 0, 0, 0); } | S_FRAME range { if (showrange) { showrange = 0; add_frange($2.left.vp, $2.right.vp, lookat(showsr, showsc), lookat(currow, curcol), 0, 0, 0, 0); } else { struct frange *cfr; cfr = find_frange(currow, curcol); if (cfr) { add_frange(cfr->or_left, cfr->or_right, $2.left.vp, $2.right.vp, 0, 0, 0, 0); } } } | S_FRAME { struct frange *cfr; /* cfr points to current frange */ cfr = find_frange(currow, curcol); if (showrange && cfr) { showrange = 0; add_frange(cfr->or_left, cfr->or_right, lookat(showsr, showsc), lookat(currow, curcol), 0, 0, 0, 0); } else { error("Need both outer and inner" " ranges to create frame"); } } | S_FRAMETOP range NUMBER { add_frange($2.left.vp, $2.right.vp, NULL, NULL, $3, -1, -1, -1); } | S_FRAMETOP NUMBER { struct frange *cfr; /* cfr points to current frange */ cfr = find_frange(currow, curcol); if (cfr) add_frange(cfr->or_left, cfr->or_right, NULL, NULL, $2, -1, -1, -1); } | S_FRAMEBOTTOM range NUMBER { add_frange($2.left.vp, $2.right.vp, NULL, NULL, -1, $3, -1, -1); } | S_FRAMEBOTTOM NUMBER { struct frange *cfr; /* cfr points to current frange */ cfr = find_frange(currow, curcol); if (cfr) add_frange(cfr->or_left, cfr->or_right, NULL, NULL, -1, $2, -1, -1); } | S_FRAMELEFT range NUMBER { add_frange($2.left.vp, $2.right.vp, NULL, NULL, -1, -1, $3, -1); } | S_FRAMELEFT NUMBER { struct frange *cfr; /* cfr points to current frange */ cfr = find_frange(currow, curcol); if (cfr) add_frange(cfr->or_left, cfr->or_right, NULL, NULL, -1, -1, $2, -1); } | S_FRAMERIGHT range NUMBER { add_frange($2.left.vp, $2.right.vp, NULL, NULL, -1, -1, -1, $3); } | S_FRAMERIGHT NUMBER { struct frange *cfr; /* cfr points to current frange */ cfr = find_frange(currow, curcol); if (cfr) add_frange(cfr->or_left, cfr->or_right, NULL, NULL, -1, -1, -1, $2); } | S_UNFRAME range { add_frange($2.left.vp, $2.right.vp, NULL, NULL, 0, 0, 0, 0); } | S_UNFRAME { struct frange *cfr; /* cfr points to current frange */ cfr = find_frange(currow, curcol); if (cfr) add_frange(cfr->or_left, cfr->or_right, NULL, NULL, 0, 0, 0, 0); } | S_COLOR NUMBER '=' { if ($2 > 0 && $2 < 9) initcolor($2); else error("Invalid color number"); } | S_COLOR NUMBER '=' e { change_color($2, $4); } | S_COLOR range NUMBER { add_crange($2.left.vp, $2.right.vp, $3); } | S_SET setlist { modflg++; } | S_UP { backrow( 1); } | S_UP NUMBER { backrow($2); } | S_DOWN { forwrow( 1); } | S_DOWN NUMBER { forwrow($2); } | S_LEFT { backcol( 1); } | S_LEFT NUMBER { backcol($2); } | S_RIGHT { forwcol( 1); } | S_RIGHT NUMBER { forwcol($2); } | S_ENDUP { doend(-1, 0); } | S_ENDDOWN { doend( 1, 0); } | S_ENDLEFT { doend( 0,-1); } | S_ENDRIGHT { doend( 0, 1); } | S_SELECT STRING { int c; if ((c = *$2) >= '0' && c <= '9') { qbuf = c - '0' + (DELBUFSIZE - 10); } else if (c >= 'a' && c <= 'z') { qbuf = c - 'a' + (DELBUFSIZE - 36); } else if (c == '"') { qbuf = 0; } else error("Invalid buffer"); scxfree($2); } | S_INSERTROW { insertrow( 1, 0); } | S_INSERTROW '*' NUMBER { insertrow($3, 0); } | S_OPENROW { insertrow( 1, 1); } | S_OPENROW '*' NUMBER { insertrow($3, 1); } | S_INSERTCOL { insertcol( 1, 0); } | S_INSERTCOL '*' NUMBER { insertcol($3, 0); } | S_OPENCOL { insertcol( 1, 1); } | S_OPENCOL '*' NUMBER { insertcol($3, 1); } | S_DELETEROW { int arg; if (showrange == SHOWROWS) { if (showsr < currow) { int r = currow; currow = showsr; showsr = r; } arg = showsr - currow + 1; } else arg = 1; deleterow(arg); } | S_DELETEROW '*' NUMBER { deleterow($3); } | S_DELETEROW NUMBER { int r = currow; currow = $2; deleterow(1); currow = r <= currow ? r : r - 1; } | S_DELETEROW NUMBER ':' NUMBER { int r = currow, arg; if ($2 < $4) { currow = $2; arg = $4 - $2 + 1; } else { currow = $4; arg = $2 - $4 + 1; } deleterow(arg); currow = r < currow ? r : r < currow + arg ? currow : r - arg; } | S_DELETECOL { int arg; if (showrange == SHOWCOLS) { if (showsc < curcol) { int c = curcol; curcol = showsc; showsc = c; } arg = showsc - curcol + 1; } else arg = 1; closecol(arg); } | S_DELETECOL COL { int r = curcol; curcol = $2; closecol(1); curcol = r <= curcol ? r : r - 1; } | S_DELETECOL '*' NUMBER { closecol($3); } | S_DELETECOL COL ':' COL { int c = curcol, arg; if ($2 < $4) { curcol = $2; arg = $4 - $2 + 1; } else { curcol = $4; arg = $2 - $4 + 1; } closecol(arg); curcol = c < curcol ? c : c < curcol + arg ? curcol : c - arg; } | S_YANKROW { int r = currow, arg; if (showrange == SHOWROWS) { if (showsr < currow) { currow = showsr; showsr = r; } arg = showsr - currow + 1; } else arg = 1; yankrow(arg); currow = r; } | S_YANKROW '*' NUMBER { yankrow($3); } | S_YANKROW NUMBER { int r = currow; currow = $2; yankrow(1); currow = r; } | S_YANKROW NUMBER ':' NUMBER { int r = currow, arg; if ($2 < $4) { currow = $2; arg = $4 - $2 + 1; } else { currow = $4; arg = $2 - $4 + 1; } yankrow(arg); currow = r; } | S_YANKCOL { int c = curcol, arg; if (showrange == SHOWCOLS) { if (showsc < curcol) { curcol = showsc; showsc = c; } arg = showsc - curcol + 1; } else arg = 1; yankcol(arg); curcol = c; } | S_YANKCOL NUMBER { int c = curcol; curcol = $2; yankcol(1); curcol = c; } | S_YANKCOL '*' NUMBER { yankcol($3); } | S_YANKCOL COL ':' COL { int c = curcol, arg; if ($2 < $4) { curcol = $2; arg = $4 - $2 + 1; } else { curcol = $4; arg = $2 - $4 + 1; } yankcol(arg); curcol = c; } | S_PULL { pullcells('p'); } | S_PULLMERGE { pullcells('m'); } | S_PULLROWS { pullcells('r'); } | S_PULLCOLS { pullcells('c'); } | S_PULLXCHG { pullcells('x'); } | S_PULLTP { pullcells('t'); } | S_PULLFMT { pullcells('f'); } | S_PULLCOPY { copy(NULL, NULL, NULL, NULL); } | S_PULLCOPY var_or_range { copy($2.left.vp, $2.right.vp, NULL, (struct ent *)1); } | S_WHEREAMI { sprintf(line, "%s%d ", coltoa(curcol), currow); sprintf(line + strlen(line), "%s%d\n", coltoa(stcol), strow); write(macrofd, line, strlen(line)); line[0] = '\0'; } | S_WHEREAMI '|' NUMBER { sprintf(line, "%s%d ", coltoa(curcol), currow); sprintf(line + strlen(line), "%s%d\n", coltoa(stcol), strow); write($3, line, strlen(line)); line[0] = '\0'; } | S_GETNUM var_or_range { getnum($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, macrofd); } | S_GETNUM var_or_range '|' NUMBER { getnum($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $4); } | S_GETNUM { getnum(currow, curcol, currow, curcol, macrofd); } | S_GETNUM '|' NUMBER { getnum(currow, curcol, currow, curcol, $3); } | S_FGETNUM var_or_range { fgetnum($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, macrofd); } | S_FGETNUM var_or_range '|' NUMBER { fgetnum($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $4); } | S_FGETNUM { fgetnum(currow, curcol, currow, curcol, macrofd); } | S_FGETNUM '|' NUMBER { fgetnum(currow, curcol, currow, curcol, $3); } | S_GETSTRING var_or_range { getstring($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, macrofd); } | S_GETSTRING var_or_range '|' NUMBER { getstring($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $4); } | S_GETSTRING { getstring(currow, curcol, currow, curcol, macrofd); } | S_GETSTRING '|' NUMBER { getstring(currow, curcol, currow, curcol, $3); } | S_GETEXP var_or_range { getexp($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, macrofd); } | S_GETEXP var_or_range '|' NUMBER { getexp($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $4); } | S_GETEXP { getexp(currow, curcol, currow, curcol, macrofd); } | S_GETEXP '|' NUMBER { getexp(currow, curcol, currow, curcol, $3); } | S_GETFORMAT COL { getformat($2, macrofd); } | S_GETFORMAT COL '|' NUMBER { getformat($2, $4); } | S_GETFORMAT { getformat(curcol, macrofd); } | S_GETFORMAT '|' NUMBER { getformat(curcol, $3); } | S_GETFMT var_or_range { getfmt($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, macrofd); } | S_GETFMT var_or_range '|' NUMBER { getfmt($2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, $4); } | S_GETFMT { getfmt(currow, curcol, currow, curcol, macrofd); } | S_GETFMT '|' NUMBER { getfmt(currow, curcol, currow, curcol, $3); } | S_GETFRAME { getframe(macrofd); } | S_GETFRAME '|' NUMBER { getframe($3); } | S_GETRANGE STRING { getrange($2, macrofd); } | S_GETRANGE STRING '|' NUMBER { getrange($2, $4); } | S_EVAL e { doeval($2, NULL, currow, curcol, macrofd); } | S_EVAL e STRING { doeval($2, $3, currow, curcol, macrofd); } | S_EVAL e STRING '|' NUMBER { doeval($2, $3, currow, curcol, $3); } | S_SEVAL e { doseval($2, currow, curcol, macrofd); } | S_QUERY STRING STRING { doquery($2, $3, macrofd); } | S_QUERY STRING STRING '|' NUMBER { doquery($2, $3, $5); } | S_QUERY STRING { doquery($2, NULL, macrofd); } | S_QUERY STRING '|' NUMBER { doquery($2, NULL, $4); } | S_QUERY { doquery(NULL, NULL, macrofd); } | S_QUERY '|' NUMBER { doquery(NULL, NULL, $3); } | S_GETKEY { dogetkey(); } | S_ERROR STRING { error($2); } | S_STATUS { dostat(macrofd); } | S_STATUS '|' NUMBER { dostat($3); } | S_RECALC { EvalAll(); update(1); changed = 0; } | S_REDRAW { if (usecurses) { clearok(stdscr, TRUE); linelim = -1; update(1); refresh(); changed = 0; } } | S_QUIT { stopdisp(); exit(0); } | S_RUN STRING { deraw(1); system($2); if (*($2 + strlen($2) - 1) != '&') { printf("Press any key to continue "); fflush(stdout); cbreak(); nmgetch(); } goraw(); scxfree($2); } | S_PLUGIN STRING '=' STRING { addplugin($2, $4, 'r'); } | S_PLUGOUT STRING '=' STRING { addplugin($2, $4, 'w'); } | PLUGIN { *line = '|'; sprintf(line + 1, $1); readfile(line, 0); scxfree($1); } | /* nothing */ | error; term: var { $$ = new_var(O_VAR, $1); } | '@' K_FIXED term { $$ = new('f', $3, ENULL); } | '(' '@' K_FIXED ')' term { $$ = new('F', $5, ENULL); } | '@' K_SUM '(' var_or_range ')' { $$ = new(SUM, new_range(REDUCE | SUM, $4), ENULL); } | '@' K_SUM '(' range ',' e ')' { $$ = new(SUM, new_range(REDUCE | SUM, $4), $6); } | '@' K_PROD '(' var_or_range ')' { $$ = new(PROD, new_range(REDUCE | PROD, $4), ENULL); } | '@' K_PROD '(' range ',' e ')' { $$ = new(PROD, new_range(REDUCE | PROD, $4), $6); } | '@' K_AVG '(' var_or_range ')' { $$ = new(AVG, new_range(REDUCE | AVG, $4), ENULL); } | '@' K_AVG '(' range ',' e ')' { $$ = new(AVG, new_range(REDUCE | AVG, $4), $6); } | '@' K_STDDEV '(' var_or_range ')' { $$ = new(STDDEV, new_range(REDUCE | STDDEV, $4), ENULL); } | '@' K_STDDEV '(' range ',' e ')' { $$ = new(STDDEV, new_range(REDUCE | STDDEV, $4), $6); } | '@' K_COUNT '(' var_or_range ')' { $$ = new(COUNT, new_range(REDUCE | COUNT, $4), ENULL); } | '@' K_COUNT '(' range ',' e ')' { $$ = new(COUNT, new_range(REDUCE | COUNT, $4), $6); } | '@' K_MAX '(' var_or_range ')' { $$ = new(MAX, new_range(REDUCE | MAX, $4), ENULL); } | '@' K_MAX '(' range ',' e ')' { $$ = new(MAX, new_range(REDUCE | MAX, $4), $6); } | '@' K_MAX '(' e ',' expr_list ')' { $$ = new(LMAX, $6, $4); } | '@' K_MIN '(' var_or_range ')' { $$ = new(MIN, new_range(REDUCE | MIN, $4), ENULL); } | '@' K_MIN '(' range ',' e ')' { $$ = new(MIN, new_range(REDUCE | MIN, $4), $6); } | '@' K_MIN '(' e ',' expr_list ')' { $$ = new(LMIN, $6, $4); } | '@' K_ROWS '(' var_or_range ')' { $$ = new_range(REDUCE | 'R', $4); } | '@' K_COLS '(' var_or_range ')' { $$ = new_range(REDUCE | 'C', $4); } | '@' K_ABS '(' e ')' { $$ = new(ABS, $4, ENULL); } | '@' K_ACOS '(' e ')' { $$ = new(ACOS, $4, ENULL); } | '@' K_ASIN '(' e ')' { $$ = new(ASIN, $4, ENULL); } | '@' K_ATAN '(' e ')' { $$ = new(ATAN, $4, ENULL); } | '@' K_ATAN2 '(' e ',' e ')' { $$ = new(ATAN2, $4, $6); } | '@' K_CEIL '(' e ')' { $$ = new(CEIL, $4, ENULL); } | '@' K_COS '(' e ')' { $$ = new(COS, $4, ENULL); } | '@' K_EXP '(' e ')' { $$ = new(EXP, $4, ENULL); } | '@' K_FABS '(' e ')' { $$ = new(FABS, $4, ENULL); } | '@' K_FLOOR '(' e ')' { $$ = new(FLOOR, $4, ENULL); } | '@' K_HYPOT '(' e ',' e ')' { $$ = new(HYPOT, $4, $6); } | '@' K_LN '(' e ')' { $$ = new(LOG, $4, ENULL); } | '@' K_LOG '(' e ')' { $$ = new(LOG10, $4, ENULL); } | '@' K_POW '(' e ',' e ')' { $$ = new(POW, $4, $6); } | '@' K_SIN '(' e ')' { $$ = new(SIN, $4, ENULL); } | '@' K_SQRT '(' e ')' { $$ = new(SQRT, $4, ENULL); } | '@' K_TAN '(' e ')' { $$ = new(TAN, $4, ENULL); } | '@' K_DTR '(' e ')' { $$ = new(DTR, $4, ENULL); } | '@' K_RTD '(' e ')' { $$ = new(RTD, $4, ENULL); } | '@' K_RND '(' e ')' { $$ = new(RND, $4, ENULL); } | '@' K_ROUND '(' e ',' e ')' { $$ = new(ROUND, $4, $6); } | '@' K_IF '(' e ',' e ',' e ')' { $$ = new(IF, $4,new(',',$6,$8)); } | '@' K_PV '(' e ',' e ',' e ')' { $$ = new(PV, $4,new(':',$6,$8)); } | '@' K_FV '(' e ',' e ',' e ')' { $$ = new(FV, $4,new(':',$6,$8)); } | '@' K_PMT '(' e ',' e ',' e ')' { $$ = new(PMT, $4,new(':',$6,$8)); } | '@' K_HOUR '(' e ')' { $$ = new(HOUR, $4, ENULL); } | '@' K_MINUTE '(' e ')' { $$ = new(MINUTE, $4, ENULL); } | '@' K_SECOND '(' e ')' { $$ = new(SECOND, $4, ENULL); } | '@' K_MONTH '(' e ')' { $$ = new(MONTH, $4, ENULL); } | '@' K_DAY '(' e ')' { $$ = new(DAY, $4, ENULL); } | '@' K_YEAR '(' e ')' { $$ = new(YEAR, $4, ENULL); } | '@' K_NOW { $$ = new(NOW, ENULL, ENULL);} | '@' K_DTS '(' e ',' e ',' e ')' { $$ = new(DTS, $4, new(',', $6, $8));} | NUMBER '.' NUMBER '.' NUMBER { $$ = new(DTS, new_const(O_CONST, (double) $1), new(',', new_const(O_CONST, (double) $3), new_const(O_CONST, (double) $5)));} | '@' K_TTS '(' e ',' e ',' e ')' { $$ = new(TTS, $4, new(',', $6, $8));} | '@' K_STON '(' e ')' { $$ = new(STON, $4, ENULL); } | '@' K_EQS '(' e ',' e ')' { $$ = new(EQS, $4, $6); } | '@' K_DATE '(' e ')' { $$ = new(DATE, $4, ENULL); } | '@' K_DATE '(' e ',' e ')' { $$ = new(DATE, $4, $6); } | '@' K_FMT '(' e ',' e ')' { $$ = new(FMT, $4, $6); } | '@' K_UPPER '(' e ')' { $$ = new(UPPER, $4, ENULL); } | '@' K_LOWER '(' e ')' { $$ = new(LOWER, $4, ENULL); } | '@' K_CAPITAL '(' e ')' { $$ = new(CAPITAL, $4, ENULL); } | '@' K_INDEX '(' range ',' e ')' { $$ = new(INDEX, new_range(REDUCE | INDEX, $4), $6); } | '@' K_INDEX '(' e ',' range ')' { $$ = new(INDEX, new_range(REDUCE | INDEX, $6), $4); } | '@' K_INDEX '(' range ',' e ',' e ')' { $$ = new(INDEX, new_range(REDUCE | INDEX, $4), new(',', $6, $8)); } | '@' K_LOOKUP '(' range ',' e ')' { $$ = new(LOOKUP, new_range(REDUCE | LOOKUP, $4), $6); } | '@' K_LOOKUP '(' e ',' range ')' { $$ = new(LOOKUP, new_range(REDUCE | LOOKUP, $6), $4); } | '@' K_HLOOKUP '(' range ',' e ',' e ')' { $$ = new(HLOOKUP, new_range(REDUCE | HLOOKUP, $4), new(',', $6, $8)); } | '@' K_HLOOKUP '(' e ',' range ',' e ')' { $$ = new(HLOOKUP, new_range(REDUCE | HLOOKUP, $6), new(',', $4, $8)); } | '@' K_VLOOKUP '(' range ',' e ',' e ')' { $$ = new(VLOOKUP, new_range(REDUCE | VLOOKUP, $4), new(',', $6, $8)); } | '@' K_VLOOKUP '(' e ',' range ',' e ')' { $$ = new(VLOOKUP, new_range(REDUCE | VLOOKUP, $6), new(',', $4, $8)); } | '@' K_STINDEX '(' range ',' e ')' { $$ = new(STINDEX, new_range(REDUCE | STINDEX, $4), $6); } | '@' K_STINDEX '(' e ',' range ')' { $$ = new(STINDEX, new_range(REDUCE | STINDEX, $6), $4); } | '@' K_STINDEX '(' range ',' e ',' e ')' { $$ = new(STINDEX, new_range(REDUCE | STINDEX, $4), new(',', $6, $8)); } | '@' K_EXT '(' e ',' e ')' { $$ = new(EXT, $4, $6); } | '@' K_NVAL '(' e ',' e ')' { $$ = new(NVAL, $4, $6); } | '@' K_SVAL '(' e ',' e ')' { $$ = new(SVAL, $4, $6); } | '@' K_SUBSTR '(' e ',' e ',' e ')' { $$ = new(SUBSTR, $4, new(',', $6, $8)); } | '(' e ')' { $$ = $2; } | '+' term { $$ = $2; } | '-' term { $$ = new('m', $2, ENULL); } | NUMBER { $$ = new_const(O_CONST, (double) $1); } | FNUMBER { $$ = new_const(O_CONST, $1); } | '@' K_PI { $$ = new(PI_, ENULL, ENULL); } | STRING { $$ = new_str($1); } | '~' term { $$ = new('!', $2, ENULL); } | '!' term { $$ = new('!', $2, ENULL); } | '@' K_FILENAME '(' e ')' { $$ = new(FILENAME, $4, ENULL); } | '@' K_MYROW { $$ = new(MYROW, ENULL, ENULL);} | '@' K_MYCOL { $$ = new(MYCOL, ENULL, ENULL);} | '@' K_LASTROW { $$ = new(LASTROW, ENULL, ENULL);} | '@' K_LASTCOL { $$ = new(LASTCOL, ENULL, ENULL);} | '@' K_COLTOA '(' e ')' { $$ = new(COLTOA, $4, ENULL);} | '@' K_NUMITER { $$ = new(NUMITER, ENULL, ENULL);} | '@' K_ERR { $$ = new(ERR_, ENULL, ENULL); } | K_ERR { $$ = new(ERR_, ENULL, ENULL); } | '@' K_BLACK { $$ = new(BLACK, ENULL, ENULL); } | '@' K_RED { $$ = new(RED, ENULL, ENULL); } | '@' K_GREEN { $$ = new(GREEN, ENULL, ENULL); } | '@' K_YELLOW { $$ = new(YELLOW, ENULL, ENULL); } | '@' K_BLUE { $$ = new(BLUE, ENULL, ENULL); } | '@' K_MAGENTA { $$ = new(MAGENTA, ENULL, ENULL); } | '@' K_CYAN { $$ = new(CYAN, ENULL, ENULL); } | '@' K_WHITE { $$ = new(WHITE, ENULL, ENULL); } ; /* expressions */ 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); } | 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('|', $1, $3); } | e '<' '=' e { $$ = new('!', new('>', $1, $4), ENULL); } | e '!' '=' e { $$ = new('!', new('=', $1, $4), ENULL); } | e '<' '>' e { $$ = new('!', new('=', $1, $4), ENULL); } | e '>' '=' e { $$ = new('!', new('<', $1, $4), ENULL); } | e '#' e { $$ = new('#', $1, $3); } ; expr_list: e { $$ = new(ELIST, ENULL, $1); } | expr_list ',' e { $$ = new(ELIST, $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 = scxmalloc((unsigned)strlen(s1)+1); (void) strcpy(s, s1); $$ = s; } ; /* allows >=1 'setitem's to be listed in the same 'set' command */ setlist : | setlist setitem ; /* things that you can 'set' */ setitem : K_AUTO { setauto(1); } | K_AUTOCALC { setauto(1); } | '~' K_AUTO { setauto(0); } | '~' K_AUTOCALC { setauto(0); } | '!' K_AUTO { setauto(0); } | '!' K_AUTOCALC { setauto(0); } | K_BYCOLS { setorder(BYCOLS); } | K_BYROWS { setorder(BYROWS); } | K_OPTIMIZE { optimize = 1; } | '~' K_OPTIMIZE { optimize = 0; } | '!' K_OPTIMIZE { optimize = 0; } | K_NUMERIC { numeric = 1; } | '~' K_NUMERIC { numeric = 0; } | '!' K_NUMERIC { numeric = 0; } | K_PRESCALE { prescale = 0.01; } | '~' K_PRESCALE { prescale = 1.0; } | '!' K_PRESCALE { prescale = 1.0; } | K_EXTFUN { extfunc = 1; } | '~' K_EXTFUN { extfunc = 0; } | '!' K_EXTFUN { extfunc = 0; } | K_CELLCUR { showcell = 1; } | '~' K_CELLCUR { showcell = 0; } | '!' K_CELLCUR { showcell = 0; } | K_TOPROW { showtop = 1; } | '~' K_TOPROW { showtop = 0; } | '!' K_TOPROW { showtop = 0; } | K_AUTOINSERT { autoinsert = 1; } | '~' K_AUTOINSERT { autoinsert = 0; } | '!' K_AUTOINSERT { autoinsert = 0; } | K_AUTOWRAP { autowrap = 1; } | '~' K_AUTOWRAP { autowrap = 0; } | '!' K_AUTOWRAP { autowrap = 0; } | K_CSLOP { cslop = 0; } | '~' K_CSLOP { cslop = 1; } | '!' K_CSLOP { cslop = 1; } | K_COLOR { color = 1; if (usecurses && has_colors()) { color_set(1, NULL); bkgd(COLOR_PAIR(1) | ' '); FullUpdate++; } } | '!' K_COLOR { color = 0; if (usecurses && has_colors()) { color_set(0, NULL); bkgd(COLOR_PAIR(0) | ' '); } } | '~' K_COLOR { color = 0; if (usecurses && has_colors()) { color_set(0, NULL); bkgd(COLOR_PAIR(0) | ' '); } } | K_COLORNEG { colorneg = 1; } | '!' K_COLORNEG { colorneg = 0; } | '~' K_COLORNEG { colorneg = 0; } | K_COLORERR { colorerr = 1; } | '!' K_COLORERR { colorerr = 0; } | '~' K_COLORERR { colorerr = 0; } | K_BRAILLE { braille = 1; } | '!' K_BRAILLE { braille = 0; } | '~' K_BRAILLE { braille = 0; } | K_ITERATIONS '=' NUMBER { setiterations($3); } | K_TBLSTYLE '=' NUMBER { tbl_style = $3; } | K_TBLSTYLE '=' K_TBL { tbl_style = TBL; } | K_TBLSTYLE '=' K_LATEX { tbl_style = LATEX; } | K_TBLSTYLE '=' K_SLATEX { tbl_style = SLATEX; } | K_TBLSTYLE '=' K_TEX { tbl_style = TEX; } | K_TBLSTYLE '=' K_FRAME { tbl_style = FRAME; } | K_RNDTOEVEN { rndtoeven = 1; FullUpdate++; } | '!' K_RNDTOEVEN { rndtoeven = 0; FullUpdate++; } | '~' K_RNDTOEVEN { rndtoeven = 0; FullUpdate++; } | K_CRACTION '=' NUMBER { craction = $3; } | K_ROWLIMIT '=' NUMBER { rowlimit = $3; } | K_COLLIMIT '=' NUMBER { collimit = $3; } | K_PAGESIZE '=' NUMBER { pagesize = $3; } | K_SCRC { scrc++; } | K_LOCALE { #ifdef USELOCALE struct lconv *locstruct; char *loc; loc = setlocale(LC_ALL, ""); if (loc != NULL) { locstruct = localeconv(); dpoint = (locstruct->decimal_point)[0]; thsep = (locstruct->thousands_sep)[0]; } else { dpoint = '.'; thsep = ','; } FullUpdate++; #else error("Locale support not available"); #endif } | '!' K_LOCALE { dpoint = '.'; thsep = ','; FullUpdate++; } | '~' K_LOCALE { dpoint = '.'; thsep = ','; FullUpdate++; } ; /* types of errors, to 'goto' */ errlist : K_ERROR range { num_search((double)0, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, CELLERROR); } | K_ERROR { num_search((double)0, 0, 0, maxrow, maxcol, CELLERROR); } | K_INVALID range { num_search((double)0, $2.left.vp->row, $2.left.vp->col, $2.right.vp->row, $2.right.vp->col, CELLINVALID); } | K_INVALID { num_search((double)0, 0, 0, maxrow, maxcol, CELLINVALID); } ;