%{
/*{{定型コード:y.tab.y(宣言部,%{〜%}内)======================================*/
#ifdef  PIECE
#include "app.h"
#else //PIECE
#include "winapp.h"
#pragma warning(default: 4131)	//{{2016/03/01追加:clipstd.hにてC4131の警告レベルを引き上げましたが、Bison/Flexの生成コードには旧スタイルの宣言が使われているので、Bison/Flexの生成コードのみ警告レベルを元に戻しました。}}
#endif//PIECE
/* パーサースタックの初期値を定義します。
 * sizeof(YYSTYPE)*YYINITDEPTH) がスタック上に確保されます。
 * デフォルトでは200と定義されており、P/ECEには大きすぎます。
 * P/ECEに適切な、小さなサイズ(16)に、再定義しました。
 * パーサースタックが不足した場合は、自動的に拡張されるので、問題ありません。
 */
#define YYINITDEPTH 16
///* エラー報告関数を定義します。 */	→{{2015/03/06:'-e'オプション対応のためにwinapp.cへ移動しました。}}
//void yyerror(const char* fmt, ...) {
//  fprintf(stderr, "### error at line %d : ", yylineno);
//  { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); }
//  fputc('\n', stderr); }
/*}}定型コード:y.tab.y(宣言部,%{〜%}内)======================================*/
%}

%union {
	int		v_num;
	double		v_dbl;
	char*		v_str;
	ST_Symbol*		v_symbol;
	ST_GameMode*		v_gameMode;
	ST_GameModeBody*	v_gameModeBody;
	ST_ReelStrip*		v_reelStrip;
	ST_ReelStripRow*	v_reelStripRow;
	ST_ReelStripRowBody*	v_reelStripRowBody;
	ST_LineDef*		v_lineDef;
	ST_LineDefRow*		v_lineDefRow;
	ST_LineDefRowBody*	v_lineDefRowBody;
	ST_PayTable*		v_payTable;
	ST_PayTableRow*		v_payTableRow;
	ST_PayTableRowBody*	v_payTableRowBody;
}

%token	<v_num>		T_NUM
%token	<v_dbl>		T_DBL
%token	<v_str>		T_LAB
%token	<v_str>		T_STR
%token			T_EOL
%token			T_END

%type	<v_num>		int_arg
%type	<v_num>		expr
%type	<v_dbl>		edbl
%type	<v_str>		estr
%type	<v_symbol>		symbolRow
%type	<v_symbol>		symbolDef
%type	<v_symbol>		symbolRef
%type	<v_gameMode>		gameMode
%type	<v_str>			labelRow
%type	<v_gameModeBody>	gameModeBody
%type	<v_reelStrip>		reelStrip
%type	<v_reelStripRow>	reelStripRow
%type	<v_reelStripRowBody>	reelStripRowBody
%type	<v_lineDef>		lineDef
%type	<v_lineDefRow>		lineDefRow
%type	<v_lineDefRowBody>	lineDefRowBody
%type	<v_num>			row
%type	<v_payTable>		payTable
%type	<v_payTableRow>		payTableRow
%type	<v_payTableRowBody>	payTableRowBody
%type	<v_num>			pay

%left			'|'
%left			'^'
%left			'&'
%left			T_SHL T_SHR
%left			'+' '-'
%left			'*' '/' '%'
%nonassoc		'~' T_UPL T_UMI T_CAST_INT T_CAST_DBL

%%

all
		: pre_blank
		| all symbolRow					{ addSymbolRow($2); yyerrok; }	//error記号の位置について『http://www.pwv.co.jp/~take/TakeWiki/index.php?Cコンパイラ設計(yacc・lexの応用)/第4章　エラー・リカバリ#dbd8d417』の【optional sequence】を参考にした。
		| all gameMode					{ addGameMode($2); yyerrok; }	//error記号の位置について『http://www.pwv.co.jp/~take/TakeWiki/index.php?Cコンパイラ設計(yacc・lexの応用)/第4章　エラー・リカバリ#dbd8d417』の【optional sequence】を参考にした。
		| all error									//全てのシンタクスエラーを報告するために継続する。
		;
pre_blank
		: /* empty */
		| pre_blank T_EOL
		;
eols
		:      T_EOL
		| eols T_EOL
		;
end
		: T_END eols
		;
int_arg
		: expr						/* use default action */
		| edbl						{ $$ =  cast_dbl_to_int($1); }
		;
expr
		: T_NUM						/* use default action */
		| '(' expr ')'					{ $$ =  $2; }
		| T_CAST_INT expr				{ $$ =  $2; }
		| T_CAST_INT edbl				{ $$ =  $2; }
		| '+' expr %prec T_UPL				{ $$ =  $2; }
		| '-' expr %prec T_UMI				{ $$ = -$2; }
		| '~' expr					{ $$ = ~$2; }
		| expr '+' expr					{ $$ = $1 + $3; }
		| expr '-' expr					{ $$ = $1 - $3; }
		| expr '*' expr					{ $$ = $1 * $3; }
		| expr '/' expr					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 / $3; }
		| expr '%' expr					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 % $3; }
		| expr '&' expr					{ $$ = $1 & $3; }
		| expr '^' expr					{ $$ = $1 ^ $3; }
		| expr '|' expr					{ $$ = $1 | $3; }
		| expr T_SHL expr				{ if((unsigned)$3 >= 32) { yyerror("shift count >= 32"); yynerrs++; YYERROR; } $$ = $1 << $3; }
		| expr T_SHR expr				{ if((unsigned)$3 >= 32) { yyerror("shift count >= 32"); yynerrs++; YYERROR; } $$ = $1 >> $3; }
		;
edbl
		: T_DBL
		| '(' edbl ')'					{ $$ =  $2; }
		| T_CAST_DBL expr				{ $$ =  $2; }
		| T_CAST_DBL edbl				{ $$ =  $2; }
		| '+' edbl %prec T_UPL				{ $$ =  $2; }
		| '-' edbl %prec T_UMI				{ $$ = -$2; }
		| edbl '+' edbl					{ $$ = $1 + $3; }
		| edbl '+' expr					{ $$ = $1 + $3; }
		| expr '+' edbl					{ $$ = $1 + $3; }
		| edbl '-' edbl					{ $$ = $1 - $3; }
		| edbl '-' expr					{ $$ = $1 - $3; }
		| expr '-' edbl					{ $$ = $1 - $3; }
		| edbl '*' edbl					{ $$ = $1 * $3; }
		| edbl '*' expr					{ $$ = $1 * $3; }
		| expr '*' edbl					{ $$ = $1 * $3; }
		| edbl '/' edbl					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 / $3; }
		| edbl '/' expr					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 / $3; }
		| expr '/' edbl					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 / $3; }
		;
estr
		: T_STR
		| '(' estr ')'					{ $$ = $2; }
		| estr '+' estr					{ $$ = strconcat($1, $3, NULL); }
		;
		/*--------------------------------------------*/
symbolRow
		: symbolDef eols				/* use default action */
		;
symbolDef
		: T_LAB estr					{ if(!($$ = SymbolDef_New(  $1,   $2))) { YYERROR; } }
		;
symbolRef
		: T_LAB						{ if(!($$ = SymbolRef_New(  $1, NULL))) { YYERROR; } }
		|       estr					{ if(!($$ = SymbolRef_New(NULL,   $1))) { YYERROR; } }
		;
		/*--------------------------------------------*/
gameMode
		: labelRow gameModeBody end			{ if(!($$ = GameMode_New($1, $2))) { YYERROR; } }
		;
labelRow
		: T_LAB eols					/* use default action */
		;
gameModeBody
		: reelStrip lineDef payTable			{ if(!($$ = GameModeBody_New($1, $2, $3))) { YYERROR; } }
		| reelStrip payTable lineDef			{ if(!($$ = GameModeBody_New($1, $3, $2))) { YYERROR; } }
		| lineDef reelStrip payTable			{ if(!($$ = GameModeBody_New($2, $1, $3))) { YYERROR; } }
		| lineDef payTable reelStrip			{ if(!($$ = GameModeBody_New($3, $1, $2))) { YYERROR; } }
		| payTable reelStrip lineDef			{ if(!($$ = GameModeBody_New($2, $3, $1))) { YYERROR; } }
		| payTable lineDef reelStrip			{ if(!($$ = GameModeBody_New($3, $2, $1))) { YYERROR; } }
		;
		/*- - - - - - - - - - - - - - - - - - - - - - */
reelStrip
		:           reelStripRow			{ if(!($$ = ReelStrip_New($1))) { YYERROR; } }
		| reelStrip reelStripRow			{ if(!($$ = ReelStrip_AddReelStripRow($1, $2))) { YYERROR; } }
		;
reelStripRow
		: reelStripRowBody eols				{ if(!($$ = ReelStripRow_New($1))) { YYERROR; } }
		;
reelStripRowBody
		:                  symbolRef			{ if(!($$ = ReelStripRowBody_New($1))) { YYERROR; } }
		| reelStripRowBody symbolRef			{ if(!($$ = ReelStripRowBody_AddSymbol($1, $2))) { YYERROR; } }
		;
		/*- - - - - - - - - - - - - - - - - - - - - - */
lineDef
		:         lineDefRow				{ if(!($$ = LineDef_New($1))) { YYERROR; } }
		| lineDef lineDefRow				{ if(!($$ = LineDef_AddLineDefRow($1, $2))) { YYERROR; } }
		;
lineDefRow
		: lineDefRowBody eols				{ if(!($$ = LineDefRow_New($1))) { YYERROR; } }
		;
lineDefRowBody
		:                    row			{ if(!($$ = LineDefRowBody_New($1))) { YYERROR; } }
		| lineDefRowBody ',' row			{ if(!($$ = LineDefRowBody_AddRow($1, $3))) { YYERROR; } }
		;
row
		: int_arg					{ if(($$ = Row_New($1)) == -1) { YYERROR; } }
		;
		/*- - - - - - - - - - - - - - - - - - - - - - */
payTable
		:          payTableRow				{ if(!($$ = PayTable_New($1))) { YYERROR; } }
		| payTable payTableRow				{ if(!($$ = PayTable_AddPayTableRow($1, $2))) { YYERROR; } }
		;
payTableRow
		: payTableRowBody eols				{ if(!($$ = PayTableRow_New($1))) { YYERROR; } }
		;
payTableRowBody
		: symbolRef       '=' pay			{ if(!($$ = PayTableRowBody_New($1, $3))) { YYERROR; } }
		| payTableRowBody ',' pay			{ if(!($$ = PayTableRowBody_AddPay($1, $3))) { YYERROR; } }
		;
pay
		: int_arg					{ if(($$ = Pay_New($1)) == -1) { YYERROR; } }
		;

%%
