如何修改Boost Spirit规则,排除PureData对象的保留关键字解析
修改Boost Spirit规则以跳过PureData特殊保留名对象
需求与背景
我需要将PureData中的对象记录解析为通用PdObject结构体,相关定义与对象语法如下:
PdObject结构体与PureData对象语法
描述:定义PureData通用对象
语法:#X obj [x_pos] [y_pos] [object_name] [p1] [p2] [p3] [...];参数:
[x_pos]:窗口内水平位置[y_pos]:窗口内垂直位置[object_name]:对象名称(可选)[p1] [p2] [p3] [...]:对象参数(可选)
示例:#X obj 55 50; #X obj 132 72 trigger bang float;
已编写并测试可用的Boost Spirit规则,但存在bng、tgl、nbx等特殊保留名称的对象(示例如下),这类对象需要由另一规则解析为不同结构体,因此需要修改现有规则,使其不匹配这类保留名对象,留待其他语法处理:
#X obj 92 146 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000;
现有Boost Spirit规则
template <typename Iterator> struct PdObjectGrammar : qi::grammar<Iterator, PdObject()> { PdObjectGrammar() : PdObjectGrammar::base_type(start) { using namespace qi; start = skip(space)[objectRule]; pdStringRule = +(('\\' >> space) | (graph-lit(";"))); objectRule = "#X obj" >> int_ >> int_ >> -(pdStringRule) >> *(pdStringRule) >> ";"; BOOST_SPIRIT_DEBUG_NODES((start)(objectRule)(pdStringRule)) } private: qi::rule<Iterator, std::string()> pdStringRule; qi::rule<Iterator, PdObject()> start; qi::rule<Iterator, PdObject(), qi::space_type> objectRule; };
修改方案
核心思路是在匹配对象名称时排除指定的保留词,具体修改步骤如下:
- 定义保留名规则:创建匹配所有需要跳过的保留名称的规则,确保精确匹配完整单词。
- 修改字符串匹配逻辑:在
pdStringRule前添加逻辑非判断,若当前输入是保留名则匹配失败,让整个objectRule对这类特殊对象不生效。
修改后的规则代码:
template <typename Iterator> struct PdObjectGrammar : qi::grammar<Iterator, PdObject()> { PdObjectGrammar() : PdObjectGrammar::base_type(start) { using namespace qi; // 定义需要跳过的特殊保留名称,可按需扩展 reserved_names = lit("bng") | lit("tgl") | lit("nbx"); // 修改pdStringRule:先检查是否为保留名,是则匹配失败,否则正常匹配字符串 pdStringRule = !(reserved_names) >> +(('\\' >> space) | (graph - lit(";"))); objectRule = "#X obj" >> int_ >> int_ >> -(pdStringRule) >> *(pdStringRule) >> ";"; start = skip(space)[objectRule]; BOOST_SPIRIT_DEBUG_NODES((start)(objectRule)(pdStringRule)(reserved_names)) } private: qi::rule<Iterator, std::string()> pdStringRule; qi::rule<Iterator, PdObject()> start; qi::rule<Iterator, PdObject(), qi::space_type> objectRule; qi::rule<Iterator()> reserved_names; // 保留名匹配规则 };
关键修改说明
reserved_names使用lit()确保只匹配完整的保留名称,避免部分匹配的情况。!(reserved_names)是逻辑非操作,当输入为保留名时,pdStringRule匹配失败,进而导致整个objectRule匹配失败,这类特殊对象就会留给其他语法规则处理。
完整测试代码
#define BOOST_SPIRIT_DEBUG #include <boost/spirit/include/qi.hpp> #include <string> #include <vector> #include <fstream> namespace qi = boost::spirit::qi; struct PdObject { int xPos; int yPos; std::string name; std::vector<std::string> params; }; BOOST_FUSION_ADAPT_STRUCT( PdObject, xPos, yPos, name, params ) template <typename Iterator> struct PdObjectGrammar : qi::grammar<Iterator, PdObject()> { PdObjectGrammar() : PdObjectGrammar::base_type(start) { using namespace qi; // 定义特殊保留名称 reserved_names = lit("bng") | lit("tgl") | lit("nbx"); // 修改后的pdStringRule,排除保留名 pdStringRule = !(reserved_names) >> +(('\\' >> space) | (graph - lit(";"))); objectRule = "#X obj" >> int_ >> int_ >> -(pdStringRule) >> *(pdStringRule) >> ";"; start = skip(space)[objectRule]; BOOST_SPIRIT_DEBUG_NODES((start)(objectRule)(pdStringRule)(reserved_names)) } private: qi::rule<Iterator, std::string()> pdStringRule; qi::rule<Iterator, PdObject()> start; qi::rule<Iterator, PdObject(), qi::space_type> objectRule; qi::rule<Iterator()> reserved_names; }; int main(int argc, char** argv) { if(argc != 2) { std::cout << "Usage: " << argv[0] << " <PatchFile>" << std::endl; exit(1); } std::ifstream inputFile(argv[1]); std::string inputString(std::istreambuf_iterator<char>(inputFile), {}); PdObject msg; PdObjectGrammar<std::string::iterator> parser; bool success = qi::phrase_parse(inputString.begin(), inputString.end(), parser, boost::spirit::ascii::space, msg); std::cout << "Success: " << success << std::endl; return 0; }
内容的提问来源于stack exchange,提问作者stix
相关产品推荐
相关产品推荐

