スクリプト読み込みツール
NekoCannonのスクリプトを読み込む処理を作ってみました。
ただ、独自の実装のため、微妙に動作が異なりますが…。
例えば、
{key1=value1,key2=value2,key3=value3},
とすると、key3の値を読み込みません…。
このように、value3の後ろに「,」をつけると読み込めます。
{key1=value1,key2=value2,key3=value3,},
以下、自作の読み込み処理です。
/** * NekoCannonスクリプト読み込みツール */ #include <iostream> #include <fstream> #include <vector> #include <map> #include <string> using namespace std; struct Node { typedef vector<Node> NodeList; typedef map<string, NodeList> ChildMap; typedef pair<string, NodeList> ChildPair; string value; // 値 ChildMap childs; // 子ノードたち }; // ============================================================================ // 半角スペース・タブを削除 // @param 変換する文字列 // @return 空文字の場合falseを返す // ============================================================================ bool lstrip(string &str) { if(str.length() == 0) return false; char c = str.at(0); while(c == ' ' || c == '\t') { str = str.erase(0, 1); c = str.at(0); } if(str.length() == 0) return false; return true; } // ============================================================================ // テキスト読み込みの再帰関数 // @param ifs ファイルオブジェクト // @param line 行の文字列 // @param node ノード // ============================================================================ void reflexLoad(ifstream &ifs, string &line, Node &node) { string key = "DUMMY"; string dlmType = ""; while(!ifs.eof()) { // 下準備 if(!lstrip(line)) { // 空行 char tmp[256]; ifs.getline(tmp, 256); line = tmp; continue; } size_t nEq = line.find('='); size_t nList = line.find('['); size_t eList = line.find(']'); size_t nMap = line.find('{'); size_t eMap = line.find('}'); size_t nDlm = line.find(','); if(nEq == -1 && nList == -1 && eList == -1 && nMap == -1 && eMap == -1 && nDlm == -1) { // 空行 char tmp[256]; ifs.getline(tmp, 256); line = tmp; continue; } else { // 先頭区切り文字を取得 map<char*, size_t> idxMap; idxMap.insert(pair<char*, size_t>("nEq", nEq)); idxMap.insert(pair<char*, size_t>("nList", nList)); idxMap.insert(pair<char*, size_t>("eList", eList)); idxMap.insert(pair<char*, size_t>("nMap", nMap)); idxMap.insert(pair<char*, size_t>("eMap", eMap)); idxMap.insert(pair<char*, size_t>("nDlm", nDlm)); int nMin = 256; for(map<char*, size_t>::iterator iter = idxMap.begin(); iter != idxMap.end(); ++iter) { if(iter->second == -1) continue; if(iter->second < nMin) { nMin = iter->second; dlmType = iter->first; } } } // 解析開始 if(dlmType.compare("nEq") == 0) { // 『=』 key = line.substr(0, nEq); line = line.substr(nEq+1); continue; } else if(dlmType.compare("nList") == 0) { // 『[』 if(node.childs.count(key) == 0) { // ノードリスト作成 Node::NodeList nodeList; node.childs.insert(Node::ChildPair(key, nodeList)); } line = line.substr(nList+1); Node childNode; reflexLoad(ifs, line, childNode); node.childs.find(key)->second.push_back(childNode); continue; } else if(dlmType.compare("eList") == 0) { // 『]』 line = line.substr(eList+1); return; } else if(dlmType.compare("nMap") == 0) { // 『{』 line = line.substr(nMap+1); reflexLoad(ifs, line, node); continue; } else if(dlmType.compare("eMap") == 0) { // 『}』 line = line.substr(eMap+1); return; } else if(dlmType.compare("nDlm") == 0) { // 『,』 if(node.childs.count(key) == 0) { // ノードリスト作成 Node::NodeList nodeList; node.childs.insert(Node::ChildPair(key, nodeList)); } Node childNode; childNode.value = line.substr(0, nDlm); line = line.substr(nDlm+1); if(childNode.value.length() != 0) { node.childs.find(key)->second.push_back(childNode); } continue; } else { throw "Syntax Error"; } } } // ============================================================================ // ノードをデバッグ出力 // @param node ノード // ============================================================================ int g_rank = 0; void DebugPrint(Node &node) { g_rank++; cout << "rank ->" << g_rank << endl; cout << "value->" << node.value.c_str() << endl; Node::ChildMap::iterator iter = node.childs.begin(); while(iter != node.childs.end()) { cout << "key ->" << iter->first.c_str() << endl; Node::NodeList list = iter->second; for(unsigned int i = 0; i < list.size(); i++) { DebugPrint(list.at(i)); } iter++; } cout << "-----------" << endl; g_rank--; } // ============================================================================ // テストドライバ // ============================================================================ void main() { ifstream ifs("data.txt"); if(ifs.fail()) { return; } char tmp[256]; ifs.getline(tmp, 256); // 一行目は空読みしてね♪ ifs.getline(tmp, 256); string line(tmp); Node node; // こいつに全部はいるよ reflexLoad(ifs, line, node); // 解析開始 ifs.close(); cout << "---result---" << endl; DebugPrint(node); // 使い方♪ cout << "type ->" << node.childs.find("type")->second.at(0).value << endl; cout << "max_enemy->" << node.childs.find("max_enemy")->second.at(0).value << endl; cout << "posx ->" << node.childs.find("posx")->second.at(0).value << endl; cout << "scale ->" << node.childs.find("scale")->second.at(0).value << endl; cout << "enemies ->" << endl; cout << " name :" << node.childs.find("enemies")->second.at(0).childs.find("name")->second.at(0).value << endl; cout << " x :" << node.childs.find("enemies")->second.at(0).childs.find("x")->second.at(0).value << endl; cout << " life :" << node.childs.find("enemies")->second.at(0).childs.find("life")->second.at(0).value << endl; cout << " scale:" << node.childs.find("enemies")->second.at(0).childs.find("scale")->second.at(0).value << endl; cout << "messages ->" << endl; Node::NodeList list = node.childs.find("messages")->second.at(0).childs.find("DUMMY")->second; for(unsigned int i = 0; i < list.size(); i++) { cout << " " << list.at(i).value << endl; } }
こいつ(data.txt)を読み込むと、
{ type=0, max_enemy=3, posx=5, scale=30, enemies=[ {name=Bubble,x=23,life=1,scale=6,}, ], messages=[ "kenmoはこのプログラムを書くのに、", "まるまる2日もかかってしまいましたとさ", "…もうちょっと、構文解析の勉強をしないと、", "ダメですね。", ], }
こんな感じで出力されます。
---result--- rank ->1 value-> key ->enemies rank ->2 value-> key ->DUMMY key ->life rank ->3 value->1 ----------- key ->name rank ->3 value->Bubble ----------- key ->scale rank ->3 value->6 ----------- key ->x rank ->3 value->23 ----------- ----------- key ->max_enemy rank ->2 value->3 ----------- key ->messages rank ->2 value-> key ->DUMMY rank ->3 value->"kenmoはこのプログラムを書くのに、" ----------- rank ->3 value->"まるまる2日もかかってしまいましたとさ" ----------- rank ->3 value->"…もうちょっと、構文解析の勉強をしないと、" ----------- rank ->3 value->"ダメですね。" ----------- ----------- key ->posx rank ->2 value->5 ----------- key ->scale rank ->2 value->30 ----------- key ->type rank ->2 value->0 ----------- ----------- type ->0 max_enemy->3 posx ->5 scale ->30 enemies -> name :Bubble x :23 life :1 scale:6 messages -> "kenmoはこのプログラムを書くのに、" "まるまる2日もかかってしまいましたとさ" "…もうちょっと、構文解析の勉強をしないと、" "ダメですね。"
リストとマップが自由にネストできるので、
なかなか応用が利くのではないかと、思います。