%{
/*{{定型コード:y.tab.y(宣言部,%{〜%}内)======================================*/
#ifdef  PIECE
#include "app.h"
#else //PIECE
#include "winapp.h"
#endif//PIECE
/* パーサースタックの初期値を定義します。
 * sizeof(YYSTYPE)*YYINITDEPTH) がスタック上に確保されます。
 * デフォルトでは200と定義されており、P/ECEには大きすぎます。
 * P/ECEに適切な、小さなサイズ(16)に、再定義しました。
 * パーサースタックが不足した場合は、自動的に拡張されるので、問題ありません。
 */
#define YYINITDEPTH 16
/* エラー報告関数を定義します。 */
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(宣言部,%{〜%}内)======================================*/

int f_rs;	/* 最後のRSを出力しないために、RSをすぐに出力せず、予約しておくフラグ */

%}

%token T_UNIT	/* ユニット */
%token T_US	/* ユニットセパレータ */
%token T_RS	/* レコードセパレータ */
%token T_EOF	/* 引用符付きの文字列の途中で、ファイル終端に達したことを示すトークン */

%%

/* 本来は、構文解析しながらツリーを組み立てて最後に出力すべきなのだが、簡略化して、字句を読み込む都度出力するようにした。
 * 入力ファイルと出力ファイルの字句の順番が同じだから、これでも大丈夫。
 */

/*--- Grammer ---*/
csv
	: records
	;
records
	: record
	| records rs record
	;
record
	: units
	;
units
	: unit
	| units us unit
	;

/*--- Output ---*/
unit
	: /* empty */	/* 空フィールドや、空レコードを許容するために、この定義が必要である。 */
	| T_UNIT	{ if(f_rs) { f_rs = 0; printf("\x1E"); }	/* RSが予約されていたら、RSを出力する。 */	/* 1E = ASCII制御文字 RS (Record Separator) */
			  printf("%s", $1); }				/* 文字列を出力する。 */
	;
us
	: T_US		{ if(f_rs) { f_rs = 0; printf("\x1E"); }	/* RSが予約されていたら、RSを出力する。 */	/* 1E = ASCII制御文字 RS (Record Separator) */
			  printf("\x1F"); }				/* USを出力する。 */				/* 1F = ASCII制御文字 US (Unit Separator) */
	;
rs
	: T_RS		{ if(f_rs) { f_rs = 0; printf("\x1E"); }	/* RSが予約されていたら、RSを出力する。 */	/* 1E = ASCII制御文字 RS (Record Separator) */
			  f_rs = 1; }					/* RSを予約する。 */
	;

%%
