%{
/*{{定型コード: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_Mesh*			v_mesh;
	ST_MeshHdr*			v_meshHdr;
	ST_MeshBody*			v_meshBody;

	ST_Vectors*			v_vectors;
	ST_VectorsHdr*			v_vectorsHdr;
	ST_VectorsBody*			v_vectorsBody;
	ST_VectorRow*			v_vectorRow;
	ST_Vector*			v_vector;
	ST_VectorRef*			v_vectorRef;

	ST_Tcoords*			v_tcoords;
	ST_TcoordsHdr*			v_tcoordsHdr;
	ST_TcoordsBody*			v_tcoordsBody;
	ST_TcoordRow*			v_tcoordRow;
	ST_Tcoord*			v_tcoord;
	ST_TcoordRef*			v_tcoordRef;

	ST_Face*			v_face;
	ST_FaceHdr*			v_faceHdr;
	ST_FaceBody*			v_faceBody;
	ST_FaceVertexRow*		v_faceVertexRow;
	ST_FaceVertex*			v_faceVertex;
}

%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_VECTORS
%token					T_TCOORDS
%token					T_FACE

%type	<v_num>				int_arg				//整数引数
%type	<v_num>				int_arg_upl_umi			//├先頭に±が有る
%type	<v_num>				int_arg_no_upl_umi		//└先頭に±が無い
%type	<v_dbl>				dbl_arg				//実数引数
%type	<v_dbl>				dbl_arg_upl_umi			//├先頭に±が有る
%type	<v_dbl>				dbl_arg_no_upl_umi		//└先頭に±が無い
%type	<v_num>				expr				//整数式
%type	<v_num>				expr_upl_umi			//├先頭に±が有る
%type	<v_num>				expr_no_upl_umi			//└先頭に±が無い
%type	<v_dbl>				edbl				//実数式
%type	<v_dbl>				edbl_upl_umi			//├先頭に±が有る
%type	<v_dbl>				edbl_no_upl_umi			//└先頭に±が無い
%type	<v_str>				estr

%type	<v_mesh>			mesh
%type	<v_meshHdr>			meshHdr
%type	<v_meshBody>			meshBody

%type	<v_vectors>			vectors
%type	<v_vectorsHdr>			vectorsHdr
%type	<v_vectorsBody>			vectorsBody
%type	<v_vectorRow>			vectorRow
%type	<v_vector>			vector
%type	<v_vectorRef>			vectorRef

%type	<v_tcoords>			tcoords
%type	<v_tcoordsHdr>			tcoordsHdr
%type	<v_tcoordsBody>			tcoordsBody
%type	<v_tcoordRow>			tcoordRow
%type	<v_tcoord>			tcoord
%type	<v_tcoordRef>			tcoordRef

%type	<v_face>			face
%type	<v_faceHdr>			faceHdr
%type	<v_faceBody>			faceBody
%type	<v_faceVertexRow>		faceVertexRow
%type	<v_faceVertex>			faceVertex

%nonassoc				T_PROMOTE
%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 mesh							{ addMesh($2); yyerrok; }	//error記号の位置について『http://www.pwv.co.jp/~take/TakeWiki/index.php?Cコンパイラ設計(yacc・lexの応用)/第4章　エラー・リカバリ#dbd8d417』の【optional sequence】を参考にした。
					| all error											//全てのシンタクスエラーを報告するために継続する。
				//{{この範囲は「y.tab.y contains ? useless nonterminals and ? useless rules」警告回避用です。実際に使われる事は有りません。
					| '#' dbl_arg_upl_umi						{ DIE(); }
					| '#' dbl_arg_no_upl_umi					{ DIE(); }
				//}}この範囲は「y.tab.y contains ? useless nonterminals and ? useless rules」警告回避用です。実際に使われる事は有りません。
					;
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); }
					;
int_arg_upl_umi
					: expr_upl_umi							/* use default action */
					| edbl_upl_umi							{ $$ =  cast_dbl_to_int($1); }
					;
int_arg_no_upl_umi
					: expr_no_upl_umi						/* use default action */
					| edbl_no_upl_umi						{ $$ =  cast_dbl_to_int($1); }
					;
dbl_arg
					: expr								{ $$ = $1; }
					| edbl								/* use default action */
					;
dbl_arg_upl_umi
					: expr_upl_umi							{ $$ = $1; }
					| edbl_upl_umi							/* use default action */
					;
dbl_arg_no_upl_umi
					: expr_no_upl_umi						{ $$ = $1; }
					| edbl_no_upl_umi						/* use default action */
					;
expr
					: expr_upl_umi    %prec T_PROMOTE				/* use default action */
					| expr_no_upl_umi %prec T_PROMOTE				/* use default action */
					;
expr_upl_umi
					: '+' expr %prec T_UPL						{ $$ =  $2; }
					| '-' expr %prec T_UMI						{ $$ = -$2; }
					| expr_upl_umi    '+' expr					{ $$ = $1 + $3; }
					| expr_upl_umi    '-' expr					{ $$ = $1 - $3; }
					| expr_upl_umi    '*' expr					{ $$ = $1 * $3; }
					| expr_upl_umi    '/' expr					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 / $3; }
					| expr_upl_umi    '%' expr					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 % $3; }
					| expr_upl_umi    '&' expr					{ $$ = $1 & $3; }
					| expr_upl_umi    '^' expr					{ $$ = $1 ^ $3; }
					| expr_upl_umi    '|' expr					{ $$ = $1 | $3; }
					| expr_upl_umi    T_SHL expr					{ if((unsigned)$3 >= 32) { yyerror("shift count >= 32"); yynerrs++; YYERROR; } $$ = $1 << $3; }
					| expr_upl_umi    T_SHR expr					{ if((unsigned)$3 >= 32) { yyerror("shift count >= 32"); yynerrs++; YYERROR; } $$ = $1 >> $3; }
					;
expr_no_upl_umi
					: T_NUM								/* use default action */
					| '(' expr ')'							{ $$ =  $2; }
					| T_CAST_INT expr						{ $$ =  $2; }
					| T_CAST_INT edbl						{ $$ =  $2; }
					| '~' expr							{ $$ = ~$2; }
					| expr_no_upl_umi '+' expr					{ $$ = $1 + $3; }
					| expr_no_upl_umi '-' expr					{ $$ = $1 - $3; }
					| expr_no_upl_umi '*' expr					{ $$ = $1 * $3; }
					| expr_no_upl_umi '/' expr					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 / $3; }
					| expr_no_upl_umi '%' expr					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 % $3; }
					| expr_no_upl_umi '&' expr					{ $$ = $1 & $3; }
					| expr_no_upl_umi '^' expr					{ $$ = $1 ^ $3; }
					| expr_no_upl_umi '|' expr					{ $$ = $1 | $3; }
					| expr_no_upl_umi T_SHL expr					{ if((unsigned)$3 >= 32) { yyerror("shift count >= 32"); yynerrs++; YYERROR; } $$ = $1 << $3; }
					| expr_no_upl_umi T_SHR expr					{ if((unsigned)$3 >= 32) { yyerror("shift count >= 32"); yynerrs++; YYERROR; } $$ = $1 >> $3; }
					;
edbl
					: edbl_upl_umi    %prec T_PROMOTE				/* use default action */
					| edbl_no_upl_umi %prec T_PROMOTE				/* use default action */
					;
edbl_upl_umi
					: '+' edbl %prec T_UPL						{ $$ =  $2; }
					| '-' edbl %prec T_UMI						{ $$ = -$2; }
					| edbl_upl_umi    '+' edbl					{ $$ = $1 + $3; }
					| edbl_upl_umi    '+' expr					{ $$ = $1 + $3; }
					| expr_upl_umi    '+' edbl					{ $$ = $1 + $3; }
					| edbl_upl_umi    '-' edbl					{ $$ = $1 - $3; }
					| edbl_upl_umi    '-' expr					{ $$ = $1 - $3; }
					| expr_upl_umi    '-' edbl					{ $$ = $1 - $3; }
					| edbl_upl_umi    '*' edbl					{ $$ = $1 * $3; }
					| edbl_upl_umi    '*' expr					{ $$ = $1 * $3; }
					| expr_upl_umi    '*' edbl					{ $$ = $1 * $3; }
					| edbl_upl_umi    '/' edbl					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 / $3; }
					| edbl_upl_umi    '/' expr					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 / $3; }
					| expr_upl_umi    '/' edbl					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 / $3; }
					;
edbl_no_upl_umi
					: T_DBL								/* use default action */
					| '(' edbl ')'							{ $$ =  $2; }
					| T_CAST_DBL expr						{ $$ =  $2; }
					| T_CAST_DBL edbl						{ $$ =  $2; }
					| edbl_no_upl_umi '+' edbl					{ $$ = $1 + $3; }
					| edbl_no_upl_umi '+' expr					{ $$ = $1 + $3; }
					| expr_no_upl_umi '+' edbl					{ $$ = $1 + $3; }
					| edbl_no_upl_umi '-' edbl					{ $$ = $1 - $3; }
					| edbl_no_upl_umi '-' expr					{ $$ = $1 - $3; }
					| expr_no_upl_umi '-' edbl					{ $$ = $1 - $3; }
					| edbl_no_upl_umi '*' edbl					{ $$ = $1 * $3; }
					| edbl_no_upl_umi '*' expr					{ $$ = $1 * $3; }
					| expr_no_upl_umi '*' edbl					{ $$ = $1 * $3; }
					| edbl_no_upl_umi '/' edbl					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 / $3; }
					| edbl_no_upl_umi '/' expr					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 / $3; }
					| expr_no_upl_umi '/' edbl					{ if(!$3) { yyerror("division or modulo by zero"); yynerrs++; YYERROR; } $$ = $1 / $3; }
					;
estr
					: T_STR
					| '(' estr ')'							{ $$ = $2; }
					| estr '+' estr							{ $$ = strconcat($1, $3, NULL); }
					;
					/*------------------------------------------------------------*/
mesh
					: meshHdr meshBody end						{ if(!($$ = Mesh_New($1, $2))) { YYERROR; } }
					;
meshHdr
					: T_LAB estr  eols						{ if(!($$ = MeshHdr_New($1,   $2))) { YYERROR; } }
					| T_LAB T_LAB eols						{ if(!($$ = MeshHdr_New($1,   $2))) { YYERROR; } }	//省略記法	pTextureNameという引数名だが、実際には単なる文字列である。当ツールは内容に関知しないから、本来は"〜"で囲むのが適切である。しかし実際にはTexNo_〜の"〜"を部分を指定する事が多いと思うので、"〜"で囲む手間を省けるようにラベル形式でも指定出来るようにした。空白や記号を含む文字列やファイル名を指定する場合は、省略記法を使わずにこれまで通り"〜"で囲む必要が有る。
					| T_LAB       eols						{ if(!($$ = MeshHdr_New($1, NULL))) { YYERROR; } }
					;
meshBody
					: /* empty */							{ if(!($$ = MeshBody_New())) { YYERROR; } }
					| meshBody vectors						{ if(!($$ = MeshBody_AddVectors($1, $2))) { YYERROR; } }
					| meshBody tcoords						{ if(!($$ = MeshBody_AddTcoords($1, $2))) { YYERROR; } }
					| meshBody face							{ if(!($$ = MeshBody_AddFace(   $1, $2))) { YYERROR; } }
					;
					/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
vectors
					: vectorsHdr vectorsBody end					{ if(!($$ = Vectors_New($1, $2))) { YYERROR; } }
					;
vectorsHdr
					: T_VECTORS eols						{ if(!($$ = VectorsHdr_New())) { YYERROR; } }
					;
vectorsBody
					: /* empty */							{ if(!($$ = VectorsBody_New())) { YYERROR; } }
					| vectorsBody vectorRow						{ if(!($$ = VectorsBody_AddVectorRow($1, $2))) { YYERROR; } }
					;
vectorRow
					: vector T_LAB eols						{ if(!($$ = VectorRow_New($1,   $2))) { YYERROR; } }
					| vector       eols						{ if(!($$ = VectorRow_New($1, NULL))) { YYERROR; } }
					;
vector
					: dbl_arg ',' dbl_arg ',' dbl_arg				{ if(!($$ = Vector_New($1, $3, $5))) { YYERROR; } }
					;
vectorRef
					: vector							{ if(!($$ = VectorRef_NewVector(      $1    ))) { YYERROR; } }
					|       int_arg							{ if(!($$ = VectorRef_NewIndex(       $1    ))) { YYERROR; } }
					| T_LAB								{ if(!($$ = VectorRef_NewLabelOffset( $1,  0))) { YYERROR; } }
					| T_LAB int_arg_upl_umi						{ if(!($$ = VectorRef_NewLabelOffset( $1, $2))) { YYERROR; } }
					;
					/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
tcoords
					: tcoordsHdr tcoordsBody end					{ if(!($$ = Tcoords_New($1, $2))) { YYERROR; } }
					;
tcoordsHdr
					: T_TCOORDS eols						{ if(!($$ = TcoordsHdr_New())) { YYERROR; } }
					;
tcoordsBody
					: /* empty */							{ if(!($$ = TcoordsBody_New())) { YYERROR; } }
					| tcoordsBody tcoordRow						{ if(!($$ = TcoordsBody_AddTcoordRow($1, $2))) { YYERROR; } }
					;
tcoordRow
					: tcoord T_LAB eols						{ if(!($$ = TcoordRow_New($1,   $2))) { YYERROR; } }
					| tcoord       eols						{ if(!($$ = TcoordRow_New($1, NULL))) { YYERROR; } }
					;
tcoord
					: int_arg_no_upl_umi ',' int_arg_no_upl_umi			{ if(!($$ = Tcoord_New($1, $3))) { YYERROR; } }
					;
tcoordRef
					: tcoord							{ if(!($$ = TcoordRef_NewTcoord(      $1    ))) { YYERROR; } }
					|       int_arg_no_upl_umi					{ if(!($$ = TcoordRef_NewIndex(       $1    ))) { YYERROR; } }
					| T_LAB								{ if(!($$ = TcoordRef_NewLabelOffset( $1,  0))) { YYERROR; } }
					| T_LAB int_arg_upl_umi						{ if(!($$ = TcoordRef_NewLabelOffset( $1, $2))) { YYERROR; } }
					;
					/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
face
					: faceHdr faceBody end						{ if(!($$ = Face_New($1, $2))) { YYERROR; } }
					;
faceHdr
					: T_FACE int_arg eols						{ if(!($$ = FaceHdr_New($2))) { YYERROR; } }
					| T_FACE         eols						{ if(!($$ = FaceHdr_New( 0))) { YYERROR; } }
					;
faceBody
					: /* empty */							{ if(!($$ = FaceBody_New())) { YYERROR; } }
					| faceBody faceVertexRow					{ if(!($$ = FaceBody_AddFaceVertexRow($1, $2))) { YYERROR; } }
					;
faceVertexRow
					: faceVertex eols						{ if(!($$ = FaceVertexRow_New($1))) { YYERROR; } }
					;
faceVertex
					: vectorRef tcoordRef						{ if(!($$ = FaceVertex_New($1,   $2))) { YYERROR; } }
					| vectorRef							{ if(!($$ = FaceVertex_New($1, NULL))) { YYERROR; } }
					;
					/*------------------------------------------------------------*/

%%
