就调试而言,可以使用正常的中断和监视方法。不过,由于规则的格式设置方式,这会变得很困难。如果您按照精神示例进行格式化(〜每行一个解析器,每行一个 phoenix 语句),断点将提供更多信息。
你的数据结构没有办法区分A()
from SOME
因为它们都是叶子(如果我遗漏了什么,请告诉我)。从您的变体评论来看,我认为这不是您的意图,因此为了区分这两种情况,我添加了一个bool commandFlag
MockExpressionNode 的成员变量(true 为A()
和假的SOME
),带有相应的融合适配器线。
具体来说,对于代码,您需要将启动规则传递给基本构造函数,即:
InputGrammar() : InputGrammar::base_type(instruction) {...}
这是语法的入口点,也是您没有解析任何数据的原因。我很惊讶它没有它就编译了,我认为语法类型需要与第一条规则的类型匹配。即便如此,这仍然是一个方便遵循的约定。
For the tag
规则,实际上有两个解析器qi::char_("a-zA-Z_")
,这是 _1 类型char
and *qi::char_("a-zA-Z_0-9")
这是 _2 的类型(基本上)vector<char>
。在没有自动规则的情况下不可能将它们强制转换为字符串,但可以通过将规则附加到每个解析的字符来完成:
tag = qi::char_("a-zA-Z_")
[ at_c<0>(qi::_val) = qi::_1 ];
>> *qi::char_("a-zA-Z_0-9") //[] has precedence over *, so _1 is
[ at_c<0>(qi::_val) += qi::_1 ]; // a char rather than a vector<char>
然而,让精神来进行这种转换要干净得多。因此定义一个新规则:
qi::rule< Iterator , std::string(void) , ascii::space_type > identifier;
identifier %= qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
不用担心;)。那么标签就变成了
tag = identifier
[
at_c<0>(qi::_val) = qi::_1,
ph::at_c<2>(qi::_val) = false //commandFlag
]
对于命令来说,第一部分很好,但是有一些问题(*instruction >> ",")[ push_back( at_c<1>(qi::_val) , qi::_1 ) ]
。这将解析零个或多个后跟“,”的指令规则。它还尝试将其推回vector<MockExpressionNode>
(也不知道为什么会编译,也许由于缺少启动规则而没有实例化?)。我认为您想要以下内容(带有标识符修改):
command =
identifier
[
ph::at_c<0>(qi::_val) = qi::_1,
ph::at_c<2>(qi::_val) = true //commandFlag
]
>> "("
>> -(instruction % ",")
[
ph::at_c<1>(qi::_val) = qi::_1
]
>> ")";
这使用可选运算符-
和列表运算符%
,后者相当于instruction >> *("," >> instruction)
。然后,phoenix 表达式将向量直接分配给结构成员,但您也可以将操作直接附加到指令匹配并使用 push_back。
指令规则很好,我只是提到它相当于instruction %= (command|tag)
.
最后一件事,如果两者实际上没有区别的话A()
and SOME
(即你的原始结构没有commandFlag
),您可以仅使用自动规则编写此解析器:
template< typename Iterator , typename ExpressionAST >
struct InputGrammar : qi::grammar<Iterator, ExpressionAST(), ascii::space_type> {
InputGrammar() : InputGrammar::base_type( command ) {
identifier %=
qi::char_("a-zA-Z_")
>> *qi::char_("a-zA-Z_0-9");
command %=
identifier
>> -(
"("
>> -(command % ",")
>> ")");
}
qi::rule< Iterator , std::string(void) , ascii::space_type > identifier;
qi::rule< Iterator , ExpressionAST(void) , ascii::space_type > command;
};
这是使用紧密模拟输入的融合包裹结构的一大好处。