%{
//{{定型コード:lex.yy.l(定義部,%{〜%}内)=======================================
#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
#include "y.tab.h"
//入力バッファサイズを定義します。
//デフォルトでは16384と定義されており、P/ECEには大きすぎます。
//P/ECEに適切な、小さなサイズ(256)に、再定義しました。
//入力バッファサイズが不足した場合は、自動的に拡張されるので、問題ありません。
//一つのトークンの大きさが、入力バッファサイズを超えたときに、拡張されるようです。
#undef  YY_BUF_SIZE
#define YY_BUF_SIZE 256
//入力ファイルの行を数えるための変数を定義します。
//「%option yylineno」を指定して、行を数えるコードを自動生成することもできますが、
//コンパイラが警告を出したりして煩わしくなるので、自分で数えることにしました。
int yylineno;
//スキャナの入力ファイルを初期化します。
//yyparse()を実行する都度、その直前に、本関数を呼び出してください。
void yylex_init(FILE* input_file) {
  if(!input_file) { DIE(); }	//入力ファイルが指定されていなければエラー停止する。
  BEGIN INITIAL;		//スタート状態を初期化する。
  yylineno = 1;			//入力ファイルの行を初期化する。
  yyrestart(input_file); }	//スキャナの実行を再開するようFlexに通知する。
//入力方法を変更するマクロを定義します。
//lex.yy.c内で、デフォルトのYY_INPUT()よりも先に展開されるので、#undefは不要です。
//自作CLiPライブラリの標準入出力は、CRLFをLFに変換しないので、明示的に変換します。
//'popen'キーワードによる入力バッファ切り替え中ならば、入力ファイルの行を増やさない事にしました。	⇒//{{2016/09/24変更:エラーメッセージに現在のファイル名も表示する変更に伴いロケーションスタックを追加したので、'popen'キーワードによる入力バッファ切り替え中も入力ファイルの行を増やせるようになった。}}
#define YY_INPUT(buf,result,max_size) {					\
  int i = 0; while(i < (max_size)) {					\
    int c = getc(yyin);							\
    if(c == EOF)  { break; }						\
    if(c == '\r') { continue; }						\
    (buf)[i++] = c;							\
    if(c == '\n') { /*if(!popen_stack_ptr)*/ { yylineno++; } break; }	\
  } (result) = i; }
//'popen'キーワードで入力バッファを切り替えた時に、切り替え前の入力バッファを記憶しておくスタックです。
//「flex version 2.5.4」にはyypush_buffer_state()とyypop_buffer_state()が無いので、自前で処理しました。
//参考資料「11 Multiple Input Buffers」(http://flex.sourceforge.net/manual/Multiple-Input-Buffers.html)
static YY_BUFFER_STATE popen_stack[16/*調整可*/];
static int popen_stack_ptr;
//P/ECEでは'popen'キーワードによる入力バッファ切り替え処理をダミーとします。
#ifdef  PIECE
#define _popen(command,type) (NULL)
#define _pclose(stream) (-1)
#endif//PIECE
//}}定型コード:lex.yy.l(定義部,%{〜%}内)=======================================
%}
/*{{定型コード:lex.yy.l(定義部,%{〜%}外)=====================================*/
/* Suppress the appearance of unneeded routines in the generated scanner. */
%option noinput
%option nounput
/* Make the scanner not call yywrap() upon an end-of-file, but simply assume that there are no more files to scan. */
%option noyywrap
/*}}定型コード:lex.yy.l(定義部,%{〜%}外)=====================================*/

%x POPEN
%x COMMENT

%%

<INITIAL>{
<<EOF>>				{ if(!popen_stack_ptr) { yyterminate(); }
				  pop_location();/*_pclose()が失敗する原因はpopenで開こうとしたファイルが無い場合がほとんどなので元ファイル側のエラーとするのが適切だ。従って_pclose()する前にロケーションを復元しておく事にした。*/
				  { int retval = _pclose(yyin); if(retval) { yyerror("pcloseが失敗しました。(%d)", retval); yynerrs++; }
				    yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(popen_stack[--popen_stack_ptr]); } }
popen[[:blank:]]+\"		{ BEGIN POPEN; }
"#"				{ BEGIN COMMENT; }

"("				|
")"				|
"+"				|
"-"				|
"*"				|
"/"				|
"%"				|
"&"				|
"^"				|
"|"				|
"~"				{ return yytext[0]; }
"<<"				{ return T_SHL; }
">>"				{ return T_SHR; }

"def"				{ return T_DEF; }
"end"				{ return T_END; }
"wait"				{ return T_WAIT; }
"stop"				{ return T_STOP; }
"play"				{ return T_PLAY; }
"vol"				{ return T_VOL; }
"pan"				{ return T_PAN; }
","				{ return yytext[0]; }

0[0-7]*				|									/*  8進数(0も含む) */
[1-9][[:digit:]]*		|									/* 10進数(0は除く) */
0(x|X)[[:xdigit:]]+		{ yylval.v_num = strtoul( yytext,          NULL, 0); return T_NUM; }	/* 16進数 */
0(b|B)[0-1]+			{ yylval.v_num = strtoul(&yytext[2/*0b*/], NULL, 2); return T_NUM; }	/*  2進数 */
[_[:alpha:]][_[:alnum:]]*	{ yylval.v_lab = strdup(yytext); return T_LAB; }	/* 原則としてラベルは数字で始まってはいけない。C言語シンボルと同じ規則。<例>「Abc123」,「_123」 */
\`[_[:alnum:]]+			{ yylval.v_lab = strdup(yytext + 1); return T_LAB; }	/* ただし先行して「`」を書けば数字で始まっても良い。「`」はラベルに含めない。<例>「`Abc123」(Abc123と書くのと同じ),「`123」(123というラベルになる) */

(0|[1-9][[:digit:]]*)?\.[[:digit:]]+([eE][+-]?(0|[1-9][[:digit:]]*))?	|
(0|[1-9][[:digit:]]*)([eE][+-]?(0|[1-9][[:digit:]]*))			{ yylval.v_dbl = atof(yytext); return T_DBL; }
\([[:blank:]]*int[[:blank:]]*\)						{ return T_CAST_INT; }
\([[:blank:]]*double[[:blank:]]*\)					{ return T_CAST_DBL; }

[[:blank:]]+			{ /** no job **/ }
";"				|
\n				{ return T_EOL; }
.				{ yyerror("scan error"); return yytext[0]; }
}

<COMMENT>{
\n				{ BEGIN INITIAL; return T_EOL; }
.				{ /** no job **/ }
}

<POPEN>{
<<EOF>>				{ BEGIN INITIAL; yyerror("EOF in popen."); yynerrs++; }
\n				{ BEGIN INITIAL; yyerror("Unterminated popen."); yynerrs++; }
\"				{ BEGIN INITIAL; yytext[yyleng - 1] = '\0';
				  { FILE* fp = _popen(yytext, "r"); if(!fp) { yyerror("popenが失敗しました。(%s)", yytext); yynerrs++; YY_BREAK; }
				    if(popen_stack_ptr >= ARRAY_SIZE(popen_stack)) { yyerror("popenの階層が深過ぎます。(%s)", yytext); yynerrs++; YY_BREAK; }
				    push_location(yytext);/*yy_switch_to_buffer()を呼ぶとyytextが破壊されるようなのでyy_switch_to_buffer()よりも先に行う必要が有る。*/
				    popen_stack[popen_stack_ptr++] = YY_CURRENT_BUFFER; yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); } }
.				{ yymore(); }
}

%%
