%{
/*{{定型コード: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_Tex*		v_tex;
	ST_TexHdr*	v_texHdr;
	ST_TexBody*	v_texBody;
	ST_Spr*		v_spr;
}

%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
%token			T_GRID
%token			T_RESOURCE
%token			T_LOOP

%type	<v_num>		int_arg
%type	<v_num>		expr
%type	<v_dbl>		edbl
%type	<v_str>		estr
%type	<v_num>		x
%type	<v_num>		y
%type	<v_num>		p
%type	<v_str>		param
%type	<v_tex>		tex
%type	<v_texHdr>	texRow
%type	<v_texHdr>	texHdr
%type	<v_texBody>	texBody
%type	<v_spr>		spr

%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 tex						{ addTex($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); }
		;
		/*--------------------------------------------*/
x
		: int_arg ':' int_arg					{ $$ = ($1 * grid_w) + $3; }	//グリッド単位:ピクセル単位
		| int_arg						{ $$ = ($1 * grid_w)     ; }	//グリッド単位
		|         ':' int_arg					{ $$ =                 $2; }	//            :ピクセル単位
		;
		/*- - - - - - - - - - - - - - - - - - - - - - */
y
		: int_arg ':' int_arg					{ $$ = ($1 * grid_h) + $3; }	//グリッド単位:ピクセル単位
		| int_arg						{ $$ = ($1 * grid_h)     ; }	//グリッド単位
		|         ':' int_arg					{ $$ =                 $2; }	//            :ピクセル単位
		;
		/*- - - - - - - - - - - - - - - - - - - - - - */
p
	    //{{本当はこの↓ように書きたいのだが、'%'を一つ先読みした時点では'expr%expr'と'(expr->int_arg)%'が判断出来ず、'shift/reduce conflict'が発生してしまう。
	    //	: int_arg '%'						/* use default action */	//幅,又は,高さに対するパーセンテージ%
	    //↓止むを得ず、ここだけこの↓ように引数がexprである場合とedblである場合を明示的に分けて書く事にした。これで上記の'shift/reduce conflict'が回避出来た。
		: expr '%'						/* use default action */	//幅,又は,高さに対するパーセンテージ%
		| edbl '%'						{ $$ =  cast_dbl_to_int($1); }	//幅,又は,高さに対するパーセンテージ%
	    //}}根本的な原因はパーセンテージ指定を示す記号に剰余と同じ'%'を使用したのが問題なのだが、それ以外の記号では直観的ではないのでこのままにしたい。だからパーセンテージ指定を示す記号は変えずに上記のように回避する事にした。
		;
		/*- - - - - - - - - - - - - - - - - - - - - - */
param
		: estr							/* use default action */		//<例> "DRW_CLR(1,2)|DRW_REVX"	スクリプト自体をCプリプロセッサに掛けない場合は、文字列をそのまま出力し後で展開する。
		| int_arg						{ $$ = strdup_printf("%d", $1); }	//<例>  DRW_CLR(1,2)|DRW_REVX	スクリプト自体をCプリプロセッサに掛ける場合は、スクリプトコンパイル前に数値化出来る。
		;
		/*--------------------------------------------*/
tex
		: texRow						{ if(!($$ = Tex_new($1, TexBody_new(1,1/*ダミー*/)))) { YYERROR; } }	//スプライト定義無しの場合
		| texHdr texBody end					{ if(!($$ = Tex_new($1, $2))) { YYERROR; } }				//スプライト定義有りの場合
		;
texRow
		: T_LAB estr                              eols		{ if(!($$ = TexHdr_new(  $1,   $2, 0, 0))) { YYERROR; } }
		| T_LAB estr T_RESOURCE                   eols		{ if(!($$ = TexHdr_new(  $1,   $2, 1, 0))) { YYERROR; } }						//リソースフラグはP/ECE用のテクスチャ定義ヘッダだけに影響する。汎用の列挙定義,及び,レジストリスクリプトでは無視される。
		| T_LAB estr            T_LOOP            eols		{ if(!($$ = TexHdr_new(  $1,   $2, 0, 1))) { YYERROR; } }																					//ループフラグはレジストリスクリプトだけに出力する。Windowsでムービーグラフィックを再生する時に参照する。
		| T_LAB estr T_RESOURCE T_LOOP            eols		{ if(!($$ = TexHdr_new(  $1,   $2, 1, 1))) { YYERROR; } }						//リソースフラグはP/ECE用のテクスチャ定義ヘッダだけに影響する。汎用の列挙定義,及び,レジストリスクリプトでは無視される。	//ループフラグはレジストリスクリプトだけに出力する。Windowsでムービーグラフィックを再生する時に参照する。	//┬一応resourceとloopを同時に指定出来るようにしました。実際にはresourceはP/ECE用,loopはWindows用なので同時に指定する事は無いと思います。
		| T_LAB estr            T_LOOP T_RESOURCE eols		{ if(!($$ = TexHdr_new(  $1,   $2, 1, 1))) { YYERROR; } }						//リソースフラグはP/ECE用のテクスチャ定義ヘッダだけに影響する。汎用の列挙定義,及び,レジストリスクリプトでは無視される。	//ループフラグはレジストリスクリプトだけに出力する。Windowsでムービーグラフィックを再生する時に参照する。	//┘
		|       estr                              eols		{ if(!($$ = TexHdr_new(NULL,   $1, 0, 0))) { YYERROR; } }	//ファイル名からラベルを自動生成する。
		|       estr T_RESOURCE                   eols		{ if(!($$ = TexHdr_new(NULL,   $1, 1, 0))) { YYERROR; } }	//ファイル名からラベルを自動生成する。	//リソースフラグはP/ECE用のテクスチャ定義ヘッダだけに影響する。汎用の列挙定義,及び,レジストリスクリプトでは無視される。
		|       estr            T_LOOP            eols		{ if(!($$ = TexHdr_new(NULL,   $1, 0, 1))) { YYERROR; } }	//ファイル名からラベルを自動生成する。																//ループフラグはレジストリスクリプトだけに出力する。Windowsでムービーグラフィックを再生する時に参照する。
		|       estr T_RESOURCE T_LOOP            eols		{ if(!($$ = TexHdr_new(NULL,   $1, 1, 1))) { YYERROR; } }	//ファイル名からラベルを自動生成する。	//リソースフラグはP/ECE用のテクスチャ定義ヘッダだけに影響する。汎用の列挙定義,及び,レジストリスクリプトでは無視される。	//ループフラグはレジストリスクリプトだけに出力する。Windowsでムービーグラフィックを再生する時に参照する。	//┬一応resourceとloopを同時に指定出来るようにしました。実際にはresourceはP/ECE用,loopはWindows用なので同時に指定する事は無いと思います。
		|       estr            T_LOOP T_RESOURCE eols		{ if(!($$ = TexHdr_new(NULL,   $1, 1, 1))) { YYERROR; } }	//ファイル名からラベルを自動生成する。	//リソースフラグはP/ECE用のテクスチャ定義ヘッダだけに影響する。汎用の列挙定義,及び,レジストリスクリプトでは無視される。	//ループフラグはレジストリスクリプトだけに出力する。Windowsでムービーグラフィックを再生する時に参照する。	//┘
		;
texHdr
		: texRow						/* use default action */
		| T_LAB                eols				{ if(!($$ = TexHdr_new(  $1, NULL, 0, 0))) { YYERROR; } }	//ファイル名を別で設定する。
		;
texBody
		: T_GRID int_arg             eols			{ if(!($$ = TexBody_new($2, $2))) { YYERROR; } }	//正方形グリッドの場合
		| T_GRID int_arg ',' int_arg eols			{ if(!($$ = TexBody_new($2, $4))) { YYERROR; } }	//長方形グリッドの場合
		| texBody spr						{ if(!($$ = TexBody_addSpr($1, $2))) { YYERROR; } }
		;
		/*--------------------------------------------*/
spr
		: T_LAB x ',' y                                   eols	{ if(!($$ = Spr_new( $1, $2, $4, grid_w, grid_h,   0,   0, "0"))) { YYERROR; } }	//スプライト名,X座標,Y座標
		| T_LAB x ',' y ',' x ',' y                       eols	{ if(!($$ = Spr_new( $1, $2, $4,     $6,     $8,   0,   0, "0"))) { YYERROR; } }	//スプライト名,X座標,Y座標,幅,高さ
		| T_LAB x ',' y ','   ','   ',' x ',' y           eols	{ if(!($$ = Spr_new( $1, $2, $4, grid_w, grid_h,  $8, $10, "0"))) { YYERROR; } }	//スプライト名,X座標,Y座標,  ,    ,X中心 ,Y中心
		| T_LAB x ',' y ',' x ',' y ',' x ',' y           eols	{ if(!($$ = Spr_new( $1, $2, $4,     $6,     $8, $10, $12, "0"))) { YYERROR; } }	//スプライト名,X座標,Y座標,幅,高さ,X中心 ,Y中心
		| T_LAB x ',' y ','   ','   ','   ','   ',' param eols	{ if(!($$ = Spr_new( $1, $2, $4, grid_w, grid_h,   0,   0, $10))) { YYERROR; } }	//スプライト名,X座標,Y座標,  ,    ,      ,      ,パラメータ
		| T_LAB x ',' y ',' x ',' y ','   ','   ',' param eols	{ if(!($$ = Spr_new( $1, $2, $4,     $6,     $8,   0,   0, $12))) { YYERROR; } }	//スプライト名,X座標,Y座標,幅,高さ,      ,      ,パラメータ
		| T_LAB x ',' y ','   ','   ',' x ',' y ',' param eols	{ if(!($$ = Spr_new( $1, $2, $4, grid_w, grid_h,  $8, $10, $12))) { YYERROR; } }	//スプライト名,X座標,Y座標,  ,    ,X中心 ,Y中心 ,パラメータ
		| T_LAB x ',' y ',' x ',' y ',' x ',' y ',' param eols	{ if(!($$ = Spr_new( $1, $2, $4,     $6,     $8, $10, $12, $14))) { YYERROR; } }	//スプライト名,X座標,Y座標,幅,高さ,X中心 ,Y中心 ,パラメータ
		//
	//不要	: T_LAB x ',' y                                   eols	{ if(!($$ = Spr_newP($1, $2, $4, grid_w, grid_h,   0,   0, "0"))) { YYERROR; } }	//スプライト名,X座標,Y座標
	//不要	| T_LAB x ',' y ',' x ',' y                       eols	{ if(!($$ = Spr_newP($1, $2, $4,     $6,     $8,   0,   0, "0"))) { YYERROR; } }	//スプライト名,X座標,Y座標,幅,高さ
		| T_LAB x ',' y ','   ','   ',' p ',' p           eols	{ if(!($$ = Spr_newP($1, $2, $4, grid_w, grid_h,  $8, $10, "0"))) { YYERROR; } }	//スプライト名,X座標,Y座標,  ,    ,X中心%,Y中心%
		| T_LAB x ',' y ',' x ',' y ',' p ',' p           eols	{ if(!($$ = Spr_newP($1, $2, $4,     $6,     $8, $10, $12, "0"))) { YYERROR; } }	//スプライト名,X座標,Y座標,幅,高さ,X中心%,Y中心%
	//不要	| T_LAB x ',' y ','   ','   ','   ','   ',' param eols	{ if(!($$ = Spr_newP($1, $2, $4, grid_w, grid_h,   0,   0, $10))) { YYERROR; } }	//スプライト名,X座標,Y座標,  ,    ,      ,      ,パラメータ
	//不要	| T_LAB x ',' y ',' x ',' y ','   ','   ',' param eols	{ if(!($$ = Spr_newP($1, $2, $4,     $6,     $8,   0,   0, $12))) { YYERROR; } }	//スプライト名,X座標,Y座標,幅,高さ,      ,      ,パラメータ
		| T_LAB x ',' y ','   ','   ',' p ',' p ',' param eols	{ if(!($$ = Spr_newP($1, $2, $4, grid_w, grid_h,  $8, $10, $12))) { YYERROR; } }	//スプライト名,X座標,Y座標,  ,    ,X中心%,Y中心%,パラメータ
		| T_LAB x ',' y ',' x ',' y ',' p ',' p ',' param eols	{ if(!($$ = Spr_newP($1, $2, $4,     $6,     $8, $10, $12, $14))) { YYERROR; } }	//スプライト名,X座標,Y座標,幅,高さ,X中心%,Y中心%,パラメータ
		;

%%
