%{
/*{{定型コード: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_Phr*		v_phr;
	ST_PhrSeq*	v_phrSeq;
}

%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_LOOP
%token			T_COMPLETE
%token			T_RESOURCE

%type	<v_num>		int_arg
%type	<v_num>		expr
%type	<v_dbl>		edbl
%type	<v_str>		estr
%type	<v_phr>		phrI
%type	<v_phr>		phrL
%type	<v_phr>		phrC
%type	<v_num>		resource
%type	<v_phrSeq>	phrs
%type	<v_phrSeq>	phrIs
%type	<v_phrSeq>	phrLs
%type	<v_phrSeq>	phrCs
%type	<v_phrSeq>	phrSeq

%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 phrSeq						{ 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); }
		;
		/*--------------------------------------------*/
phrSeq
		: phrs resource eols					{ if(!($$ = PhrSeq_markResource($1, $2))) { YYERROR; } }		//通常フレーズ ...
		;
resource
		: /* empty */						{ $$ = 0; }
		| T_RESOURCE						{ $$ = 1; }	//リソースフラグはP/ECE用のフレーズ定義ヘッダだけに影響する。汎用の列挙定義,及び,レジストリスクリプトでは無視される。
		;
		/*--------------------------------------------*/
phrs
		: phrIs							/* use default action */
		| phrLs							/* use default action */
		| phrCs							/* use default action */
		;
phrIs
		:           phrI					{ if(!($$ = PhrSeq_new(       $1))) { YYERROR; } }			//通常フレーズ
		| phrIs ',' phrI					{ if(!($$ = PhrSeq_addPhr($1, $3))) { YYERROR; } }			//通常フレーズ,...
		;
phrLs
		:           phrL					{ if(!($$ = PhrSeq_new(       $1))) { YYERROR; } }			//                 ループフレーズ
		| phrIs ',' phrL					{ if(!($$ = PhrSeq_addPhr($1, $3))) { YYERROR; } }			//通常フレーズ,...,ループフレーズ
		;
phrCs
		:           phrC					{ if(!($$ = PhrSeq_new(       $1))) { YYERROR; } }			//                 完全フレーズ
		| phrIs ',' phrC					{ if(!($$ = PhrSeq_addPhr($1, $3))) { YYERROR; } }			//通常フレーズ,...,完全フレーズ
		;
		/*--------------------------------------------*/
phrI
		: T_LAB estr						{ if(!($$ = Phr_new(  $1,   $2, NULL))) { YYERROR; } }			//通常フレーズ,又は,未決定
		| T_LAB     						{ if(!($$ = Phr_new(  $1, NULL, NULL))) { YYERROR; } }			//通常フレーズ,又は,未決定	ファイル名を別で設定する。
		|       estr						{ if(!($$ = Phr_new(NULL,   $1, NULL))) { YYERROR; } }			//通常フレーズ,又は,未決定	ファイル名からラベルを自動生成する。
		|       int_arg						{ if(!($$ = Phr_newPN(      $1, NULL))) { YYERROR; } }			//通常フレーズ,又は,未決定	PN指定。PNから仮のラベルと仮のファイル名を自動生成する。
		;
phrL
		: T_LAB estr    T_LOOP					{ if(!($$ = Phr_new(  $1,   $2, "$loop"))) { YYERROR; } }		//ループフレーズ
		| T_LAB         T_LOOP					{ if(!($$ = Phr_new(  $1, NULL, "$loop"))) { YYERROR; } }		//ループフレーズ		ファイル名を別で設定する。
		|       estr    T_LOOP					{ if(!($$ = Phr_new(NULL,   $1, "$loop"))) { YYERROR; } }		//ループフレーズ		ファイル名からラベルを自動生成する。
		|       int_arg T_LOOP					{ if(!($$ = Phr_newPN(      $1, "$loop"))) { YYERROR; } }		//ループフレーズ		PN指定。PNから仮のラベルと仮のファイル名を自動生成する。
		;
phrC
		: T_LAB estr    T_COMPLETE				{ if(!($$ = Phr_new(  $1,   $2, "$complete"))) { YYERROR; } }		//完全フレーズ
		| T_LAB         T_COMPLETE				{ if(!($$ = Phr_new(  $1, NULL, "$complete"))) { YYERROR; } }		//完全フレーズ			ファイル名を別で設定する。
		|       estr    T_COMPLETE				{ if(!($$ = Phr_new(NULL,   $1, "$complete"))) { YYERROR; } }		//完全フレーズ			ファイル名からラベルを自動生成する。
		|       int_arg T_COMPLETE				{ if(!($$ = Phr_newPN(      $1, "$complete"))) { YYERROR; } }		//完全フレーズ			PN指定。PNから仮のラベルと仮のファイル名を自動生成する。
		;

%%
