我在PureData中有以下对象记录的定义,我需要能够将其解析为我的通用PdObject结构:
Description:
Defines an object
Syntax:
#X obj [x_pos] [y_pos] [object_name] [p1] [p2] [p3] [...];\r\n
Parameters:
[x_pos] - horizontal position within the window
[y_pos] - vertical position within the window
[object_name] - name of the object (optional)
[p1] [p2] [p3] [...] the parameters of the object (optional)
Example:
#X obj 55 50;
#X obj 132 72 trigger bang float;
我创建了以下经过测试有效的增强精神规则:
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;
};
但是,也有一些特殊的“保留名称”不能使用,例如 “bng”,“tgl”,“nbx”, 等。
例如,下面是另一种类型的“obj”,它使用了一个保留名称关键字,必须通过不同的规则单独解析:
#X obj 92 146 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000;
我如何修改我之前的qi规则来 * 不 * 解析上面的字符串,并将其留给另一个语法来检查(这将把它解析为不同的结构体)?
后记:
我对PdObjectGrammar的完整测试是:
#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;
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;
};
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;
}
1条答案
按热度按时间8yparm6h1#
在某种程度上,“关键词”不是语法的一部分,而是一种语义检查。
语法处理关键字的方式并不统一,例如,C++有许多标识符,它们只是在上下文中保留的。
简而言之,你只需要在代码中表达你的约束,或者在事后(对解析的结果)验证语义。
标签:Live
或Live
符号
你可以通过为它定义一个符号来使它更优雅、更可维护、更高效:Live
区分关键词
这里有一个缺陷。当用户以内置列表开始命名对象时,例如
bngalore
或vslander
,内置列表将匹配,因此名称将被拒绝:Live为了说明这一点,请确保我们在词素边界上:Live
不管用!
那是因为语法有缺陷。在你的辩护中,规范是非常草率的。它是 * 那些语法之一 * 好吧。
由于所有这些都是可选的,你应该问自己,当有参数时,解析器是如何知道
name
被省略的?就我所知,解析器永远不会知道,所以当名字被省略时,就不可能有参数了。我们可以表示:Live
哦,不,现在整个
(string >> *string)
都兼容 * 只是 * name属性...:这里我建议调整AST以反映解析的语法:
现在,它确实正确地传播了属性:Live,注意输出中的额外子对象(
()
):一路走来
作为一个专业提示,不要像规范那样草率地实现解析器。很可能,你只是想用专用的AST类型和同上规则解析不同的对象类型。
对于非常高级的/可插入的语法,您可以根据名称符号分派规则,这就是众所周知的Nabialek技巧。
让我们推广我们的
object
规则:现在让我们演示VSL规则,以及泛型对象:
Generic仍然是我们以前拥有的:
让我们粗略地看看
Vslider
:当然,我们需要一些帮手:
AST类型:
把这些放在一起:
完整Demo
**第一次
打印
注意我们默认情况下是如何将
bng
解析为Generic
的,这仅仅是因为我们还没有为它添加定义规则。Live:这基本上是从PureData语法文档中1:1复制粘贴。
init
,send
,receive
,label
,x_off
,y_off
,font
,fontsize
,bg_color
,fg_color
和label_color
的重复......但我将把它留给读者作为驱魔。*