/// <summary> /// 関数をシステムに追加する /// </summary> /// <param name="name">関数の名前</param> /// <param name="argdef">引数の定義</param> /// <param name="resultType">関数の戻り値</param> /// <param name="f">実際に処理を行うC#のdelegate</param> /// <param name="desc">関数の説明</param> /// <param name="kana">命令のよみがな</param> protected void addFunc(string name, string argdef, NakoVarType resultType, SysCallDelegate f, string desc, string kana) { name = NakoToken.TrimOkurigana(name); NakoAPIFunc s = new NakoAPIFunc(name, argdef, resultType, f); NakoAPIFuncBank.Instance.AddFunc(s); }
/// <summary> /// ユーザー関数を登録する /// </summary> protected void RegisterUserCall() { // tokenでDEFINE FUNKが見つかったらEOLまでを最上部に追加 if (tokens != null) { tokens.MoveTop(); while (!tokens.IsEOF()) { NakoToken tok = tokens.CurrentToken; if (tok.Type == NakoTokenType.DEF_FUNCTION) { int index = 0; while (tok.Type != NakoTokenType.SCOPE_BEGIN) { NakoToken insertToken = new NakoToken(tok.Type, tok.LineNo, tok.IndentLevel, tok.Value); if (tok.Type == NakoTokenType.DEF_FUNCTION) { insertToken.Type = NakoTokenType.DEF_FUNCTION_ALIASE; } tokens.Insert(index, insertToken); index++; tokens.MoveNext(); tokens.MoveNext(); tok = tokens.CurrentToken; } tokens.Insert(index, tok); } tokens.MoveNext(); } tokens.MoveTop(); } }
/// <summary> /// 関数を追加 /// </summary> /// <param name="name"></param> /// <param name="argdef"></param> /// <param name="resultType"></param> /// <param name="f"></param> /// <param name="desc"></param> /// <param name="kana"></param> public void AddFunc(string name, string argdef, NakoVarType resultType, NakoPlugin.SysCallDelegate f, string desc, string kana) { name = NakoToken.TrimOkurigana(name); NakoAPIFunc s = new NakoAPIFunc(name, argdef, resultType, f); s.PluginInstance = PluginInstance; this.AddFuncToList(s); }
//> _for : WORD _value _value FOR _scope_or_statement //> ; private bool _for() { NakoToken tokVar = null; TokenTry(); // local variable if (!Accept(NakoTokenType.WORD)) { return(false); } tokVar = tok.CurrentToken; if (!(tokVar.Josi == "を" || tokVar.Josi == "で")) { return(false); } tok.MoveNext(); // get argument * 2 if (!_value()) { TokenBack(); return(false); } if (!_value()) { TokenBack(); return(false); } NakoNodeFor fornode = new NakoNodeFor(); NakoNodeVariable v = new NakoNodeVariable(); fornode.loopVar = v; v.scope = NakoVariableScope.Local; v.Token = tokVar; v.varNo = localVar.CreateVar(tokVar.Value); fornode.nodeTo = calcStack.Pop(); fornode.nodeFrom = calcStack.Pop(); if (!Accept(NakoTokenType.FOR)) { TokenBack(); return(false); } TokenFinally(); tok.MoveNext(); fornode.nodeBlocks = _scope_or_statement(); this.parentNode.AddChild(fornode); lastNode = fornode; return(true); }
//> _callfunc : { [{_value}] FUNCTION_NAME } //> ; private bool _callfunc_stmt() { NakoToken startToken = tok.CurrentToken; TokenTry(); while (!tok.IsEOF()) { WriteLog(tok.CurrentToken.ToStringForDebug()); if (Accept(NakoTokenType.EOL)) { tok.MoveNext(); break; } if (!_value()) { TokenBack(); return(false); } } TokenFinally(); //TODO: _callfunc_stmt // 計算用スタックの管理 if (calcStack.Count > 0) { while (calcStack.Count > 0) { NakoNode n = calcStack.Shift(); if (!(n is NakoNodeCallFunction)) { // 余剰スタックの値を得る string r = ""; for (int i = 0; i < calcStack.Count; i++) { if (i != 0) { r += ","; } NakoNode n0 = calcStack[i]; r += n0.ToTypeString(); } throw new NakoParserException( "無効な式か値があります。(余剰スタックのチェック):" + r, startToken); } parentNode.AddChild(n); parentNode.AddChild(new NakoNodePop()); } } // ここで本来ならば // スタックを空にする or 余剰なスタックがあればエラーにするのが筋だが... // 連続関数呼び出しに対応するためエラーにしない return(true); }
//> _arglist : '(' { _value } ')' //> ; private bool _arglist(NakoNodeCallFunction node) { NakoToken firstT = tok.CurrentToken; int nest = 0; // '(' から始まるかチェック if (!Accept(NakoTokenType.PARENTHESES_L)) { return(false); } tok.MoveNext(); // skip '(' nest++; // '(' .. ')' の間を取りだして別トークンとする NakoTokenList par_list = new NakoTokenList(); while (!tok.IsEOF()) { if (Accept(NakoTokenType.PARENTHESES_R)) { nest--; if (nest == 0) { tok.MoveNext(); break; } } else if (Accept(NakoTokenType.PARENTHESES_L)) { nest++; } par_list.Add(tok.CurrentToken); tok.MoveNext(); } // 現在のトークン位置を保存 tok.Save(); NakoTokenList tmp_list = tok; tok = par_list; tok.MoveTop(); while (!tok.IsEOF()) { if (!_value()) { throw new NakoParserException("関数の引数の配置エラー。", firstT); } } // トークンリストを復元 tok = tmp_list; tok.Restore(); return(true); }
//> _variable_elements : '[' _value ']' //> | '\' _value //> ; private bool _variable_elements(NakoNodeVariable n) { NakoToken firstT = tok.CurrentToken; // 配列アクセス? if (!Accept(NakoTokenType.BRACKETS_L) && !Accept(NakoTokenType.YEN)) { return(false); } NakoTokenType t; while (!tok.IsEOF()) { t = tok.CurrentTokenType; if (t == NakoTokenType.BRACKETS_L) { tok.MoveNext(); // skip ']' if (!_value()) { throw new NakoParserException("変数要素へのアクセスで要素式にエラー。", firstT); } if (!Accept(NakoTokenType.BRACKETS_R)) { throw new NakoParserException("変数要素へのアクセスで閉じ角カッコがありません。", firstT); } tok.MoveNext(); // skip ']' n.AddChild(calcStack.Pop()); } else // t == NakoTokenType.YEN { tok.MoveNext(); // skip '\' if (!_value_nojfunc()) { throw new NakoParserException("変数要素へのアクセスで要素式にエラー。", firstT); } n.AddChild(calcStack.Pop()); } // 引き続き、変数要素へのアクセスがあるかどうか if (Accept(NakoTokenType.BRACKETS_L)) { continue; } if (Accept(NakoTokenType.YEN)) { continue; } break; } return(true); }
//> _if_stmt : IF _value THEN [EOL] _scope_or_statement [ ELSE _scope_or_statement ] //> ; private bool _if_stmt() { if (!Accept(NakoTokenType.IF)) { return(false); } tok.MoveNext(); // skip IF NakoNodeIf ifnode = new NakoNodeIf(); // _value NakoToken t = tok.CurrentToken; if (!_value()) { throw new NakoParserException("もし文で比較式がありません。", t); } ifnode.nodeCond = calcStack.Pop(); // THEN (日本語では、助詞なのでたぶんないはずだが...) if (Accept(NakoTokenType.THEN)) { tok.MoveNext(); } while (Accept(NakoTokenType.EOL)) { tok.MoveNext(); } // TRUE ifnode.nodeTrue = _scope_or_statement(); while (Accept(NakoTokenType.EOL)) { tok.MoveNext(); } // FALSE if (Accept(NakoTokenType.ELSE)) { tok.MoveNext(); // skip ELSE while (Accept(NakoTokenType.EOL)) { tok.MoveNext(); } ifnode.nodeFalse = _scope_or_statement(); } this.parentNode.AddChild(ifnode); this.lastNode = ifnode; return(true); }
//> _def_function_args : empty //> | '(' { WORD } ')' FUNCTION_NAME //> | { WORD } FUNCTION_NAME //> | FUNCTION_NAME '(' { WORD } ')' //> ; private bool _def_function_args(NakoFunc func) { NakoToken firstT = tok.CurrentToken; NakoTokenList argTokens = new NakoTokenList(); bool argMode = false; NakoToken funcName = null; // 関数の引数宣言を取得する while (!tok.IsEOF()) { // '(' .. ')' の中は全部、関数の引数です if (argMode) { if (Accept(NakoTokenType.PARENTHESES_R)) { argMode = false; tok.MoveNext(); continue; } argTokens.Add(tok.CurrentToken); tok.MoveNext(); continue; } if (Accept(NakoTokenType.PARENTHESES_L)) { tok.MoveNext(); argMode = true; continue; } if (Accept(NakoTokenType.SCOPE_BEGIN)) { break; } if (Accept(NakoTokenType.FUNCTION_NAME)) { funcName = tok.CurrentToken; tok.MoveNext(); continue; } argTokens.Add(tok.CurrentToken); tok.MoveNext(); } if (funcName == null) { throw new NakoParserException("関数名がありません。", firstT); } func.name = funcName.GetValueAsName(); //TODO: check namespace and class name func.args.analizeArgTokens(argTokens); return(true); }
private bool _try_stmt() { if (!Accept(NakoTokenType.TRY)) { return(false); } tok.MoveNext(); // skip IF NakoNodeTry trynode = new NakoNodeTry(); NakoToken t = tok.CurrentToken; while (Accept(NakoTokenType.EOL)) { tok.MoveNext(); } // TRY trynode.nodeTry = _scope_or_statement(); while (Accept(NakoTokenType.EOL)) { tok.MoveNext(); } // CATCH //TODO ○○のエラーならば〜☆☆のエラーならば〜への対応 //TODO ○○や☆☆のエラーならばへの対応 while (Accept(NakoTokenType.CATCH)) { //TODO:catchの例外種別を取得 tok.MoveNext(); //skip catch while (Accept(NakoTokenType.EOL)) { tok.MoveNext(); } //while (calcStack.Count > 0) { // calcStack.Pop (); //} NakoNode nodeCatch = _scope_or_statement(); //TODO Add trynode.nodeCatch = nodeCatch; } //TODO set finally this.parentNode.AddChild(trynode); this.lastNode = trynode; return(true); }
//> _def_function : DEF_FUNCTION _def_function_args _scope //> ; private bool _def_function() { if (!Accept(NakoTokenType.DEF_FUNCTION)) { return(false); } NakoToken t = tok.CurrentToken; tok.MoveNext(); // '*' NakoFunc userFunc = new NakoFunc(); userFunc.funcType = NakoFuncType.UserCall; // 引数 + 関数名の取得 _def_function_args(userFunc); // ブロックの取得 PushFrame(); NakoNodeDefFunction funcNode = new NakoNodeDefFunction(); funcNode.func = userFunc; parentNode = funcNode.funcBody = new NakoNode(); funcNode.RegistArgsToLocalVar(); localVar = funcNode.localVar; if (!_scope()) { throw new NakoParserException("関数定義中のエラー。", t); } PopFrame(); // グローバル変数に登録 NakoVariable v = new NakoVariable(); v.SetBody(funcNode, NakoVarType.UserFunc); globalVar.CreateVar(userFunc.name, v); // 関数の宣言は、ノードのトップ直下に追加する if (!this.topNode.hasChildren()) { this.topNode.AddChild(new NakoNode()); } this.topNode.Children.Insert(0, funcNode); return(true); }
//> _blocks : empty //> | { _statement | _eol } //> ; private bool _blocks() { if (tok.IsEOF()) { return(true); } NakoToken tBlockTop = tok.CurrentToken; NakoToken t; while (!tok.IsEOF()) { // ブロックを抜けるキーワードをチェック if (Accept(NakoTokenType.SCOPE_END)) { return(true); } if (Accept(NakoTokenType.KOKOMADE)) { return(true); } // ブロック要素を繰り返し評価 t = tok.CurrentToken; if (_statement()) { continue; } if (_eol()) { continue; } throw new NakoParserException("ブロックの解析エラー", t); } return(true); }
/// <summary> /// 引数の定義文字列を読んで、関数の引数として登録する /// </summary> public void analizeArgTokens(NakoTokenList tokens) { bool optMode = false; ArgOpt argOpt = new ArgOpt(); for (int i = 0; i < tokens.Count; i++) { NakoToken tok = tokens[i]; NakoFuncArg arg = null; // オプション指定モード(optMode) の on/off if (tok.Type == NakoTokenType.BRACES_L) { // オプションの初期化 optMode = true; argOpt.Init(); continue; } if (tok.Type == NakoTokenType.BRACES_R) { optMode = false; continue; } if (optMode) { if (tok.Type == NakoTokenType.WORD) { string opt = (string)tok.Value; if (opt == "参照渡し") { argOpt.varBy = VarByType.ByRef; } if (opt == "整数") //TODO:数値 { NakoToken checkToken = tokens [i + 1]; if (checkToken.Type == NakoTokenType.EQ) { checkToken = tokens [i + 2]; if (checkToken.Type == NakoTokenType.INT) { argOpt.defaultValue = int.Parse(checkToken.Value); } } } if (opt == "文字列") { NakoToken checkToken = tokens [i + 1]; if (checkToken.Type == NakoTokenType.EQ) { checkToken = tokens [i + 2]; if (checkToken.Type == NakoTokenType.STRING || checkToken.Type == NakoTokenType.STRING_EX || checkToken.Type == NakoTokenType.WORD) { argOpt.defaultValue = (string)checkToken.Value; } } } } else { //find type string type = (string)tok.Value; int index = NakoAPIFuncBank.Instance.FuncList.FindIndex(delegate(NakoAPIFunc obj) { return(obj.PluginInstance.Name == type); }); if (index > 0) { argOpt.type = type; } } continue; } // WORD if (tok.Type == NakoTokenType.WORD) { int idx = indexOfName(tok.Value); if (idx < 0) { arg = new NakoFuncArg(); arg.name = tok.Value; arg.varBy = argOpt.varBy; arg.defaultValue = argOpt.defaultValue; arg.type = argOpt.type; arg.AddJosi(tok.Josi); this.Add(arg); argOpt.Init(); } else { arg = this[idx]; arg.AddJosi(tok.Josi); } } if (tok.Type == NakoTokenType.OR || tok.Type == NakoTokenType.OR_OR) { continue; } } }
/// <summary> /// 変数を追加 /// </summary> /// <param name="name"></param> /// <param name="value"></param> /// <param name="desc"></param> /// <param name="kana"></param> public void AddVar(string name, object value, string desc, string kana) { name = NakoToken.TrimOkurigana(name); this.AddVarToList(name, value); }
//> _callfunc : FUNCTION_NAME //> | FUNCTION_NAME _arglist //> ; private bool _callfunc() { NakoToken t = tok.CurrentToken; if (!Accept(NakoTokenType.FUNCTION_NAME)) { return(false); } tok.MoveNext(); // skip FUNCTION_NAME string fname = t.GetValueAsName(); NakoVariable var = globalVar.GetVar(fname); if (var == null) { throw new NakoParserException("関数『" + fname + "』が見あたりません。", t); } // NakoNodeCallFunction callNode = new NakoNodeCallFunction(); NakoFunc func = null; callNode.Token = t; if (var.Type == NakoVarType.SystemFunc) { int funcNo = (int)var.Body; func = NakoAPIFuncBank.Instance.FuncList[funcNo]; callNode.func = func; } else { NakoNodeDefFunction defNode = (NakoNodeDefFunction)var.Body; func = callNode.func = defNode.func; callNode.value = defNode; } // --------------------------------- if (Accept(NakoTokenType.PARENTHESES_L)) { _arglist(callNode); // TODO ここで引数の数をチェックする処理 } // 引数の数だけノードを取得 for (int i = 0; i < func.ArgCount; i++) { NakoFuncArg arg = func.args[func.ArgCount - i - 1]; NakoNode argNode; if (arg.defaultValue != null && calcStack.Count < (func.ArgCount - i)) //初期値があって引数が無い場合に引数に初期値を与える { argNode = new NakoNodeConst(); argNode.value = arg.defaultValue; if (arg.defaultValue is int) { argNode.type = NakoNodeType.INT; argNode.Token = new NakoToken(NakoTokenType.INT); } else if (arg.defaultValue is string) { argNode.type = NakoNodeType.STRING; argNode.Token = new NakoToken(NakoTokenType.STRING); } } else { argNode = calcStack.Pop(arg); } if (arg.varBy == VarByType.ByRef) { if (argNode.type == NakoNodeType.LD_VARIABLE) { ((NakoNodeVariable)argNode).varBy = VarByType.ByRef; } } callNode.AddChild(argNode); } // --------------------------------- // 計算スタックに関数の呼び出しを追加 calcStack.Push(callNode); this.lastNode = callNode; return(true); }
/// <summary> /// 構文解析エラーを出す /// </summary> /// <param name="message"></param> /// <param name="tok"></param> public NakoParserException(string message, NakoToken tok) : base(message + ":" + tok.ToStringForDebug()) { }
/// <summary> /// 引数の定義文字列を読んで、関数の引数として登録する /// </summary> public void analizeArgTokens(NakoTokenList tokens) { bool optMode = false; ArgOpt argOpt = new ArgOpt(); for (int i = 0; i < tokens.Count; i++) { NakoToken tok = tokens[i]; NakoFuncArg arg = null; // オプション指定モード(optMode) の on/off if (tok.Type == NakoTokenType.BRACES_L) { // オプションの初期化 optMode = true; argOpt.Init(); continue; } if (tok.Type == NakoTokenType.BRACES_R) { optMode = false; continue; } if (optMode) { if (tok.Type == NakoTokenType.DIM_INT) //ユーザー定義関数の「整数」はDIM INTと判定されるので、WORDに直す { tok.Type = NakoTokenType.WORD; } if (tok.Type == NakoTokenType.WORD) { string opt = (string)tok.Value; if (opt == "参照渡し") { argOpt.varBy = VarByType.ByRef; } if (opt == "整数") //TODO:数値 { NakoToken checkToken = tokens [i + 1]; if (checkToken.Type == NakoTokenType.EQ) { checkToken = tokens [i + 2]; if (checkToken.Type == NakoTokenType.INT) { argOpt.defaultValue = int.Parse(checkToken.Value); } } } if (opt == "文字列") { NakoToken checkToken = tokens [i + 1]; if (checkToken.Type == NakoTokenType.EQ) { checkToken = tokens [i + 2]; if (checkToken.Type == NakoTokenType.STRING || checkToken.Type == NakoTokenType.STRING_EX || checkToken.Type == NakoTokenType.WORD) { argOpt.defaultValue = (string)checkToken.Value; } } } if (opt == "関数") //関数定義が引数の場合。{関数(2)}とか表記(n)はn個引数があるという意味。初期値は無いはずなので、引数の個数をdefaultValueプロパティに入れているが、その点は修正の必要があるかもしれない。 { argOpt.defaultValue = 0; argOpt.type = NakoFuncType.UserCall.ToString(); for (int j = i + 1; j < tokens.Count; j++) { if (tokens [j].Type == NakoTokenType.PARENTHESES_L) { j++; NakoToken argCountToken = tokens [j]; argOpt.defaultValue = int.Parse(argCountToken.Value); j++; } if (tokens [j].Type == NakoTokenType.BRACES_R) { break; } } } } else { //find type string type = (string)tok.Value; int index = NakoAPIFuncBank.Instance.FuncList.FindIndex(delegate(NakoAPIFunc obj) { return(obj.PluginInstance.Name == type); }); if (index > 0) { argOpt.type = type; } } continue; } // WORD if (tok.Type == NakoTokenType.WORD) { int idx = indexOfName(tok.Value); if (idx < 0) { arg = new NakoFuncArg(); arg.name = tok.Value; arg.varBy = argOpt.varBy; arg.defaultValue = argOpt.defaultValue; arg.type = argOpt.type; arg.AddJosi(tok.Josi); this.Add(arg); argOpt.Init(); } else { arg = this[idx]; arg.AddJosi(tok.Josi); } } if (tok.Type == NakoTokenType.OR || tok.Type == NakoTokenType.OR_OR) { continue; } } }
protected void addVar(string name, Object value, string desc, string kana) { name = NakoToken.TrimOkurigana(name); NakoAPIFuncBank.Instance.AddVar(name, value); }
//> _def_variable : WORD (DIM_VARIABLE|DIM_NUMBER|DIM_INT|DIM_STRING|DIM_ARRAY) [=_value] //> ; private bool _def_variable() { if (!Accept(NakoTokenType.WORD)) { return(false); } NakoVarType st = NakoVarType.Object; switch (tok.NextTokenType) { case NakoTokenType.DIM_VARIABLE: st = NakoVarType.Object; break; case NakoTokenType.DIM_NUMBER: st = NakoVarType.Double; break; case NakoTokenType.DIM_INT: st = NakoVarType.Int; break; case NakoTokenType.DIM_STRING: st = NakoVarType.String; break; case NakoTokenType.DIM_ARRAY: st = NakoVarType.Array; break; default: return(false); } NakoToken t = tok.CurrentToken; int varNo = localVar.CreateVar(t.GetValueAsName()); NakoVariable v = localVar.GetVar(varNo); v.SetBody(null, st); tok.MoveNext(); // skip WORD tok.MoveNext(); // skip DIM_xxx // 変数の初期化があるか? if (!Accept(NakoTokenType.EQ)) { return(true); // なければ正常値として戻る } tok.MoveNext(); // skip EQ if (!_value()) { throw new NakoParserException("変数の初期化文でエラー。", t); } // 代入文を作る NakoNodeLet let = new NakoNodeLet(); let.VarNode = new NakoNodeVariable(); let.VarNode.varNo = varNo; let.VarNode.scope = NakoVariableScope.Local; let.ValueNode.AddChild(calcStack.Pop()); this.parentNode.AddChild(let); return(true); }