%{

#include "stdafx.h"
#include "interprete.h"
#include "token.h"
#include "symbol.h"
#include "function.h"
#include "addctrl.h"

#pragma warning(disable : 4102)
#pragma warning(disable : 4996)

static	char	*yaccReturnValue;	/* result output */
static	char	**bufs = NULL;
static	unsigned num_bufs = 0;
static	HWND	hSubDlg;

%}

%union {
	unsigned dval;
	char    *text;
	struct ARGS *args;
}

%token	EOL
%token	<dval>	NUMBER
%token  <text>	STRING NAME NAME_D
%token	'(' ')' '[' ']'
%token	IF ELSE GOTO GOSUB EXIT ABORT ARRAY WHILE RETURN RESIZE
%token	FOR F0R
%left	ANDAND OROR
%left	'=' E_ADDOP E_SUBOP E_ANDOP E_OROP E_MULOP E_DIVOP E_MODOP E_RSHIFT E_LSHIFT E_XOROP E_RSHIFT E_LSHIFT
%left	'?' ':'
%left	'>' '<' ELARGE ESMALL EEQUAL NEQUAL EEEQUAL NEEQUAL
%left	'&' '|' '^'
%left	'+' '-'
%left	'*' '/' '%'
%left	INC	DEC
%left	RSHIFT LSHIFT
%left	',' '.'
%right  '~' '!'
%right	MINUS

%type	<dval>	expr
%type	<text>	string
%type	<args>	args arg

%start	s

%%

s		:	expr EOL
			{ // <数> : 何もしない
				rtn_result("", "");
				YYACCEPT;
			}
			
		|	string EOL
			{ // <文字列$> : 何もしない
				rtn_result("", "");
				YYACCEPT;
			}

		|	IF expr ':' NAME EOL
			{ // 分岐 IF <数> <:ラベル>
				if ($2)	rtn_result(":", $4);
				else rtn_result("", "");
				YYACCEPT;
			}
		|	IF expr ':' NAME ELSE ':' NAME EOL
			{ // 分岐 IF <数> <:ラベル> ELSE <:ラベル>
				if ($2)	rtn_result(":", $4);
				else rtn_result(":", $7);
				YYACCEPT;
			}
		|	ELSE IF expr ':' NAME EOL
			{ // if {} による分岐サポート(結果は逆) ELSE IF <数> <:ラベル>
				if ($3)	rtn_result("", "");
				else rtn_result(":", $5);
				YYACCEPT;
			}

		|	WHILE expr ':' NAME EOL
			{ // while {} による繰り返しサポート(結果は逆) WHILE <数> <:ラベル>
				if ($2)	rtn_result("", "");
				else rtn_result(":", $4);
				YYACCEPT;
			}
		|	IF expr EOL
			{ // 分岐[真なら次の一行を実行] IF <数>
				if ($2)	rtn_result("", "");
				else rtn_result("nextline", "");
				YYACCEPT;
			}

		|	IF string ':' NAME EOL
			{ // 分岐 IF <文字列> <:ラベル>		; 文字列 != "" なら真
				if ($2[0]) rtn_result(":", $4);
				else rtn_result("", "");
				YYACCEPT;
			}
		|	IF string ':' NAME ELSE ':' NAME EOL
			{ // 分岐 IF <文字列> <:ラベル> ELSE <:ラベル>		; 文字列 != "" なら真
				if ($2[0]) rtn_result(":", $4);
				else rtn_result(":", $7);
				YYACCEPT;
			}
		|	ELSE IF string ':' NAME EOL
			{ // if {} による分岐サポート(結果は逆) ELSE IF <文字列> <:ラベル>		; 文字列 != "" なら真
				if ($3[0]) rtn_result("", "");
				else rtn_result(":", $5);
				YYACCEPT;
			}
		|	WHILE string ':' NAME EOL
			{ // while {} による繰り返しサポート(結果は逆) WHILE <数> <:ラベル>		; 文字列 != "" なら真
				if ($2[0]) rtn_result("", "");
				else rtn_result(":", $4);
				YYACCEPT;
			}
		|	IF string EOL
			{ // 分岐[真なら次の一行を実行] IF <数>		; 文字列 != "" なら真
				if ($2[0]) rtn_result("", "");
				else rtn_result("nextline", "");
				YYACCEPT;
			}
			
		|	FOR '(' expr ',' NAME ESMALL expr ')' ':' NAME EOL
			{ // 繰り返し（初期化）
				unsigned r;
				if (0 == setVariable($5, r = $3)) {
					if (r <= $7) rtn_result("nextline", "");
					else rtn_result(":", $10);
				}
				else rtn_result($5, ":使われている変数が多すぎます。");
				YYACCEPT;
			}
		|	FOR '(' expr ',' NAME '[' expr ']' ESMALL expr ')' ':' NAME EOL
			{ // 繰り返し（初期化）
				unsigned r;
				if (0 == setVariable_a($5, $7, r = $3)) {
					if (r <= $10) rtn_result("nextline", "");
					else            rtn_result(":", $13);
				}
				else
					rtn_result_n($5, $7, ":未宣言の配列か、要素数が大きすぎます。");
				YYACCEPT;
			}
		|	FOR '(' expr ',' NAME '<' expr ')' ':' NAME EOL
			{ // 繰り返し（初期化）
				unsigned r;
				if (0 == setVariable($5, r = $3)) {
					if (r < $7) rtn_result("nextline", "");
					else rtn_result(":", $10);
				}
				else rtn_result($5, ":使われている変数が多すぎます。");
				YYACCEPT;
			}
		|	FOR '(' expr ',' NAME '[' expr ']' '<' expr ')' ':' NAME EOL
			{ // 繰り返し（初期化）
				unsigned r;
				if (0 == setVariable_a($5, $7, r = $3)) {
					if (r < $10) rtn_result("nextline", "");
					else rtn_result(":", $13);
				}
				else rtn_result_n($5, $7, ":未宣言の配列か、要素数が大きすぎます。");
				YYACCEPT;
			}
		|	FOR '(' expr ',' NAME ELARGE expr ')' ':' NAME EOL
			{ // 繰り返し（初期化）
				unsigned r;
				if (0 == setVariable($5, r = $3)) {
					if (r >= $7) rtn_result("nextline", "");
					else rtn_result(":", $10);
				}
				else rtn_result($5, ":使われている変数が多すぎます。");
				YYACCEPT;
			}
		|	FOR '(' expr ',' NAME '[' expr ']' ELARGE expr ')' ':' NAME EOL
			{ // 繰り返し（初期化）
				unsigned r;
				if (0 == setVariable_a($5, $7, r = $3)) {
					if (r >= $10) rtn_result("nextline", "");
					else rtn_result(":", $13);
				}
				else rtn_result_n($5, $7, ":未宣言の配列か、要素数が大きすぎます。");
				YYACCEPT;
			}
		|	FOR '(' expr ',' NAME '>' expr ')' ':' NAME EOL
			{ // 繰り返し（初期化）
				unsigned r;

				if (0 == setVariable($5, r = $3)) {
					if (r > $7) rtn_result("nextline", "");
					else rtn_result(":", $10);
				}
				else rtn_result($5, ":使われている変数が多すぎます。");
				YYACCEPT;
			}
		|	FOR '(' expr ',' NAME '[' expr ']' '>' expr ')' ':' NAME EOL
			{ // 繰り返し（初期化）
				unsigned r;
				if (0 == setVariable_a($5, $7, r = $3)) {
					if (r > $10) rtn_result("nextline", "");
					else rtn_result(":", $13);
				}
				else rtn_result_n($5, $7, ":未宣言の配列か、要素数が大きすぎます。");
				YYACCEPT;
			}

		|	F0R FOR '(' expr ',' NAME ESMALL expr ')' ':' NAME EOL
			{ // 繰り返し（本体）
				unsigned r;
				if (0 == setVariable($6, r = getVariable($6)+1)) {
					if (r <= $8) rtn_result("", "");
					else rtn_result(":", $11);
				}
				else rtn_result($6, ":使われている変数が多すぎます。");
				YYACCEPT;
			}
		|	F0R FOR '(' expr ',' NAME '[' expr ']' ESMALL expr ')' ':' NAME EOL
			{ // 繰り返し（本体）
				unsigned r;
				getVariable_a($6, $8, &r);
				if (0 == setVariable_a($6, $8, ++r))  {
					if (r <= $11) rtn_result("", "");
					else rtn_result(":", $14);
				}
				else rtn_result_n($6, $8, ":未宣言の配列か、要素数が大きすぎます。");
				YYACCEPT;
			}
		|	F0R FOR '(' expr ',' NAME '<' expr ')' ':' NAME EOL
			{ // 繰り返し（本体）
				unsigned r;
				if (0 == setVariable($6, r = getVariable($6)+1)) {
					if (r < $8) rtn_result("", "");
					else rtn_result(":", $11);
				}
				else rtn_result($6, ":使われている変数が多すぎます。");
				YYACCEPT;
			}
		|	F0R FOR '(' expr ',' NAME '[' expr ']' '<' expr ')' ':' NAME EOL
			{ // 繰り返し（本体）
				unsigned r;
				getVariable_a($6, $8, &r);
				if (0 == setVariable_a($6, $8, ++r)) {
					if (r < $11) rtn_result("", "");
					else rtn_result(":", $14);
				}
				else rtn_result_n($6, $8, ":未宣言の配列か、要素数が大きすぎます。");
				YYACCEPT;
			}
		|	F0R FOR '(' expr ',' NAME ELARGE expr ')' ':' NAME EOL
			{ // 繰り返し（本体）
				unsigned r;
				if (0 == setVariable($6, r = getVariable($6)-1)) {
					if (r >= $8) rtn_result("", "");
					else rtn_result(":", $11);
				}
				else rtn_result($6, ":使われている変数が多すぎます。");
				YYACCEPT;
			}
		|	F0R FOR '(' expr ',' NAME '[' expr ']' ELARGE expr ')' ':' NAME EOL
			{ // 繰り返し（本体）
				unsigned r;
				getVariable_a($6, $8, &r);
				if (0 == setVariable_a($6, $8, --r)) {
					if (r >= $11) rtn_result("", "");
					else rtn_result(":", $14);
				}
				else rtn_result_n($6, $8, ":未宣言の配列か、要素数が大きすぎます。");
				YYACCEPT;
			}
		|	F0R FOR '(' expr ',' NAME '>' expr ')' ':' NAME EOL
			{ // 繰り返し（本体）
				unsigned r;
				if (0 == setVariable($6, r = getVariable($6)-1)) {
					if (r > $8) rtn_result("", "");
					else rtn_result(":", $11);
				}
				else rtn_result($6, ":使われている変数が多すぎます。");
				YYACCEPT;
			}
		|	F0R FOR '(' expr ',' NAME '[' expr ']' '>' expr ')' ':' NAME EOL
			{ // 繰り返し（本体）
				unsigned r;
				getVariable_a($6, $8, &r);
				if (0 == setVariable_a($6, $8, --r)) {
					if (r > $11) rtn_result("", "");
					else rtn_result(":", $14);
				}
				else rtn_result_n($6, $8, ":未宣言の配列か、要素数が大きすぎます。");
				YYACCEPT;
			}

		|	GOTO ':' NAME EOL
			{ // ジャンプ GOTO <:ラベル>
				rtn_result(":", $3);
				YYACCEPT;
			}
			
		|	GOSUB ':' NAME EOL
			{ // サブルーチンコール GOSUB <:ラベル>
				rtn_result("GOSUB :", $3);
				YYACCEPT;
			}		

		|	GOTO string EOL
			{ // ジャンプ GOTO str
				if ($2[0] == ':') rtn_result($2, "");
				else rtn_result("GOTOラベルが:で始まっていません - ", $2);
				YYACCEPT;
			}
			
		|	GOSUB string EOL
			{ // サブルーチンコール GOSUB str
				if ($2[0] == ':') rtn_result("GOSUB ", $2);
				else rtn_result("GOSUBラベルが:で始まっていません - ", $2);
				YYACCEPT;
			}

		|	RETURN EOL
			{ // サブルーチンからの帰還
				rtn_result("return", "");
				YYACCEPT;
			}
			
		|	EXIT EOL
			{ // 終了 Exit (正常にダイアログ構築/保存/破棄作業を終了させる)
				rtn_result("exit", "");
				YYACCEPT;
			}
		|	ABORT EOL
			{ // 中断 Abort (強制的にダイアログ構築/保存/破棄作業を中止させる)
				rtn_result("abort", "");
				YYACCEPT;
			}

		|	ARRAY NAME '[' expr ']' EOL
			{	// 配列変数(数値)の準備
				if (array_variables($2, $4) == 1) // 整数型配列を確保 (0 〜 n-1)
					 rtn_result_n($2, $4, ":使用済みの変数か、宣言済みの配列か、メモリが足りません。");
				else rtn_result("", "");
				YYACCEPT;
			}
		|	ARRAY NAME_D '[' expr ']' EOL
			{	// 配列変数(文字列)の準備
				if (array_variables_d($2, $4) == 1) // 文字列型配列を確保 (0 〜 n-1)
					 rtn_result_n($2, $4, ":使用済みの変数か、宣言済みの配列か、メモリが足りません。");
				else rtn_result("", "");
				YYACCEPT;
			}
		
		|	RESIZE NAME '[' expr ']' EOL
			{	// 配列変数(数値)のリサイズ
				if (resize_variables($2, $4) == 1)	// 整数型配列を確保 (0 〜 n-1)
					 rtn_result_n($2, $4, ":メモリが足りません。");
				else rtn_result("", "");
				YYACCEPT;
			}
		|	RESIZE NAME_D '[' expr ']' EOL
			{	// 配列変数(文字列)のリサイズ
				if (resize_variables_d($2, $4) == 1) // 文字列型配列を確保 (0 〜 n-1)
					 rtn_result_n($2, $4, ":メモリが足りません。");
				else rtn_result("", "");
				YYACCEPT;
			}

		|	EOL
		|	':' NAME s
			{ // なにもなし
				rtn_result("", "");
				YYACCEPT;
			}
		;

expr	:	expr '+' expr
			{	$$ = $1 + $3; }
		| expr '-' expr
			{	$$ = $1 - $3; }
		| expr '*' expr
			{ $$ = $1 * $3; }
		| expr '/' expr
			{
				if($3 == 0) {
					rtn_result("0による除算。", "");
					YYACCEPT;
				} else
					$$ = $1 / $3;
			}
		| expr '%' expr
			{
				if($3 == 0.0) {
					rtn_result("0による除算。", "");
					YYACCEPT;
				} else
					$$ = $1 % $3;
			}
		| '-' expr	%prec MINUS
			{ $$ = 0-$2; /* 0x100000000 - $2 の値になる */ }
		| '(' expr ')'
			{ $$ = $2; }

		| NAME '=' expr
			{
				if (0 == setVariable($1, $3))
					$$ = $3;
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' '=' expr
			{
				if (0 == setVariable_a($1, $3, $6))
					$$ = $6;
				else {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
			}
		| NAME '=' string
			{
				unsigned i;
				if (0 == setVariable($1, i = atoi($3)))
					$$ = i;
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' '=' string
			{
				unsigned i;
				if (0 == setVariable_a($1, $3, i = atou($6)))
					$$ = i;
				else {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
			}

		| expr '>' expr
			{ $$ = (unsigned)(($1 > $3)?1:0); }
		| expr '<' expr
			{ $$ = (unsigned)(($1 < $3)?1:0); }
		| expr ELARGE expr
			{ $$ = (unsigned)(($1 >= $3)?1:0); }
		| expr ESMALL expr
			{ $$ = (unsigned)(($1 <= $3)?1:0); }
		| expr EEQUAL expr
			{ $$ = (unsigned)(($1 == $3)?1:0); }
		| expr NEQUAL expr
			{ $$ = (unsigned)(($1 != $3)?1:0); }

		| string '>' string
			{ $$ = (unsigned)((strcmp($1,$3) < 0)?1:0); }
		| string '<' string
			{ $$ = (unsigned)((strcmp($1,$3) > 0)?1:0); }
		| string ELARGE string
			{ $$ = (unsigned)((strcmp($1,$3) >= 0)?1:0); }
		| string ESMALL string
			{ $$ = (unsigned)((strcmp($1,$3) <= 0)?1:0); }
		| string EEQUAL string
			{ $$ = (unsigned)((strcmp($1,$3) == 0)?1:0); }
		| string EEEQUAL string
			{ $$ = (unsigned)((strcmpi($1,$3) == 0)?1:0); }
		| string NEQUAL string
			{ $$ = (unsigned)((strcmp($1,$3) != 0)?1:0); }
		| string NEEQUAL string
			{ $$ = (unsigned)((strcmpi($1,$3) != 0)?1:0); }

		| expr ANDAND expr
			{ $$ = (unsigned)(($1 != 0) && ($3 != 0)); }
		| expr OROR expr
			{ $$ = (unsigned)(($1 != 0) || ($3 != 0)); }
		| expr '&' expr
			{ $$ = ((unsigned)$1 & (unsigned)$3); }
		| expr '|' expr
			{ $$ = ((unsigned)$1 | (unsigned)$3); }
		| expr '^' expr
			{ $$ = ((unsigned)$1 ^ (unsigned)$3); }
		| expr RSHIFT expr
			{ $$ = ((unsigned)$1 >> (unsigned)$3); }
		| expr LSHIFT expr
			{ $$ = ((unsigned)$1 << (unsigned)$3); }
		| '~' expr
			{ $$ = (~(unsigned)$2); }
		| expr '?' expr ':' expr
			{ $$ = ($1 ? $3 : $5); }
		| string '?' expr ':' expr
			{ $$ = ($1[0] ? $3 : $5); }
		| '!' expr
			{ $$ = !($2); }

		| NAME E_ADDOP expr
			{
				if (0 == setVariable($1, getVariable($1) + $3))
					$$ = getVariable($1);
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' E_ADDOP expr
			{
				int r;
				if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, r += $6);
					$$ = r;
				}
			}

		| NAME E_ADDOP string
			{
				if (0 == setVariable($1, getVariable($1) + atoi($3)))
					$$ = getVariable($1);
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' E_ADDOP string
			{
				unsigned r;
				if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, r += atou($6));
					$$ = r;
				}
			}

		| NAME E_SUBOP expr
			{
				if (0 == setVariable($1, getVariable($1) - $3))
					$$ = getVariable($1);
				else {
					rtn_result($1,":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' E_SUBOP expr
			{
				unsigned r;
				if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, r -= $6);
					$$ = r;
				}
			}
			
		| NAME E_MULOP expr
			{
				if (0 == setVariable($1, getVariable($1) * $3))
					$$ = getVariable($1);
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' E_MULOP expr
			{
				unsigned r;
				if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, r *= $6);
					$$ = r;
				}
			}

		| NAME E_DIVOP expr
			{
				if($3 == 0) {
					rtn_result("0による除算。", "");
					YYACCEPT;
				}
				else {
					if (0 == setVariable($1, getVariable($1) / $3))
						$$ = getVariable($1);
					else {
						rtn_result($1, ":使われている変数が多すぎます。");
						YYACCEPT;
					}
				}
			}
		| NAME '[' expr ']' E_DIVOP expr
			{
				unsigned r;
				if($6 == 0) {
					rtn_result("0による除算。", "");
					YYACCEPT;
				}
				else if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, r /= $6);
					$$ = r;
				}
			}
			
		| NAME E_MODOP expr
			{
				if($3 == 0) {
					rtn_result("0による除算。", "");
					YYACCEPT;
				}
				else {
					if (0 == setVariable($1, getVariable($1) % $3))
						$$ = getVariable($1);
					else {
						rtn_result($1, ":使われている変数が多すぎます。");
						YYACCEPT;
					}
				}
			}
		| NAME '[' expr ']' E_MODOP expr
			{
				unsigned r;
				if($6 == 0) {
					rtn_result(":0による除算。", "");
					YYACCEPT;
				}
				else if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, r %= $6);
					$$ = r;
				}
			}
			
		| NAME E_XOROP expr
			{
				if (0 == (setVariable($1, ((unsigned)getVariable($1) ^ (unsigned)$3))))
					$$ = getVariable($1);
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' E_XOROP expr
			{
				unsigned r;
				if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, ((unsigned)r ^= (unsigned)$6));
					$$ = r;
				}
			}			

		| NAME E_ANDOP expr
			{
				if (0 == (setVariable($1, ((unsigned)getVariable($1) & (unsigned)$3))))
					$$ = getVariable($1);
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' E_ANDOP expr
			{
				unsigned r;
				if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, ((unsigned)r &= (unsigned)($6)));
					$$ = r;
				}
			}			

		| NAME E_OROP expr
			{
				if (0 == (setVariable($1, getVariable($1) | $3)))
					$$ = getVariable($1);
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' E_OROP expr
			{
				unsigned r;
				if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, r |= $6);
					$$ = r;
				}
			}			

		| NAME E_RSHIFT expr
			{
				if (0 == (setVariable($1, getVariable($1) >> $3)))
					$$ = getVariable($1);
				else {
					rtn_result($1,":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' E_RSHIFT expr
			{
				unsigned r;
				if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, r >>= $6);
					$$ = r;
				}
			}

		| NAME E_LSHIFT expr
			{
				if (0 == (setVariable($1, getVariable($1) << $3)))
					$$ = getVariable($1);
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' E_LSHIFT expr
			{
				unsigned r;
				if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, r <<= $6);
					$$ = r;
				}
			}

		| NAME INC
			{
				unsigned r = getVariable($1);
				if (0 == (setVariable($1, r + 1)))
					$$ = r;
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' INC
			{
				unsigned r;
				if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, r+1);
					$$ = r;
				}
			}

		| NAME DEC
			{
				unsigned r = getVariable($1);
				if (0 == (setVariable($1, r - 1)))
					$$ = r;
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME '[' expr ']' DEC
			{
				unsigned r;
				if (1 == getVariable_a($1, $3, &r)) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($1, $3, r-1);
					$$ = r;
				}
			}

		| INC NAME
			{
				unsigned r = getVariable($2) + 1;
				if (0 == (setVariable($2, r)))
					$$ = r;
				else {
					rtn_result($2, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| INC NAME '[' expr ']'
			{
				unsigned r;
				if (1 == getVariable_a($2, $4, &r)) {
					rtn_result_n($2, $4, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($2, $4, ++r);
					$$ = r;
				}
			}
			
		| DEC NAME
			{
				unsigned r = getVariable($2) - 1;
				if (0 == (setVariable($2, r)))
					$$ = r;
				else {
					rtn_result($2, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| DEC NAME '[' expr ']'
			{
				unsigned r;
				if (1 == getVariable_a($2, $4, &r)) {
					rtn_result_n($2, $4, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else {
					setVariable_a($2, $4, --r);
					$$ = r;
				}
			}

		| expr '+' string
			{
				$$ = $1 + atoi($3);
			}
		| NUMBER
			{
				$$ = $1;
			}
		| NAME
			{
				$$ = getVariable($1);
			}
		| NAME '[' expr ']'
			{
				unsigned r;
				if (getVariable_a($1, $3, &r) == 1) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else
					$$ = r;
			}
		| NAME '(' args ')'
			{ // 戻り値が数の関数呼び出し
				BYTE result;
				$$ = funccall(hSubDlg, $1, $3, &result);
				switch(result) {
					case UFC_UNKNOWN_FUNCNAME:
						rtn_result($1, "():関数名が違います。");
						YYACCEPT;
						break;

					case UFC_MISSMATCH_ARGS:
						rtn_result($1, "():引数の種類か数が正しくありません。");
						YYACCEPT;
						break;

					case UFS_NEED_DOLLAR:
						rtn_result($1, "():関数名の後ろに$記号が必要です。");
						YYACCEPT;
						break;

					case UFS_NOTFOUNDDLL:
						rtn_result($3->v.text, ":指定されたDLLが見つかりません。");
						YYACCEPT;
						break;

					case UFS_NOTFOUNDDLLFUNC:
						rtn_result($3->next->v.text, "():指定された関数がDLL内に見つかりません。");
						YYACCEPT;
						break;

					case UFC_CANTRUNEXE:
						rtn_result($3->v.text, ":指定されたファイルを実行できません。");
						YYACCEPT;
						break;
				}
			}
		| NAME '.' NAME '(' args ')'
			{ // DLL内関数の呼び出し(戻り値が数)
				BYTE result;
				struct ARGS a_dll, a_func;
				char *buf = malloc(strlen($1)+5);
				if (buf) {
					strcpy(buf, $1);
					strcat(buf, ".dll");
					
					a_dll.type = UFCT_ARG_STRING;
					a_dll.v.text = buf;
					a_dll.next = &a_func;

					a_func.type = UFCT_ARG_STRING;
					a_func.v.text = $3;
					a_func.next = $5;

					$$ = rfunc_CallDll(hSubDlg, &a_dll, &result);
					switch(result) {
						case UFC_UNKNOWN_FUNCNAME:
							rtn_result($3, "():関数名が違います。");
							YYACCEPT;
							break;

						case UFC_MISSMATCH_ARGS:
							rtn_result($3, "():引数の種類か数が正しくありません。");
							YYACCEPT;
							break;

						case UFS_NEED_DOLLAR:
							rtn_result($3, "():関数名の後ろに$記号が必要です。");
							YYACCEPT;
							break;

						case UFS_NOTFOUNDDLL:
							rtn_result($1, ":指定されたDLLが見つかりません。");
							YYACCEPT;
							break;

						case UFS_NOTFOUNDDLLFUNC:
							rtn_result($3, "():指定された関数がDLL内に見つかりません。");
							YYACCEPT;
							break;

						case UFC_CANTRUNEXE:
							rtn_result($3, ":指定されたファイルを実行できません。");
							YYACCEPT;
							break;
					}
					
					safefree(buf);
				}
				else {
					rtn_result($3, ":メモリが足らないため、実行を継続できません。");
					YYACCEPT;				
				}
			}
		;
		
string	: string '+' string
			{
				$$ = RM(malloc(strlen($1) + strlen ($3) + 1));
				strcpy($$, $1);
				strcat($$, $3);
			}
		| string '+' expr
			{
				$$ = RM(malloc(strlen($1) + 12));
				sprintf($$, "%s%u", $1, $3);
			}

		| expr '?' string ':' string
			{
				$$ = ($1 ? $3 : $5);
			}
		| string '?' string ':' string
			{
				$$ = ($1[0] ? $3 : $5);
			}

		| NAME_D '=' string
			{
				if (setVariable_d($1, $3) == 0)
					$$ = $3;
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME_D '[' expr ']' '=' string
			{
				if (setVariable_d_a($1, $3, $6) == 0)
					$$ = $6;
				else {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
			}

		| NAME_D E_ADDOP string
			{
				if (addVariable_d($1, $3) == 0)
					$$ = getVariable_d($1);
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME_D '[' expr ']' E_ADDOP string
			{
				if (addVariable_d_a($1, $3, $6) == 0)
					$$ = getVariable_d_a($1, $3);
				else {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
			}

		| NAME_D '=' expr
			{
				char itbuf[16];
				if (setVariable_d($1, itoa10ex($3, itbuf)) == 0)
					$$ = getVariable_d($1);
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME_D '[' expr ']' '=' expr
			{
				char itbuf[16];
				if (setVariable_d_a($1, $3, itoa10ex($6, itbuf)) == 0)
					$$ = getVariable_d_a($1, $3);
				else {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
			}

		| NAME_D E_ADDOP expr
			{
				char itbuf[16];
				if (addVariable_d($1, itoa10ex($3, itbuf)) == 0)
					$$ = getVariable_d($1);
				else {
					rtn_result($1, ":使われている変数が多すぎます。");
					YYACCEPT;
				}
			}
		| NAME_D '[' expr ']' E_ADDOP expr
			{
				char itbuf[16];
				if (addVariable_d_a($1, $3, itoa10ex($6, itbuf)) == 0)
					$$ = getVariable_d_a($1, $3);
				else {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
			}

		| NAME_D
			{	$$ = getVariable_d($1);	}
		| NAME_D '[' expr ']'
			{
				char *s;
				if (NULL == (s = getVariable_d_a($1, $3))) {
					rtn_result_n($1, $3, ":未宣言の配列か、要素数が大きすぎます。");
					YYACCEPT;
				}
				else
					$$ = s;
			}
			
		| '(' string ')'
			{	$$ = $2;	}
			
		| NAME_D '(' args ')'
			{ // 戻り値が文字列の関数呼び出し
				BYTE result;
				char *tmp;

				tmp = funccall_d(hSubDlg, $1, $3, &result);
				switch(result) {
					case UFC_UNKNOWN_FUNCNAME:
						rtn_result($1, "():関数名が違います。");
						YYACCEPT;
						break;

					case UFC_MISSMATCH_ARGS:
						rtn_result($1, "():引数の種類か数が正しくありません。");
						YYACCEPT;
						break;

					case UFS_NOTFOUNDDLL:
						rtn_result($3->v.text, ":指定されたDLLが見つかりません。");
						YYACCEPT;
						break;

					case UFS_NOTFOUNDDLLFUNC:
						rtn_result($3->next->v.text, ":指定された関数がDLL内に見つかりません。");
						YYACCEPT;
						break;
				}
				
				if (tmp)
					$$ = RM(tmp);
				else
					$$ = "";
			}

		| NAME '.' NAME_D '(' args ')'
			{ // 戻り値が文字列の関数呼び出し
				BYTE result;
				char *tmp, *dllname, *funcname, *p;
				struct ARGS a_dll, a_func;

				dllname = malloc(strlen($1) + 5);
				if (dllname) {
					funcname = _strdup($3);
					if (funcname) {
						// dllname.funcname$() で呼び出された場合は、dllname に .dllをつける
						strcpy(dllname, $1);
						strcat(dllname, ".dll");
						a_dll.type = UFCT_ARG_STRING;
						a_dll.v.text = dllname;
						a_dll.next = &a_func;

						// funcname$() から $ を取り除く
						p = strchr(funcname, '$');
						if (p)
							*p = 0;
						a_func.type = UFCT_ARG_STRING;
						a_func.v.text = funcname;
						a_func.next = $5;
						
						tmp = rfunc_CallDll_dd(hSubDlg, &a_dll, &result);
						switch(result) {
							case UFC_UNKNOWN_FUNCNAME:
								rtn_result($3, "():関数名が違います。");
								YYACCEPT;
								break;

							case UFC_MISSMATCH_ARGS:
								rtn_result($3, "():引数の種類か数が正しくありません。");
								YYACCEPT;
								break;

							case UFS_NOTFOUNDDLL:
								rtn_result($1, ":指定されたDLLが見つかりません。");
								YYACCEPT;
								break;

							case UFS_NOTFOUNDDLLFUNC:
								rtn_result($3, ":指定された関数がDLL内に見つかりません。");
								YYACCEPT;
								break;
						}
						
						if (tmp)
							$$ = RM(tmp);
						else
							$$ = "";
							
						safefree(funcname);
						safefree(dllname);
					}
					else {
						safefree(dllname);
						rtn_result($3, ":メモリが足らないため、実行を継続できません。");
						YYACCEPT;
					}
				}
				else {
					rtn_result($3, ":メモリが足らないため、実行を継続できません。");
					YYACCEPT;
				}
			}

		| STRING
			{ $$ = $1; }
		;
		
args	: arg ',' args
			{
				$1->next = $3;
				$$ = $1;
			}
		| arg
			{	$$ = $1;	}
		|
			{	$$ = NULL;	}
		;
		
arg		: expr
			{
				struct ARGS *arg = (struct ARGS *)RM(malloc(sizeof(struct ARGS)));
				arg->next = NULL;
				arg->type = UFCT_ARG_INT;
				arg->v.integer = $1;
				$$ = arg;				
			}
		| string
			{
				struct ARGS *arg = (struct ARGS *)RM(malloc(sizeof(struct ARGS)));
				arg->next = NULL;
				arg->type = UFCT_ARG_STRING;
				arg->v.text = $1;
				$$ = arg;
			}
		| NAME '[' ']'
			{
				struct ARGS *arg = (struct ARGS *)RM(malloc(sizeof(struct ARGS)));
				arg->next = NULL;
				arg->type = UFCT_ARG_INTS;
				arg->v.text = $1;
				$$ = arg;
			}
		| NAME_D '[' ']'
			{
				struct ARGS *arg = (struct ARGS *)RM(malloc(sizeof(struct ARGS)));
				arg->next = NULL;
				arg->type = UFCT_ARG_STRINGS;
				arg->v.text = $1;
				$$ = arg;
			}
		;
		
%%

char *regimemory(char *p)
{
	if (p) { // 登録
		char **tmp;
		if (NULL != (tmp = (char **)realloc(bufs, (num_bufs + 1) * sizeof(char*)))) {
			bufs = tmp;
			bufs[num_bufs++] = p;
		}
	}
	return p;
}

static void	free_memorys(void)
{
	// 一時的に確保したメモリを解放
	if (bufs) {
		unsigned i;
		for(i=0 ; i<num_bufs ; i++)
			safefree(bufs[i]);
		safefree(bufs);
		num_bufs = 0;	
	}
}

char	*interprete(HWND hWnd, const char *buf)
{
	hSubDlg = hWnd;
	set_input_buffer (buf);
	yyparse();
	free_memorys();
	return(yaccReturnValue);
}

static	void rtn_result(char *text1, char *text2)
{
	safefree(yaccReturnValue);
	yaccReturnValue = malloc(strlen(text1) + strlen(text2) + 1);
	if (yaccReturnValue) {
		strcpy(yaccReturnValue, text1);
		strcat(yaccReturnValue, text2);
	}
}

static	void rtn_result_n(char *text1, unsigned n, char *text2)
{
	safefree(yaccReturnValue);
	yaccReturnValue = malloc(strlen(text1) + 15 + strlen(text2) + 1);
	if (yaccReturnValue) {
		char itbuf[16];
		strcpy(yaccReturnValue, text1);
		strcat(yaccReturnValue, "[");
		strcat(yaccReturnValue, itoa10ex(n, itbuf));
		strcat(yaccReturnValue, "]");
		strcat(yaccReturnValue, text2);
	}
}

static	int yyerror(char *msg)
{
	safefree(yaccReturnValue);
	yaccReturnValue = _strdup(msg);
	return 0;
}

int yywrap(void)
{
	return 1;
}
