﻿#include "stdafx.h"
#include "Common.h"
#include "fr_script.h"
#include "fr_parser_tab.h" // Bisonが生成するヘッダ

//#define FR_DEBUG	1

#ifdef FR_DEBUG
const char *OPNAME(int op)
{
	switch (op) {
		case ND_BLOCK:		return "BLOCK";
		case ND_ASSIGN:		return "ASSIGN";
		case ND_IF:			return "IF";
		case ND_WHILE:		return "WHILE";
		case ND_EXIT:		return "EXIT";
		case ND_BREAK:		return "BREAK";
		case ND_CONTINUE:	return "CONTINUE";
		case ND_EXPR_INT:	return "INT";
		case ND_EXPR_STR:	return "STRING";
		case ND_VAR:		return "VAR";
		case ND_FUNC_CALL:	return "FUNC";
		case ND_CB_CALL:	return "CBFUNC";
		case ND_ADD:		return "+";
		case ND_SUB:		return "-";
		case ND_MUL:		return "*";
		case ND_DIV:		return "/";
		case ND_MOD:		return "%";
		case ND_BIT_OR:		return "|";
		case ND_BIT_AND:	return "&";
		case ND_BIT_XOR:	return "^";
		case ND_BIT_NOT:	return "~";
		case ND_LSHIFT:		return "<<";
		case ND_RSHIFT:		return ">>";
		case ND_EQ:			return "==";
		case ND_NE:			return "!=";
		case ND_STRICT_EQ:	return "===";
		case ND_STRICT_NE:	return "!==";
		case ND_LT:			return "<";
		case ND_GT:			return ">";
		case ND_LE:			return "<=";
		case ND_GE:			return ">=";
		case ND_LOGIC_AND:	return "&&";
		case ND_LOGIC_OR:	return "||";
		case ND_LOGIC_NOT:	return "!";
		default:			return "Unknown";
	}
}

#endif

// グローバル変数定義
Context g_context;
Node* g_root = NULL;

// --- Node Implementations ---

// IntNode（数値）
IntNode::IntNode(int v) : val(v) { type = ND_EXPR_INT; }
Value IntNode::eval() {
#ifdef FR_DEBUG
	fprintf(stderr, "IntNode:%d\n", val);
#endif
	
	return val;
}

// VarNode（変数）
/*VarNode::VarNode(char* n) {
#ifdef FR_DEBUG
	fprintf(stderr, "VarNode:%s\n",n);
#endif

	name = n;
    std::transform(name.begin(), name.end(), name.begin(), ::toupper);
    free(n); 
    type = ND_VAR;
}*/
Value VarNode::eval() {
	// コンテキスト（変数テーブル）から検索
    if (g_context.variables.count(name)) {
        return g_context.variables[name];
    }

    // 未定義変数の場合
    if (!name.empty() && name[name.length()-1] == '$') {
        return Value(""); // 文字列変数は空文字
    }
    return Value(0);      // 数値変数は0
}
Value& VarNode::ref() { return g_context.variables[name]; }

// BinaryNode
BinaryNode::BinaryNode(NodeType t, Node* l, Node* r) : lhs(l), rhs(r) { type = t; }
BinaryNode::~BinaryNode() { delete lhs; delete rhs; }
Value BinaryNode::eval() {
#ifdef FR_DEBUG
	fprintf(stderr, "BinaryNode[(%d:%s):", type, OPNAME(type));
	if (lhs->eval().isString) {
		fprintf(stderr, "(string)%s,",lhs->eval().sVal.c_str());
	}
	else {
		fprintf(stderr, "(int)%d,",lhs->eval().iVal);
	}
	if (rhs->eval().isString) {
		fprintf(stderr, "(string)%s]\n",rhs->eval().sVal.c_str());
	}
	else {
		fprintf(stderr, "(int)%d]\n",rhs->eval().iVal);
	}
#endif

	Value l = lhs->eval();
    if (type == ND_LOGIC_AND && !l.toInt()) return 0;
    if (type == ND_LOGIC_OR  &&  l.toInt()) return 1;

    Value r = rhs->eval();

    switch(type) {
        case ND_ADD: 
				// 文字列 + 何か = 連結
				if (l.isString) return Value(l.sVal + r.toStr());
				// 数値 + 文字列 = 文字列を数値化して加算
				if (r.isString) return Value(l.iVal + r.toInt());
				// 数値 + 数値
				return Value(l.iVal + r.iVal);

        case ND_SUB: return l.toInt() - r.toInt();
        case ND_MUL: return l.toInt() * r.toInt();
    	case ND_DIV: if (r.iVal != 0) {
    					return(l.iVal / r.iVal);
    				 }
			    	 else {
						/* エラー発生コールバック(0による除算:商) */
						char errmes[1025];
						wsprintfA(errmes, "Runtime Error: Division by zero(/0) at line %d\n", this->line);
						errorCall(ERROR_DIV0, yylineno, errmes);
						g_context.status = EXEC_EXIT;
						break;
			    	 }
        case ND_MOD: if (r.toInt() != 0) {
    					return(l.toInt() % r.toInt());
    				 }
			    	 else {
						/* エラー発生コールバック(0による除算:余り) */
						char errmes[1025];
						wsprintfA(errmes, "Runtime Error: Division by zero(%%0) at line %d\n", this->line);
						errorCall(ERROR_DIV0M, yylineno, errmes);
						g_context.status = EXEC_EXIT;
			    	 	break;
			    	 }
        case ND_BIT_OR:  return l.toInt() | r.toInt();
        case ND_BIT_AND: return l.toInt() & r.toInt();
        case ND_BIT_XOR: return l.toInt() ^ r.toInt();
        case ND_LSHIFT:  return l.toInt() << r.toInt();
        case ND_RSHIFT:  return l.toInt() >> r.toInt();
        case ND_EQ: // ゆるい比較(==)
			if (l.isString || r.isString) return Value(l.toStr() == r.toStr() ? 1 : 0);
				return Value(l.iVal == r.iVal ? 1 : 0);

		case ND_STRICT_EQ: // 厳密な比較 (===)
            if (l.isString != r.isString) return Value(0);
            if (l.isString) return Value(l.sVal == r.sVal ? 1 : 0);
            return Value(l.iVal == r.iVal ? 1 : 0);

        case ND_NE: // ゆるい比較(!=)
			if (l.isString || r.isString) return Value(l.toStr() != r.toStr() ? 1 : 0);
				return Value(l.iVal != r.iVal ? 1 : 0);

		case ND_STRICT_NE: // 厳密な比較 (!==)
            if (l.isString != r.isString) return Value(1);
            if (l.isString) return Value(l.sVal != r.sVal ? 1 : 0);
            return Value(l.iVal != r.iVal ? 1 : 0);

        case ND_LT:
			if (l.isString || r.isString) return Value(l.toStr() < r.toStr() ? 1 : 0);
				return Value(l.iVal < r.iVal ? 1 : 0);

		case ND_GT:
			if (l.isString || r.isString) return Value(l.toStr() > r.toStr() ? 1 : 0);
				return Value(l.iVal > r.iVal ? 1 : 0);

        case ND_LE:
			if (l.isString || r.isString) return Value(l.toStr() <= r.toStr() ? 1 : 0);
				return Value(l.iVal <= r.iVal ? 1 : 0);

        case ND_GE:
			if (l.isString || r.isString) return Value(l.toStr() >= r.toStr() ? 1 : 0);
				return Value(l.iVal >= r.iVal ? 1 : 0);

        case ND_LOGIC_AND: return l.toInt() && r.toInt();
        case ND_LOGIC_OR:  return l.toInt() || r.toInt();
    }
    return 0;
}

// UnaryNode
UnaryNode::UnaryNode(NodeType t, Node* o) : op(o) { type = t; }
UnaryNode::~UnaryNode() { delete op; }
Value UnaryNode::eval() {
#ifdef FR_DEBUG
	fprintf(stderr, "UnaryNode(%d:%s):", type, OPNAME(type));
	if (op->eval().isString) {
		fprintf(stderr, "(string)%s\n",op->eval().sVal.c_str());
	}
	else {
		fprintf(stderr, "(int)%d\n",op->eval().iVal);
	}
#endif

	int v = op->eval().toInt();
    switch(type) {
        case ND_SUB: return -v;
        case ND_LOGIC_NOT: return !v;
        case ND_BIT_NOT: return ~v;
    }
    return 0;
}

// BlockNode
BlockNode::BlockNode() { type = ND_BLOCK; }
BlockNode::~BlockNode() { for(size_t i=0; i<stmts.size(); ++i) delete stmts[i]; }
void BlockNode::add(Node* n) { stmts.push_back(n); }
Value BlockNode::eval() {
#ifdef FR_DEBUG
	fprintf(stderr, "BlockNode\n");
#endif

	Value lastVal = 0;
    for(size_t i=0; i<stmts.size(); ++i) {
        lastVal = stmts[i]->eval();

		/* 1行実行するごとにコールバック */
		if (g_context.stepCallBack) {
			if (STEP_CALLBACK_STOP == g_context.stepCallBack(stmts[i]->line)) {
				/* 呼び出し元から中断指示が来たらEXIT */
				g_context.status = EXEC_EXIT;
				break;
			}
		}

        if(g_context.status != EXEC_NORMAL) break;
    }
    return lastVal;
}

// AssignNode
AssignNode::AssignNode(VarNode* v, Node* e, int o) : var(v), expr(e), op(o) { type = ND_ASSIGN; }
AssignNode::~AssignNode() { delete var; delete expr; }
Value AssignNode::eval() {
#ifdef FR_DEBUG
	fprintf(stderr, "AssignNode{(%d:%s):%s,", op, OPNAME(op), var->name.c_str());
	if (expr->eval().isString) {
		fprintf(stderr, "(string)%s}\n",expr->eval().sVal.c_str());
	}
	else {
		fprintf(stderr, "(int)%d}\n",expr->eval().iVal);
	}
#endif

	if(op == ND_ASSIGN) { // 普通の代入
		var->ref() = expr->eval();
	}
	else {
		if (var->ref().isString) { // 代入先が文字列型変数の場合
			std::string val = expr->eval().toStr();
			if(op == ND_ADD_ASSIGN) { // 加算（文字列ver.）
				var->ref() = var->eval().sVal + val;
			}
			return var->ref().iVal;
		}
		else { // 代入先が数値変数の場合
			int val = expr->eval().toInt();
			if(op == ND_ADD_ASSIGN) { // 加算
				var->ref().iVal += val;
			}
			else if(op == ND_SUB_ASSIGN) { // 減算
				var->ref().iVal -= val;
			}
			else if(op == ND_ADD_ASSIGN_AFTER) { // 加算（ただし、変化前の値を返す。v++用）
				int ret=var->ref().iVal;
				var->ref().iVal += val;
				return ret;
			}
			else if(op == ND_SUB_ASSIGN_AFTER) { // 減算（ただし、変化前の値を返す。v--用）
				int ret=var->ref().iVal;
				var->ref().iVal -= val;
				return ret;
			}
			else if(op == ND_MUL_ASSIGN) { // 乗算
				var->ref().iVal *= val;
			}
			else if(op == ND_DIV_ASSIGN) { // 除算
				if (val == 0) {
					/* エラー発生コールバック(0による除算:商) */
					char errmes[1025];
					wsprintfA(errmes, "Runtime Error: Division by zero(/0) at line %d\n", this->line);
					errorCall(ERROR_DIV0, yylineno, errmes);
					g_context.status = EXEC_EXIT;
				}
				else {
					var->ref().iVal /= val;
				}
			}
			else if(op == ND_MOD_ASSIGN) { // 余り
				if (val == 0) {
					/* エラー発生コールバック(0による除算:余り) */
					char errmes[1025];
					wsprintfA(errmes, "Runtime Error: Division by zero(%%0) at line %d\n", this->line);
					errorCall(ERROR_DIV0M, yylineno, errmes);
					g_context.status = EXEC_EXIT;
				}
				else {
					var->ref().iVal %= val;
				}
			}
			else if(op == ND_RSHIFT_ASSIGN) { // 右シフト
				var->ref().iVal >>= val;
			}
			else if(op == ND_LSHIFT_ASSIGN) { // 左シフト
				var->ref().iVal <<= val;
			}
			else if(op == ND_OR_ASSIGN) { // OR
				var->ref().iVal |= val;
			}
			else if(op == ND_XOR_ASSIGN) { // XOR
				var->ref().iVal ^= val;
			}
			else if(op == ND_AND_ASSIGN) { // AND
				var->ref().iVal &= val;
			}

			return var->ref().iVal;
		}
	}

	return var->ref();
}

// IfNode
IfNode::IfNode(Node* c, Node* t, Node* e) : cond(c), thenBlock(t), elseBlock(e) { type = ND_IF; }
IfNode::~IfNode() { delete cond; delete thenBlock; if(elseBlock) delete elseBlock; }
Value IfNode::eval() {
#ifdef FR_DEBUG
	fprintf(stderr, "IfNode\n");
#endif

	// thenになる条件…数値型なら0以外、文字列型なら空文字列以外（長さ1異常の文字列）
	Value condresult = cond->eval();
	if(condresult.isString ? condresult.sVal.size() > 0 : condresult.iVal) {
		return thenBlock->eval();
	}
    else if(elseBlock) {
		return elseBlock->eval();
	}

    return 0;
}

// WhileNode
WhileNode::WhileNode(Node* c, Node* b, bool loop) : cond(c), block(b), isLoop(loop) { type = ND_WHILE; }
WhileNode::~WhileNode() { if(cond) delete cond; delete block; }
Value WhileNode::eval() {
#ifdef FR_DEBUG
	fprintf(stderr, "WhileNode\n");
#endif

	Value ret = 0;
	Value condresult;
	// whileのときのループ条件…数値型なら0以外、文字列型なら空文字列以外（長さ1異常の文字列）

    while(isLoop || (condresult = cond->eval(),condresult.isString ? condresult.sVal.size() > 0 : condresult.iVal)) {
        ret = block->eval();
        if(g_context.status == EXEC_BREAK) {
            g_context.status = EXEC_NORMAL;
            break;
        }
        if(g_context.status == EXEC_CONTINUE) {
            g_context.status = EXEC_NORMAL;
            continue;
        }
        if(g_context.status == EXEC_EXIT) break;
    }
    return ret;
}

// FlowNode (BREAK, CONTINUE)
FlowNode::FlowNode(NodeType t) { type = t; }
Value FlowNode::eval() {
#ifdef FR_DEBUG
	fprintf(stderr, "FlowNode(%d:%s)\n",type, OPNAME(type));
#endif

    if (type == ND_BREAK) g_context.status = EXEC_BREAK;
    if (type == ND_CONTINUE) g_context.status = EXEC_CONTINUE;
    return 0;
}

// ExitNode
ExitNode::ExitNode(Node* e) : expr(e) { type = ND_EXIT; }
ExitNode::~ExitNode() { if(expr) delete expr; }
Value ExitNode::eval() {
#ifdef FR_DEBUG
	fprintf(stderr, "ExitNode::eval()\n");
#endif

	g_context.status = EXEC_EXIT;
	g_context.exitCode = expr ? expr->eval().toInt() : 0;
    return g_context.exitCode;
}

// UTF-8→UTF-16文字列コンバータ
std::wstring u8_to_u16(std::string &u8)
{
	int len = MultiByteToWideChar(CP_UTF8, 0, u8.c_str(), -1, NULL, NULL);
	if (len == 0) {
		return L"";
	}
	WCHAR* u16cstr = (WCHAR *)calloc(len+2, sizeof(WCHAR));
	if (u16cstr) {
		MultiByteToWideChar(CP_UTF8, 0, u8.c_str(), -1, u16cstr, len);
		std::wstring u16(u16cstr);
		free(u16cstr);
		return u16;
	}
	return L"";
}

// UTF-16→UTF-8文字列コンバータ
std::string u16_to_u8(std::wstring &u16)
{
	int len = WideCharToMultiByte(CP_UTF8, 0, u16.c_str(), -1, NULL, 0, NULL, NULL);
	if (len == 0) {
		return "";
	}
	char* u8cstr = (char *)calloc(len+2, sizeof(char));
	if (u8cstr) {
		WideCharToMultiByte(CP_UTF8, 0, u16.c_str(), -1, u8cstr, len, NULL, NULL);
		std::string u8(u8cstr);
		free(u8cstr);
		return u8;
	}
	return "";
}

// エラーコールバック呼び出し
void errorCall(int errcd, int line, const char *mes)
{
	if (g_context.errorCallBack) {
		// エラーメッセージをWide Charへ変換
		std::wstring wmes(u8_to_u16(std::string(mes)));

		// エラーコールバック
		g_context.errorCallBack(ERROR_UNKNOWN_FUNCD, line, wmes.c_str());
	}
}

// ヘルパー：MsgBox API(A→W）呼び出し
int CallMsgBoxAPI(std::string &msg, std::string &title, int flag)
{
	// msg, titleをWideCharに変換
	std::wstring wmsg(u8_to_u16(msg));
	std::wstring wtitle(u8_to_u16(title));

	return g_context.pMsgBoxW(g_context.hWnd, wmsg.c_str(), wtitle.c_str(), flag);
}

// ヘルパー：大文字変換（比較用・組み込み関数用）
std::string to_upper_std(std::string s) {
    std::transform(s.begin(), s.end(), s.begin(), ::toupper);
    return s;
}

// 組み込み関数ヘルパー
Value CallBuiltin(std::string name, std::vector<Value>& args, int iLine) {
    std::string uname = to_upper_std(name);
    SYSTEMTIME st; GetLocalTime(&st);
	size_t ac = args.size();

#ifdef FR_DEBUG
	fprintf(stderr, "CallBuiltin:%s(), argc=%d, args=", uname.c_str(), ac);
	for(int i=0 ; i<ac ; ++i) {
		if (i > 0) {
			fprintf(stderr, ", ");
		}
		if (args[i].isString) {
			fprintf(stderr, "(string)%s",args[i].sVal.c_str());
		}
		else {
			fprintf(stderr, "(int)%d",args[i].iVal);
		}
	}
	fprintf(stderr, "\n");
#endif

	bool bNeedD = false;

	// --- 基本操作 ---
	if (uname == "SLEEP" && ac == 1) {
		Sleep(args[0].toInt()); return 1;
	}

    else if (uname == "GETCURRENTYEAR" && ac == 0)         return st.wYear;
    else if (uname == "GETCURRENTMONTH" && ac == 0)        return st.wMonth;
    else if (uname == "GETCURRENTDAY" && ac == 0)          return st.wDay;
    else if (uname == "GETCURRENTDAYOFWEEK" && ac == 0)    return st.wDayOfWeek;
    else if (uname == "GETCURRENTHOUR" && ac == 0)         return st.wHour;
    else if (uname == "GETCURRENTMINUTE" && ac == 0)       return st.wMinute;
    else if (uname == "GETCURRENTSECOND" && ac == 0)       return st.wSecond;
    else if (uname == "GETCURRENTMILLISECONDS" && ac == 0) return st.wMilliseconds;
    else if (uname == "RAND" && ac == 0) return rand();
    else if (uname == "SRAND" && (ac == 0 || ac == 1)) {
		if (ac == 0) {
			srand(GetTickCount());
		}
		else {
			srand(args[0].toInt());
		}
		return 1;
	}
    else if (uname == "GETSYSTEMMETRICS" && ac == 1) {
		return GetSystemMetrics(args[0].toInt());
	}
    else if (uname == "GETFR_SCRIPTVERSION" && ac == 0) {
		return FR_SCRIPT_VERSIONNUMBER;
	}

	// --- MessageBox系 ---
    else if ((uname == "TEXTOUT" || uname == "MESSAGE" || uname == "MESSAGEBOX") && (ac == 1 || ac == 2)) {
		std::string title;

		if (ac == 1) {
			title = "Message";
		}
		else {
			title = args[1].toStr();
		}
		CallMsgBoxAPI(args[0].toStr(), title, MB_OK);
        
        return Value(0);
    }
    else if (uname == "QUESTION" && (ac == 1 || ac == 2)) {
        int res;
		std::string title;
		
		if (ac == 1) {
			title = "Question";
		}
		else {
			title = args[1].toStr();
		}

		res = CallMsgBoxAPI(args[0].toStr(), title, MB_YESNO | MB_ICONQUESTION);

        return Value(res == IDYES ? 1 : 0);
    }
    else if (uname == "QUESTION_OKCANCEL" && (ac == 1 || ac == 2)) {
        int res;
		std::string title;
		
		if (ac == 1) {
			title = "Question";
		}
		else {
			title = args[1].toStr();
		}

		res = CallMsgBoxAPI(args[0].toStr(), title, MB_OKCANCEL | MB_ICONQUESTION);

        return Value(res == IDOK ? 1 : 0);
    }
    else if (uname == "QUESTION_YESNOCANCEL" && (ac == 1 || ac == 2)) {
        int res;
		std::string title;
		
		if (ac == 1) {
			title = "Question";
		}
		else {
			title = args[1].toStr();
		}

		res = CallMsgBoxAPI(args[0].toStr(), title, MB_YESNOCANCEL | MB_ICONQUESTION);

        return Value(res == IDYES ? 1 :
			         res == IDNO  ? 0 :
					                -1 );
    }
    else if ((uname == "WARNING" || uname == "INFORMATION" || uname == "ERROR") && (ac == 1 || ac == 2)) {
        UINT icon = (uname == "WARNING") ? MB_ICONWARNING : 
                    (uname == "ERROR") ? MB_ICONSTOP : MB_ICONINFORMATION;
		std::string title;

		if (ac == 1) {
			title = (uname == "WARNING") ? "Warning" : 
                    (uname == "ERROR") ? "Error" : "Information";
		}
		else {
			title = args[1].toStr();
		}
		CallMsgBoxAPI(args[0].toStr(), title, MB_OK | icon);
        
        return Value(0);
    }

    // --- 文字列操作 ---
    else if (uname == "STRLEN" && ac == 1) { // 文字列を構成するバイト数を返す
		return Value((int)args[0].toStr().length());
	}
    else if (uname == "TOINT" && ac == 1) { // 数値に変換
		return Value(args[0].toInt());
	}
    else if (uname == "TOSTR$" && ac == 1) { // 10進数の文字列に変換
		return Value(args[0].toStr());
	}
	else if (uname == "TOSTR") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}
    // --- 検索・変換 ---
    else if (uname == "STRSTR" && ac == 2) {
        size_t pos = args[0].toStr().find(args[1].toStr());
        return Value(pos == std::string::npos ? -1 : (int)pos);
    }
    else if (uname == "STRSTRI" && ac == 2) {
        std::string s1 = to_upper_std(args[0].toStr());
        std::string s2 = to_upper_std(args[1].toStr());
        size_t pos = s1.find(s2);
        return Value(pos == std::string::npos ? -1 : (int)pos);
    }
    else if (uname == "TOSTR2$" && ac == 1) { // 2進数の文字列に変換
        unsigned int n = (unsigned int)args[0].toInt();
        if (n == 0) return Value("0");
        std::string r = "";
        while (n > 0) {
            r = (n % 2 == 0 ? "0" : "1") + r;
            n /= 2;
        }
        return Value(r);
    }
	else if (uname == "TOSTR2") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}
    else if (uname == "TOSTR16$" && ac == 1) { // 16進数の文字列に変換
        char buf[32];
        wsprintfA(buf, "%X", (unsigned char)args[0].toInt());
        return Value(std::string(buf));
    }
	else if (uname == "TOSTR16") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}

	else if (uname == "PADLEFT$" && (ac == 2 || ac == 3)) { // 第１引数の文字列に対して左にパディング。第２引数に最低限の文字数、第３引数に補う文字(デフォルトはスペース)を指定
		std::string str(args[0].toStr());
		int len = (int)str.size();
		int min = args[1].toInt();

		// 左に補文字を追加(すでに、最低限の文字数よりも現在の文字数の方が多かった場合は何もしない)
		if( len <= min ) {
			// 補文字の取得（デフォルトはスペース）
			std::string padchar(ac == 2 ? " " : args[2].toStr());
			char c = padchar[0];
			if (c == 0) c = ' ';

			str.insert(0, min-len, c);
		}

		return Value(str); // 生成した文字列を返す
	}
	else if (uname == "PADLEFT") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}

	else if (uname == "PADRIGHT$" && (ac == 2 || ac == 3)) { // 第１引数の文字列に対して右にパディング。第２引数に最低限の文字数、第３引数に補う文字(デフォルトはスペース)を指定
		std::string str(args[0].toStr());
		int len = (int)str.size();
		int min = args[1].toInt();

		// 右に補文字を追加(すでに、最低限の文字数よりも現在の文字数の方が多かった場合は何もしない)
		if( len <= min ) {
			// 補文字の取得（デフォルトはスペース）
			std::string padchar(ac == 2 ? " " : args[2].toStr());
			char c = padchar[0];
			if (c == 0) c = ' ';

			str.insert(len, min-len, c);
		}

		return Value(str); // 生成した文字列を返す
	}
	else if (uname == "PADRIGHT") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}

	else if (uname == "TRIMLEFT$" && (ac == 1 || ac == 2)) { // 第１引数の文字列に対して左トリム。第２引数にトリムする文字(デフォルトはスペース)を指定（複数指定可）
		std::string str(args[0].toStr());
		int len = (int)str.size();
		std::string trimchar;

		// 削除文字の取得（デフォルトはスペース）
		if (ac == 1) {
			trimchar = " ";
		}
		else {
			trimchar = args[1].toStr();
			if (trimchar.size() == 0) {
				trimchar = " ";
			}
		}

		// 削除文字以外の最初の文字の位置を取得
		size_t start = str.find_first_not_of(trimchar);

		// トリムした文字列を部分文字列として生成し、生成した文字列を返す
		return Value(start == std::string::npos ? str : str.substr(start));
	}
	else if (uname == "TRIMLEFT") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}

	else if (uname == "TRIMRIGHT$" && (ac == 1 || ac == 2)) { // 第１引数の文字列に対して右トリム。第２引数にトリムする文字(デフォルトはスペース)を指定（複数指定可）
		std::string str(args[0].toStr());
		int len = (int)str.size();
		std::string trimchar;

		// 削除文字の取得（デフォルトはスペース）
		if (ac == 1) {
			trimchar = " ";
		}
		else {
			trimchar = args[1].toStr();
			if (trimchar.size() == 0) {
				trimchar = " ";
			}
		}

		// 削除文字以外の最後の文字の位置を取得
		size_t end = str.find_last_not_of(trimchar);

		// トリムした文字列を部分文字列として生成し、生成した文字列を返す
		return Value(end == std::string::npos ? str : str.substr(0, end+1)); 
	}
	else if (uname == "TRIMRIGHT") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}

    else if (uname == "STRUPR$" && ac == 1) {
        return Value(to_upper_std(args[0].toStr()));
    }
	else if (uname == "STRUPR") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}
    else if (uname == "STRLWR$" && ac == 1) {
        std::string s = args[0].toStr();
        std::transform(s.begin(), s.end(), s.begin(), ::tolower);
        return Value(s);
    }
	else if (uname == "STRLWR") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}

    // --- 切り出し (1-based index) ---
	else if (uname == "LEFT$" && ac == 2) {
        std::string s = args[0].toStr();
        int n = args[1].toInt();
        return Value(s.substr(0, (size_t)n));
    }
	else if (uname == "LEFT") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}
    else if (uname == "RIGHT$" && ac == 2) {
        std::string s = args[0].toStr();
        int n = args[1].toInt();
        if (n >= (int)s.length()) return Value(s);
        return Value(s.substr(s.length() - n));
    }
	else if (uname == "RIGHT") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}
    else if ((uname == "MID$" || uname == "SUBSTR$" || uname == "SUBSTRING$") && ac == 3) {
        std::string s = args[0].toStr();
        int start = args[1].toInt() - 1; // 1文字目 -> index 0
        int len = args[2].toInt();
        if (start < 0) start = 0;
        if (start >= (int)s.length()) return Value("");
        return Value(s.substr(start, len));
    }	
	else if (uname == "MID" || uname == "SUBSTR" || uname == "SUBSTRING") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}

	else if (uname == "GETASCIICODE" && ac == 2) {
		// 文字列中の特定の文字の文字コードを得る
		std::string s = args[0].toStr();
		int n = args[1].toInt();
		if ((int)s.size() <= n || n < 0) {
			// nが負の数だったり、文字数が足りなかったりする場合
			return Value(-1);
		}
		else {
			// n文字目の文字を得て、文字コードを数値としてとらえて返す
			const char *t = s.c_str();
			return Value((int)t[n]);
		}
	}
	else if (uname == "ASCIICODE$" && ac == 1) {
		// nを文字コードとみなして、その文字コード1文字の文字列を返す
		char s[2];

		s[0] = (char)args[0].toInt();
		s[1] = 0;
		return Value(s);
	}
	else if (uname == "ASCIICODE") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}
	else if (uname == "REPLACE$" && (ac == 2 || ac == 3)) {
		// 引数1の中から引数2を探し、引数3(省略された場合は空文字)に置換し、結果の文字列を返す
		std::string s  = args[0].toStr();			// 対象文字列
		std::string r1 = args[1].toStr();			// これを見つけたらr2に置換
		std::string r2 = ac == 3 ? args[2].toStr() : "";
		std::string::size_type r1len = r1.length(); // r1(引数2)の長さ
		std::string::size_type r2len = r2.length(); // r2(引数3)の長さ
		std::string::size_type p = 0;				// サーチ中の位置
		std::string::size_type rp = 0;				// r1が見つかった位置

		while(1) {
			rp = s.find(r1, p);
			if ( rp == std::string::npos ) {
				break;
			}
			else {
				s.replace(rp, r1len, r2);
				p = rp + r2len;
			}
		}

		// 置換結果を返す
		return Value(s);
	}
	else if (uname == "REPLACE") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}

	// --- 環境変数 ---
    else if (uname == "GETENV$" && ac == 1) {
		// envnameをWideCharに変換
		std::wstring wenvname(u8_to_u16(args[0].toStr()));

		// 環境変数の読み出し
		WCHAR buf[32767];
		if (GetEnvironmentVariableW(wenvname.c_str(), buf, 32767) > 0) {
			// WideCharから変換し、返却する
			std::wstring wenvdata(buf);
			return Value(u16_to_u8(wenvdata));
		}
		else {
			// 読みだせなかったら空文字を返却
			return Value("");
		}
    }
	else if (uname == "GETENV") {
		bNeedD = true;  // $が必要な場合はヒントを示せるようにする
	}

    else if (uname == "SETENV" && ac == 2) {
		// 環境変数の名前と設定する中身をWideCharへ変換
		std::wstring wenvname(u8_to_u16(args[0].toStr()));
		std::wstring wenvdata(u8_to_u16(args[1].toStr()));
		
		// 環境変数を設定
		BOOL res = SetEnvironmentVariableW(wenvname.c_str(), wenvdata.c_str());
        return Value(res ? 1 : 0);
    }


	// --- 指定された関数名は存在しない（$が必要な場合はヒントを示せるようにする） ---
	if (bNeedD) {
		/* エラー発生コールバック */
		char errmes[1025];
		wsprintfA(errmes, "Runtime error at line %d: Unknown Function Call:%s(args:%d). But %s$() exists.\n", iLine, uname.c_str(), ac, uname.c_str());
		errorCall(ERROR_UNKNOWN_FUNCD, iLine, errmes);
		g_context.status = EXEC_EXIT;
		return 0;
	}
	else {
		/* エラー発生コールバック */
		char errmes[1025];
		wsprintfA(errmes, "Runtime error at line %d: Unknown Function Call or Not enough arguments:%s(args:%d)\n", iLine, uname.c_str(), ac);
		errorCall(ERROR_UNKNOWN_FUNC, iLine, errmes);
		g_context.status = EXEC_EXIT;

		if (uname.back() == '$') {
			return "";
		}
		else {
			return 0;
		}
	}
}

// FuncCallNode
FuncCallNode::FuncCallNode(std::string* n) { name = *n; delete n; type = ND_FUNC_CALL; }
FuncCallNode::~FuncCallNode() { for(size_t i=0; i<args.size(); ++i) delete args[i]; }
void FuncCallNode::addArg(Node* n) { args.push_back(n); }
Value FuncCallNode::eval() {
#ifdef FR_DEBUG
	fprintf(stderr, "FuncCallNode::eval()\n");
#endif
    std::vector<Value> evalArgs;

    for(size_t i=0; i<args.size(); ++i) {
		evalArgs.push_back(args[i]->eval());
	}

    return CallBuiltin(name, evalArgs, this->line);
}

// CBCallNode
CBCallNode::CBCallNode(std::string* n) { name = *n; delete n; type = ND_CB_CALL; }
CBCallNode::~CBCallNode() { for(size_t i=0; i<args.size(); ++i) delete args[i]; }
void CBCallNode::addArg(Node* n) { args.push_back(n); }
Value CBCallNode::eval() {
#ifdef FR_DEBUG
	fprintf(stderr, "CBCallNode::eval()\n");
#endif
    if(!g_context.callback) return 0;
    std::vector<Value> evalArgs;
    for(size_t i=0; i<args.size(); ++i) evalArgs.push_back(args[i]->eval());
    FRCallbackData data;
    data.symbol = name.c_str();
    data.args = evalArgs.empty() ? NULL : &evalArgs[0];
    data.argCount = (int)evalArgs.size();

	//文字列のWideChar変換
	FRCallbackDataW wdata;
	std::wstring wsymbol = u8_to_u16(std::string(data.symbol));
	wdata.symbol = wsymbol.c_str();
	wdata.argCount = data.argCount;
	if (wdata.argCount == 0) {
		wdata.args = NULL; //引数なし
	}
	else {
		wdata.args = new ValueW[wdata.argCount];
		for(int i=0 ; i<wdata.argCount; ++i) {
			wdata.args[i].isString = data.args[i].isString;
			wdata.args[i].iVal = data.args[i].iVal;
			if (wdata.args[i].isString) {
				// 文字列の場合は文字コード変換
				wdata.args[i].sVal = u8_to_u16(data.args[i].sVal);
			}
		}
	}

	// 戻り値を格納するための領域を確保
	ValueW retValue = ValueW(0);
	wdata.retVal = &retValue;

	// コールバック呼び出し
	g_context.callback(&wdata); // 成功したらTRUE, 失敗したらFALSEを返すことになっているが、現状は戻り値を無視する

	// 戻り値をWideCharから変換
	if (wdata.retVal->isString) {
		return Value(u16_to_u8(wdata.retVal->sVal));
	}
	else {
		return Value(wdata.retVal->iVal);
	}

	
}

// ListNode
ListNode::ListNode() { type = ND_BLOCK; }
Value ListNode::eval() { return 0; }
void ListNode::push(Node* n) { nodes.push_back(n); }

// --- API実装 ---
typedef struct yy_buffer_state *YY_BUFFER_STATE;
extern YY_BUFFER_STATE yy_scan_string(const char *str);
extern void yy_delete_buffer(YY_BUFFER_STATE buffer);

int fr_script(const wchar_t* script, FR_SCRIPT_PARAM* param)
{
	yylineno = 1;
    if (!script) {
		if (param && param->ec) {
			param->ec(ERROR_INVALID_PARAM, -1, L"Invalid Parameter.");
		}
		return -1;
	}
    g_context.clear();
    g_context.callback = param ? param->cb : NULL;
    if (g_root) { delete g_root; g_root = NULL; }

    int len = WideCharToMultiByte(CP_UTF8, 0, script, -1, NULL, 0, NULL, NULL);
    if (len == 0) return 0;
    char* sScript = (char *)calloc(len+2, 1);
	if (sScript) {
		int ret;

		if (script[0] == 0xfeff) { // 冒頭がBOMなら読みとばす
			ret = WideCharToMultiByte(CP_UTF8, 0, script+1, -1, sScript, len, NULL, NULL);
		}
		else {
			ret = WideCharToMultiByte(CP_UTF8, 0, script, -1, sScript, len, NULL, NULL);
		}
		if (ret == 0) {
			param->ec(ERROR_INVALID_PARAM, -1, L"Script Convert Error.");
		}

		lstrcatA(sScript, "\n"); // 最終行に改行が付いていなかった場合に備え、最終行に改行を加えて文として成立させる

		// 各コールバック関数をグローバル変数へ代入
		g_context.errorCallBack = param ? param->ec : NULL;
		g_context.stepCallBack = param ? param->sc : NULL;
		if (param && param->pMsgBoxW) {
			g_context.pMsgBoxW = param->pMsgBoxW;
		}
		else {
			g_context.pMsgBoxW = MessageBoxW;
		}

		// ウィンドウハンドルを渡す
		g_context.hWnd = param ? param->hWnd : NULL;

		YY_BUFFER_STATE buf = yy_scan_string(sScript);

		int i = yyparse();
		if (i == 0 && g_root) {
			g_root->eval();
		}

		yy_delete_buffer(buf);
		free(sScript);
		int result = g_context.exitCode;
		if (g_root) { delete g_root; g_root = NULL; }
		return result;
	}
	else {
		if (param && param->ec) {
			param->ec(ERROR_OUT_OF_MEMORY, -1, L"Out of memory while translating script.");
		}
		return -1;
	}
}
