%{
//{{定型コード:y.tab.y(宣言部,%{〜%}内)========================================
#include "app.h"
#pragma warning(default: 4131)	//{{2016/03/01追加:clipstd.hにてC4131の警告レベルを引き上げましたが、Bison/Flexの生成コードには旧スタイルの宣言が使われているので、Bison/Flexの生成コードのみ警告レベルを元に戻しました。}}
//パーサースタックの初期値を定義します。
//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(宣言部,%{〜%}内)========================================
%}

%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を予約する。
		;

%%
