/*	SC	A Spreadsheet Calculator
 *		Command and expression parser
 *
 *		James Gosling, September 1982
 *
 */



%{
#include "sc.h"
%}

%union {
    long ival;
    double fval;
    struct ent *ent;
    struct enode *enode;
    char *sval;
}

%type <enode> e term
%type <ent> var
%token <sval> STRING
%token <ival> NUMBER
%type <ival> row, col
%token <fval> FNUMBER
%token <sval> WORD
%type <ival> reduce_op
%token S_FORMAT
%token S_LABEL
%token S_LEFTSTRING
%token S_RIGHTSTRING
%token S_GET
%token S_PUT
%token S_LET
%token S_WRITE
%token K_FIXED
%token K_R
%token K_C

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

%%
command:	S_LET var '=' e	{ let ($2, $4); }
	|	S_LABEL var '=' STRING
				{ label ($2, $4, 0); }
	|	S_LEFTSTRING var '=' STRING
				{ label ($2, $4, -1); }
	|	S_RIGHTSTRING var '=' STRING
				{ label ($2, $4, 1); }
	|	S_FORMAT NUMBER NUMBER NUMBER
				{ fwidth[$2] = $3;
				  FullUpdate++;
				  precision[$2] = $4; }
	|	S_GET STRING	{ readfile ($2); }
	|	S_PUT STRING	{ writefile ($2); }
	|	S_WRITE STRING	{ printfile ($2); }
	|	/* nothing */
	|	error;

row:		K_R NUMBER	{ $$ = $2; };
col:		K_C NUMBER	{ $$ = $2; };
var:		row col		{ $$ = lookat($1, $2); }
	|	col row		{ $$ = lookat($2, $1); };

reduce_op:	'+'		{ $$ = '+'; }
	|	'*'		{ $$ = '*'; }
	;

term:		var		{ $$ = new ('v', $1); }
	|	K_FIXED term	{ $$ = new ('f', 0, $2); }
	|	reduce_op '/' var ':' var
				{ $$ = new (O_REDUCE($1), $3, $5); }
	|	'(' e ')'	{ $$ = $2; }
	|	'+' term	{ $$ = $2; }
	|	'-' term	{ $$ = new ('m', 0, $2); }
	|	NUMBER		{ $$ = new ('k', (double) $1); }
	|	FNUMBER		{ $$ = new ('k', $1); }
	|	'~' term	{ $$ = new ('~', 0, $2); }
	|	'!' term	{ $$ = new ('~', 0, $2); }
	;

e:		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 ('~', 0, new ('>', $1, $4)); }
	|	e '!' '=' e	{ $$ = new ('~', 0, new ('=', $1, $4)); }
	|	e '>' '=' e	{ $$ = new ('~', 0, new ('<', $1, $4)); }
	;
