/* ----------------------------------------------------------------------
 * FILE: rhparse.y
 * PACKAGE: rh - recursive file finder.
 * VERSION: 4.0
 * DESCRIPTION:
 *	This contains the YACC parser for the rh language.
 *
 * REVISION HISTORY:
 *	Oct 20, 1990 - re-Created.
 *
 * AUTHOR:
 *	Ken Stauffer.
 * ---------------------------------------------------------------------- */

%{

#include <time.h>
#include <varargs.h>
#include "rh.h"

#define YYSTYPE		union yystack

int	lineno;		/* current line number */

static struct symbol *curfunc = NULL;

extern struct expr	*genbinary(), *gentrinary(), *genvar(), *genparam(),
			*genident(), *genstring(), *gennumber(), *genbuiltin(),
			*genargs(), *genfunc();

extern union yystack	yylval;
extern char	*rhstr;
extern char	*rhfilename;
extern FILE	*rhfile;

%}

/* types of the non-terminals */
%type <sym> id ids id_list
%type <expr> lval factor func expr expr1 expr2 unary_expr arg_list args optexpr
%type <value> stat stat_list if_tail

/* Definition of returned tokens from the lexical analyzer */
%token ADDOP	/* += */
%token SUBOP	/* -= */
%token MULOP	/* *= */
%token DIVOP	/* /= */
%token MODOP	/* %= */
%token OROP	/* |= */
%token ANDOP	/* &= */
%token LSHOP	/* <<= */
%token RSHOP	/* >>= */
%token XOROP	/* ^= */
%token OR	/* || */
%token AND	/* && */
%token LE	/* < */
%token GE	/* > */
%token NE	/* != */
%token EQ	/* == */
%token SHIFTL	/* >> */
%token SHIFTR	/* << */
%token PLUSPLUS		/* ++ */
%token MINUSMINUS	/* -- */

%token <value> NUMBER
%token <string> STRING
%token <sym> FIELD
%token <sym> FUNCTION
%token <sym> PARAMETER
%token <sym> IDENTIFIER
%token <sym> VARIABLE
%token <sym> BUILTIN

%token BEGIN
%token END
%token BREAK
%token CONTINUE
%token DO
%token ELSE
%token EXIT
%token FOR
%token IF
%token NEXT
%token RETURN
%token UNDEFINE
%token WHILE

%right '=' ADDOP SUBOP MULOP DIVOP MODOP OROP ANDOP LSHOP RSHOP XOROP
%left OR
%left AND
%left '|'
%left '^'
%left '&'
%left EQ NE
%left '<' LE '>' GE
%left SHIFTL SHIFTR
%left '+' '-'
%left '*' '/' '%'

%start program

%%
program	:	expr				{ gen1match($1);
						  gendefault(); }
		| bigprogram
		;

bigprogram	: func
		| matchrule
		| undefine
		| bigprogram func
		| bigprogram matchrule
		| bigprogram undefine
		;

undefine	: UNDEFINE undef_list ';'

undef		: IDENTIFIER		{}
		| FUNCTION		{ remove($1->name); }
		| VARIABLE
			{ if( $1->bvar )
				error("%s is a built in variable", $1->name);
			  else
				remove($1->name);
			}
		;

undef_list	: undef
		| undef_list ',' undef
		;

matchrule	: expr
						{ gen1match($1); }
			'{' stat_list '}'
						{ gen2match(); }

		| expr ';'			{ gen1match($1);
						  gendefault(); }

		| BEGIN
						{ genbeg1(); }
			'{' stat_list '}'
						{ genbeg2(); }

		| END
						{ genend1(); }
			'{' stat_list '}'
						{ genend2(); }

		| '{'
						{ gen1match(NULL); }
			stat_list '}'
						{ gen2match(); }
		;

func		: IDENTIFIER id_list
						{ func_1($1,$2);
						  curfunc = $1; }
			'{' opt_stat_list '}'
						{ func_2($1,$2);
						  curfunc = NULL; }
		;

opt_stat_list	: stat_list
		| /* empty */
		;

id_list		: '(' ids ')'	{ $$ = $2; }

		| '(' ')'
				{ $$ = NULL; }
		;

ids		: id
				{ $1->type = PARAMETER;
				  $1->val = 0;
				  $1->param = NULL;
				  $$ = $1; }

		| ids ',' id
				{ $3->type = PARAMETER;
				  $3->val = $1->val + 1;
				  $3->param = $1;
				  $$ = $3; }
		;

id		: PARAMETER
				{ error("%s is already used as a parameter",
								$1->name); }
		| VARIABLE
				{ error("%s is already a global variable",
								$1->name); }
		| IDENTIFIER
				{ $$ = $1; }
		| FUNCTION
				{ error("%s is already a function",
								$1->name); }
		;

stat		: RETURN optexpr ';'		{ gen_return($2,curfunc); }
		| expr ';'			{ gen_expr($1); }
		| BREAK ';'			{ gen_break(lineno); }
		| CONTINUE ';'			{ gen_continue(lineno); }
		| NEXT ';'			{ gen_next(curfunc); }

		| IF '(' expr ')'
						{ $$ = gen_if1($3); }
				stat if_tail
						{ gen_if2($<value>5,$7); }

		| FOR '(' optexpr ';' optexpr ';' optexpr ')'
						{ $$ = gen1for($3,$5); }
				stat
						{ gen2for($<value>9,$7); }

		| WHILE '(' expr ')'
						{ $$ = gen1while($3); }
			stat
						{ gen2while($<value>5); }

		| DO
						{ $$ = gen_do1(); }
			stat WHILE '(' expr ')' ';'
						{ gen_do2($6,$<value>2); }

		| '{' stat_list '}'				{;}
		| '{' '}'					{;}
		| ';'						{;}
		;

if_tail:	/* empty */			{ $$ = -1; }
		| ELSE { $$ = gen_if3(); } stat
						{ $$ = $<value>2; }
		;

stat_list	: stat_list stat			{;}
		| stat					{;}
		;

optexpr		: expr			{ $$ = $1; }
		| /* empty */		{ $$ = gennumber(1); }
		;

unary_expr	: '!' unary_expr	{ $$ = genbinary(OP_NOT,NULL,$2); }
		| '-' unary_expr	{ $$ = genbinary(OP_NEG,NULL,$2); }
		| '~' unary_expr	{ $$ = genbinary(OP_BNOT,NULL,$2); }
		| PLUSPLUS lval		{ $$ = genbinary(OP_ADDOP,$2,gennumber(1)); }
		| MINUSMINUS lval	{ $$ = genbinary(OP_SUBOP,$2,gennumber(1)); }
		| lval PLUSPLUS
				{ $$ = genbinary(OP_PLUSPLUS,NULL,$1); }
		| lval MINUSMINUS
				{ $$ = genbinary(OP_MINUSMINUS,NULL,$1); }
		| factor		{ $$ = $1; }
		;

expr2		: expr2 OR expr2	{ $$ = genbinary(OP_OR1,$1,$3); }
		| expr2 AND expr2	{ $$ = genbinary(OP_AND1,$1,$3); }
		| expr2 '|' expr2	{ $$ = genbinary(OP_BOR,$1,$3); }
		| expr2 '^' expr2	{ $$ = genbinary(OP_XOR,$1,$3); }
		| expr2 '&' expr2	{ $$ = genbinary(OP_BAND,$1,$3); }
		| expr2 EQ expr2	{ $$ = genbinary(OP_EQ,$1,$3); }
		| expr2 NE expr2	{ $$ = genbinary(OP_NE,$1,$3); }
		| expr2 '>' expr2	{ $$ = genbinary(OP_GT,$1,$3); }
		| expr2 '<' expr2	{ $$ = genbinary(OP_LT,$1,$3); }
		| expr2 GE expr2	{ $$ = genbinary(OP_GE,$1,$3); }
		| expr2 LE expr2	{ $$ = genbinary(OP_LE,$1,$3); }
		| expr2 SHIFTL expr2	{ $$ = genbinary(OP_SHL,$1,$3); }
		| expr2 SHIFTR expr2	{ $$ = genbinary(OP_SHR,$1,$3); }
		| expr2 '+' expr2	{ $$ = genbinary(OP_ADD,$1,$3); }
		| expr2 '-' expr2	{ $$ = genbinary(OP_SUB,$1,$3); }
		| expr2 '%' expr2	{ $$ = genbinary(OP_MOD,$1,$3); }
		| expr2 '*' expr2	{ $$ = genbinary(OP_MUL,$1,$3); }
		| expr2 '/' expr2	{ $$ = genbinary(OP_DIV,$1,$3); }
		| unary_expr		{ $$ = $1; }
		;

expr1		: expr2 '?' expr1 ':' expr1	{ $$ = gentrinary($1,$3,$5); }
		| expr2				{ $$ = $1; }
		;

expr		: lval '=' expr		{ $$ = genbinary(OP_ASSIGN,$1,$3); }
		| lval ADDOP expr	{ $$ = genbinary(OP_ADDOP,$1,$3); }
		| lval SUBOP expr	{ $$ = genbinary(OP_SUBOP,$1,$3); }
		| lval MULOP expr	{ $$ = genbinary(OP_MULOP,$1,$3); }
		| lval DIVOP expr	{ $$ = genbinary(OP_DIVOP,$1,$3); }
		| lval MODOP expr	{ $$ = genbinary(OP_MODOP,$1,$3); }
		| lval RSHOP expr	{ $$ = genbinary(OP_RSHOP,$1,$3); }
		| lval LSHOP expr	{ $$ = genbinary(OP_LSHOP,$1,$3); }
		| lval OROP expr	{ $$ = genbinary(OP_OROP,$1,$3); }
		| lval ANDOP expr	{ $$ = genbinary(OP_ANDOP,$1,$3); }
		| lval XOROP expr	{ $$ = genbinary(OP_XOROP,$1,$3); }
		| expr1			{ $$ = $1; }
		;

lval		: VARIABLE			{ $$ = genvar($1,NULL); }
		| VARIABLE '[' expr ']'		{ $$ = genvar($1,$3); }
		| PARAMETER			{ $$ = genparam($1,NULL); }
		| PARAMETER '[' expr ']'	{ $$ = genparam($1,$3); }
		| IDENTIFIER			{ $$ = genident($1,NULL); }
		| IDENTIFIER '[' expr ']'	{ $$ = genident($1,$3); }
		;

factor		: '(' expr ')'			{ $$ = $2; }
		| STRING			{ $$ = genstring($1); }
		| NUMBER			{ $$ = gennumber($1); }
		| lval				{ $$ = $1; }
		| FUNCTION arg_list		{ $$ = genfunc($1,$2); }
		| BUILTIN arg_list		{ $$ = genbuiltin($1,$2); }
		;

arg_list	: '(' args ')'			{ $$ = $2; }
		| '(' ')'			{ $$ = NULL; }
		| /* empty */			{ $$ = NULL; }
		;

args		: expr				{ $$ = genargs(NULL,$1); }
		| args ',' expr			{ $$ = genargs($1,$3); }
		;

%%

/* yyerror -
 *	Pass control to the "real" error function.
 */

yyerror(s)
char *s;
{
	error(s);
}

/* error -
 *	Print an error and exit. Do not attempt to recover from
 *	the error.
 */

error(va_alist)
va_dcl
{
	va_list ap;
	char *fmt;

	va_start(ap);
	fmt = va_arg(ap, char *);

	fprintf(stderr,"%s: line: %d, ",rhfilename, lineno);

	vfprintf(stderr,fmt, ap);
	fprintf(stderr,".\n");

	va_end(ap);
	exit(1);
}