%{
/*{{定型コード: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_lab;
	//
	ST_LabelRow*	v_labelRow;
	ST_PlayRows*	v_playRows;
	ST_SeqTbl*	v_seqTbl;
	ST_DataRow*	v_dataRow;
	ST_DataRows*	v_dataRows;
	ST_DatTbl*	v_datTbl;
}

%token			T_PLAY
%token			T_REPEAT
%token			T_END
%token			T_STAY
%token			T_LOOP
%token			T_DATA
%token	<v_num>		T_NUM
%token	<v_dbl>		T_DBL
%token	<v_lab>		T_LAB
%token			T_EOL

%type	<v_num>		int_arg
%type	<v_num>		expr
%type	<v_dbl>		edbl
%type	<v_labelRow>	labelRow
%type	<v_lab>		labDef
%type	<v_lab>		playRow
%type	<v_lab>		labRef
%type	<v_playRows>	playRows
%type	<v_seqTbl>	seqTbl
%type	<v_num>		dimmer
%type	<v_dataRow>	dataRow data
%type	<v_dataRows>	dataRows
%type	<v_datTbl>	datTbl

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

%%

all
		: /* empty */
		| all T_EOL			/* no action */
		| all seqTbl			{ add_seqTbl($2); yyerrok; }	//error記号の位置について『http://www.pwv.co.jp/~take/TakeWiki/index.php?Cコンパイラ設計(yacc・lexの応用)/第4章　エラー・リカバリ#dbd8d417』の【optional sequence】を参考にした。
		| all datTbl			{ add_datTbl($2); yyerrok; }	//error記号の位置について『http://www.pwv.co.jp/~take/TakeWiki/index.php?Cコンパイラ設計(yacc・lexの応用)/第4章　エラー・リカバリ#dbd8d417』の【optional sequence】を参考にした。
		| all error							//全てのシンタクスエラーを報告するために継続する。
		;
seqTbl
		: labelRow playRows                 T_END T_EOL		{ $$ = SeqTbl_new($1, $2, calloc(1, sizeof(ST_PlayRows))); }
		| labelRow playRows repeat playRows T_END T_EOL		{ $$ = SeqTbl_new($1, $2, $4); }
		| labelRow          repeat playRows T_END T_EOL		{ $$ = SeqTbl_new($1, calloc(1, sizeof(ST_PlayRows)), $3); }
		;
datTbl
		: labelRow dataRows T_END          T_EOL		{ $$ = DatTbl_new($1, $2, INT_MAX); }	//ループ無し。
		| labelRow dataRows T_STAY         T_EOL		{ $$ = DatTbl_new($1, $2, -1); }	//(最終フレーム+1)-1からループ。つまり、最終フレームを維持。
		| labelRow dataRows T_LOOP         T_EOL		{ $$ = DatTbl_new($1, $2,  0); }	//先頭フレーム+0からループ。つまり、全体ループ。
		| labelRow dataRows T_LOOP int_arg T_EOL		{ $$ = DatTbl_new($1, $2, $4); }	//指定されたフレームからループ。(-全体フレーム数)〜0〜(全体フレーム数-1)の範囲で指定可能。
		;
labelRow
		: labDef   T_EOL		{ $$ = LabelRow_new($1); }
		| labelRow T_EOL		/* use default action */
		;
labDef
		: T_LAB				{ $$ = LabDef_new($1); }
		;
playRows
		:          playRow		{ $$ = PlayRows_add(NULL, $1); }
		| playRows playRow		{ $$ = PlayRows_add(  $1, $2); }
		;
playRow
		: T_PLAY labRef T_EOL		{ $$ = $2; }
		| playRow       T_EOL		/* use default action */
		;
labRef
		: T_LAB				{ $$ = LabRef_new($1); }
		;
repeat
		: T_REPEAT T_EOL		/* no action */
		| repeat   T_EOL		/* no action */
		;
dataRows
		:          dataRow		{ if(!($$ = DataRows_add(NULL, $1))) { YYERROR; } }	//'data'命令の要素数(=LEDチャネル数)が同じでなければ、シンタクスエラーを生成して、このdataRowを受け入れない。
		| dataRows dataRow		{ if(!($$ = DataRows_add(  $1, $2))) { YYERROR; } }	//'data'命令の要素数(=LEDチャネル数)が同じでなければ、シンタクスエラーを生成して、このdataRowを受け入れない。
		;
dataRow
		: T_DATA data T_EOL		{ $$ = $2; }
		| dataRow     T_EOL		/* use default action */
		;
data
		:          dimmer		{ $$ = DataRow_add(NULL, $1); }
		| data ',' dimmer		{ $$ = DataRow_add(  $1, $3); }
		;
dimmer
		: int_arg			{ $$ = Dimmer_new($1); }
		;
int_arg
		: expr				/* use default action */
		| edbl				{ $$ =  cast_dbl_to_int($1); }
		;
expr
		: T_NUM
		| '(' 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; }
		;

%%
