%{
/*{{定型コード: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_Ncs*		v_ncs;
	ST_RelExpr	v_relExpr;
	ST_ExprList*	v_exprList;
	ST_NodeRow*	v_nodeRow;
	ST_NodeRows*	v_nodeRows;
}

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

%type	<v_num>		int_arg
%type	<v_num>		expr
%type	<v_dbl>		edbl
%type	<v_relExpr>	relExpr
%type	<v_exprList>	exprList
%type	<v_ncs>		ncs
%type	<v_str>		labRow
%type	<v_nodeRow>	nodeRow
%type	<v_nodeRows>	nodeRows

%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 ncs						{ addNcs($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; }
			;
			/*----------------------------------------------------*/
relExpr
			:       int_arg						{ $$ = RelExpr_New($1, 0); }
			| T_REL int_arg						{ $$ = RelExpr_New($2, 1); }
			;
exprList
			:              relExpr					{ if(!($$ = ExprList_New(    $1))) { YYERROR; } }	//現在の所エラーが発生する事は無い。
			| exprList ',' relExpr					{ if(!($$ = ExprList_Add($1, $3))) { YYERROR; } }	//現在の所エラーが発生する事は無い。
			;
			/*----------------------------------------------------*/
ncs
			: labRow nodeRows end					{ if(!($$ = Ncs_New($1, $2))) { YYERROR; } }		//時刻が昇順になっていなければエラーとする。時刻が範囲外ならばエラーとする。座標が範囲外ならばエラーとする。
			;
labRow
			: T_LAB eols						/* use default action */
			;
nodeRows
			:          nodeRow					{ if(!($$ = NodeRows_Add(NULL, $1))) { YYERROR; } }	//現在の所エラーが発生する事は無い。
			| nodeRows nodeRow					{ if(!($$ = NodeRows_Add(  $1, $2))) { YYERROR; } }	//軸の数が異なるnodeRowを追加しようとしたらエラーとする。ノード数が多過ぎたらエラーとする。
			;
nodeRow
			: relExpr ',' exprList eols				{ if(!($$ = NodeRow_New($1, $3))) { YYERROR; } }	//現在の所エラーが発生する事は無い。
			;

%%
