带船长的Boost.Qi规则与“."不匹配特点 [英] Boost.Qi rule with skipper does not match '.' character
问题描述
所以我有以下qi队长:
So I have the following qi skipper:
template<typename Iterator> struct verilog_skipper :
public qi::grammar<Iterator> {
verilog_skipper() : verilog_skipper::base_type(skip) {
namespace phx = boost::phoenix;
skip = qi::ascii::space | qi::eol | line_comment;
line_comment = (qi::lit("//") >> *(qi::char_ - qi::eol) >> *(qi::eol));
}
qi::rule<Iterator> skip;
qi::rule<Iterator> line_comment;
};
和以下齐语法:
template <typename Iterator,
typename Skipper = verilog_skipper<Iterator> struct verilog_grammer :
qi::grammar<Iterator, Skipper> {
verilog_ast ckt_ast;
verilog_grammer()
: verilog_grammer::base_type(module) {
namespace phx = boost::phoenix;
module = (module_definition >> statements >> qi::lit("endmodule"));
statements = statement % ';';
statement = (input_wires | instance);
module_definition = (qi::lit("module") >> ident >> qi::char_('(')
>> ident_list >> qi::char_(')') >> ';' );
input_wires = (qi::lit("input") >> ident_list);
instance = (ident >> ident >>
qi::char_('(') >> connection_pair_list >> qi::char_(')'));
connection_pair_list = connection_pair % ',';
connection_pair = (qi::char_('.')[phx::bind(&found_smth)]
>> ident >> qi::char_('(') >> ident >> qi::char_(')'));
ident_list = ident % ',';
ident = (qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9"));
}
qi::rule<Iterator, Skipper> module;
qi::rule<Iterator, Skipper> module_definition;
qi::rule<Iterator, Skipper> statements;
qi::rule<Iterator, Skipper> statement;
qi::rule<Iterator, Skipper> instance;
qi::rule<Iterator, Skipper> input_wires;
qi::rule<Iterator, std::vector<std::pair<std::string, std::string> >(), Skipper> connection_pair_list;
qi::rule<Iterator, std::pair<std::string, std::string>(), Skipper> connection_pair;
qi::rule<Iterator, std::vector<std::string>(), Skipper> ident_list;
qi::rule<Iterator, std::string(), Skipper> ident;
};
我已经将 found_smth
函数绑定到语法中的点字符.我认为规则正确,但是我无法匹配以下输入中的任何connection_pairs,并且由于迭代器彼此不可达,因此解析失败:
I have binded the found_smth
function to the dot character in the grammar. I feel the rules are correct but I am unable to match any connection_pairs in the following input and the parse fails as the iterators do not reach one another:
module mymod (A, B);
input A, B;
XOR21 gatexor5 (.A(B) , .C(D));
endmodule
船长是否正在消耗点?我应该立刻在点上找到火柴,对吗?谁能帮我发现问题?
Is the skipper consuming the dot? I should get a match on the dot immediately right? Can anyone help me spot the issue?
这是我的主要
代码:
typedef verilog_skipper<std::string::const_iterator> verilog_skipper;
typedef verilog_grammer<std::string::const_iterator, verilog_skipper> verilog_grammar;
verilog_grammar vg; // Our grammar
verilog_skipper vg_skip; // Our grammar
using boost::spirit::ascii::space;
std::string::const_iterator iter = storage.begin();
std::string::const_iterator end = storage.end();
bool r = qi::phrase_parse(iter, end, vg, vg_skip);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "-------------------------\n";
return 0;
}
推荐答案
一些事情.
-
您需要复习船长和词素:
You need to brush up on skippers and lexemes:
具体来说, qi :: eol
是 qi :: space
的一部分(不是 qi :: blank
).我可以简单地将船长指定为
Specifically, qi::eol
is part of qi::space
(not qi::blank
). I'd specify the skipper simply as
skip = qi::ascii::space | line_comment;
line_comment = "//" >> *(qi::char_ - qi::eol) >> (qi::eol|qi::eoi);
更具体地说,您将/需要/确保标识符是一个词素.最简单的方法是从规则的声明中删除船长.否则,"a b \ nc"
是标识符"abc"
的完全有效的拼写.
Even more specifically, you'll /need/ to make sure identifiers are a lexeme. The simplest way is to drop the skipper from the rule's declaration. Otherwise "a b\nc"
is a perfectly valid spelling of the identifier "abc"
.
// lexemes
qi::rule<Iterator, std::string()> primitive_gate, ident;
下一个示例显示每个语句以';'
结尾.但是你的语法说:
Next up your sample shows every statement terminated with ';'
. But your grammar says:
statements = statement % ';';
这将允许"S1"
,"S1; S2"
,...但不允许 "S1;"
.有几种方法可以修复它.最简单的似乎是
This will allow "S1"
, "S1;S2"
, ... but not "S1;"
. There are several ways to fix it. The simplest would appear to be
statements = +(statement >> ';'); // require exactly one `;` always
或者,如果"S1 ;;;;"
也可以接受,您可能会想说
Alternatively, if "S1;;;;"
is also acceptable, you might be tempted to say
statements = +(statement >> +qi::lit(';')); // require at least one `;` always
请注意,尽管这将不接受您可能期望的";;; S1 ;;"
或"
.我经常采用的模式是可选元素列表:
Note though that this would not accept ";;;S1;;"
, nor ""
as you might have expected. A pattern I often employ is the optional element list:
statements = -statement % ';'; // simple and flexible
哪种方法可以很好地接受"
,;"
,";;"
,"S1"
,";; S1;"
等.请注意,它效率不如
Which has a nice way of accepting ""
, ";"
, ";;"
, "S1"
, ";;S1;"
etc. Note it's not as efficient as something more verbose like
statements = *(*qi::lit(';') >> statement >> +qi::lit(';')); // require exactly one `;` always
我注意到您使用了 qi :: char _('(')
(及类似方法),它将在合成属性中公开匹配的字符. 高度 这不是您的意思,而是使用 qi :: lit('(')
解析表达式¹
I note you use qi::char_('(')
(and similar) that will expose the matched character in the synthesized attribute. It is highly unlikely this is what you mean. Use qi::lit('(')
instead, or indeed, using bare character/string literals in your parser expression will promote them to parser expressions¹
考虑使用BOOST_SPIRIT_DEBUG来了解您的语法在做什么
Consider using BOOST_SPIRIT_DEBUG to gain insight into what your grammar is doing
封装您的队长,因为不应打扰呼叫者,并且您可能不希望语法用户更改队长(这可能会破坏整个语法).
Encapsulate your skipper, since the caller should not be bothered about it, and you likely do not want users of your grammar to be able to change the skipper (that might break the entire grammar).
考虑使用符号而不是列出关键字,例如:
Consider using symbols instead of listing keywords, like:
primitive_gate = qi::lit("nand") | "nor" | "and" | "or" | "xor" |
"xnor" | "buf" | "not";
请注意顺序和关键字匹配.如果您解析标识符,则将匹配诸如 nand
的关键字.但是,如果您有一个标识符,例如 xor21
,则关键字 xor
将首先匹配.您可能需要/需要注意这一点(如何以激进的精神正确地解析保留字)
Pay attention to the ordering and keyword matching. If you parse an identifier, a keyword like nand
would match. If you have an identifier like xor21
however, the keyword xor
would match first. You may want/need to guard against this (How to parse reserved words correctly in boost spirit)
请注意,除非您使用 operator%= ,否则存在语义动作(例如
found_smth
)会抑制自动属性传播.code>将解析器表达式分配给规则.
Note that the presence of a semantic action (like e.g. the found_smth
) inhibits automatic attribute propagation, unless you use operator%=
to assign the parser expression to the rule.
演示时间
应用以上...:
DEMO TIME
Applying the above...:
在魔盒上直播 >
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/repository/include/qi_distinct.hpp>
#include <boost/fusion/adapted.hpp>
namespace qi = boost::spirit::qi;
static void found_smth() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
template <typename Iterator> struct verilog_skipper : qi::grammar<Iterator> {
verilog_skipper() : verilog_skipper::base_type(skip) {
skip = qi::ascii::space | line_comment;
line_comment = "//" >> *(qi::char_ - qi::eol) >> (qi::eol|qi::eoi);
}
private:
qi::rule<Iterator> skip;
qi::rule<Iterator> line_comment;
};
template <typename Iterator>
struct verilog_grammar : qi::grammar<Iterator> {
//verilog_ast ckt_ast;
typedef verilog_skipper<Iterator> Skipper;
verilog_grammar() : verilog_grammar::base_type(start) {
namespace phx = boost::phoenix;
using boost::spirit::repository::qi::distinct;
auto kw = distinct(qi::char_("a-zA-Z_0-9"));
start = qi::skip(qi::copy(skipper)) [module];
module = (module_definition >> statements >> kw["endmodule"]);
module_definition = (kw["module"] >> ident >> '(' >> ident_list >> ')' >> ';');
statements = -statement % ';';
statement = input_wires | output_wires | internal_wires | primitive | instance;
input_wires = kw["input"] >> ident_list;
output_wires = kw["output"] >> ident_list;
internal_wires = kw["wire"] >> ident_list;
primitive = primitive_gate >> ident >> '(' >> ident_list >> ')';
instance = ident >> ident >> '(' >> connection_pair_list >> ')';
connection_pair_list = connection_pair % ',';
// NOTE subtle use of `operator%=` in the presence of a semantic action
connection_pair %= (qi::lit('.')[phx::bind(&found_smth)] >> ident
>> '(' >> ident >> ')');
ident_list = ident % ',';
ident = (qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9"));
primitive_gate = qi::raw[kw[primitive_gate_]];
BOOST_SPIRIT_DEBUG_NODES(
(module)(module_definition)(statements)(statement)
(primitive)(primitive_gate)(instance)
(output_wires)(input_wires)(input_wires)
(connection_pair_list)(connection_pair)(ident_list)(ident)
)
}
private:
qi::rule<Iterator> start;
qi::rule<Iterator, Skipper> module;
qi::rule<Iterator, Skipper> module_definition;
qi::rule<Iterator, Skipper> statements;
qi::rule<Iterator, Skipper> statement;
qi::rule<Iterator, Skipper> primitive;
qi::rule<Iterator, std::string()> primitive_gate;
qi::rule<Iterator, Skipper> instance;
qi::rule<Iterator, Skipper> output_wires;
qi::rule<Iterator, Skipper> input_wires;
qi::rule<Iterator, Skipper> internal_wires;
qi::rule<Iterator, std::vector<std::pair<std::string, std::string> >(), Skipper> connection_pair_list;
qi::rule<Iterator, std::pair<std::string, std::string>(), Skipper> connection_pair;
qi::rule<Iterator, std::vector<std::string>(), Skipper> ident_list;
// lexemes
qi::rule<Iterator, std::string()> ident;
struct primitive_gate_t : qi::symbols<char> {
primitive_gate_t() { this->add("nand")("nor")("and")("or")("xor")("xnor")("buf")("not"); }
} primitive_gate_;
Skipper skipper;
};
#include <fstream>
int main() {
std::ifstream ifs("input.txt");
using It = boost::spirit::istream_iterator;
It f(ifs >> std::noskipws), l;
bool ok = qi::parse(f, l, verilog_grammar<It>{});
if (ok)
std::cout << "Parsed\n";
else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed '" << std::string(f,l) << "'\n";
}
打印:
void found_smth()
void found_smth()
Parsed
或启用了调试信息( BOOST_SPIRIT_DEBUG
):
Or with debug information enabled (BOOST_SPIRIT_DEBUG
):
<module>
<try>module mymod (A, B);</try>
<module_definition>
<try>module mymod (A, B);</try>
<ident>
<try>mymod (A, B);\n\ninput</try>
<success> (A, B);\n\ninput A, B</success>
<attributes>[[m, y, m, o, d]]</attributes>
</ident>
<ident_list>
<try>A, B);\n\ninput A, B;\n</try>
<ident>
<try>A, B);\n\ninput A, B;\n</try>
<success>, B);\n\ninput A, B;\n\n</success>
<attributes>[[A]]</attributes>
</ident>
<ident>
<try>B);\n\ninput A, B;\n\nXO</try>
<success>);\n\ninput A, B;\n\nXOR</success>
<attributes>[[B]]</attributes>
</ident>
<success>);\n\ninput A, B;\n\nXOR</success>
<attributes>[[[A], [B]]]</attributes>
</ident_list>
<success>\n\ninput A, B;\n\nXOR21</success>
<attributes>[]</attributes>
</module_definition>
<statements>
<try>\n\ninput A, B;\n\nXOR21</try>
<statement>
<try>\n\ninput A, B;\n\nXOR21</try>
<input_wires>
<try>\n\ninput A, B;\n\nXOR21</try>
<input_wires>
<try>\n\ninput A, B;\n\nXOR21</try>
<ident_list>
<try> A, B;\n\nXOR21 gatexo</try>
<ident>
<try>A, B;\n\nXOR21 gatexor</try>
<success>, B;\n\nXOR21 gatexor5</success>
<attributes>[[A]]</attributes>
</ident>
<ident>
<try>B;\n\nXOR21 gatexor5 (</try>
<success>;\n\nXOR21 gatexor5 (.</success>
<attributes>[[B]]</attributes>
</ident>
<success>;\n\nXOR21 gatexor5 (.</success>
<attributes>[[[A], [B]]]</attributes>
</ident_list>
<success>;\n\nXOR21 gatexor5 (.</success>
<attributes>[]</attributes>
</input_wires>
<success>;\n\nXOR21 gatexor5 (.</success>
<attributes>[]</attributes>
</input_wires>
<success>;\n\nXOR21 gatexor5 (.</success>
<attributes>[]</attributes>
</statement>
<statement>
<try>\n\nXOR21 gatexor5 (.A</try>
<input_wires>
<try>\n\nXOR21 gatexor5 (.A</try>
<input_wires>
<try>\n\nXOR21 gatexor5 (.A</try>
<fail/>
</input_wires>
<fail/>
</input_wires>
<output_wires>
<try>\n\nXOR21 gatexor5 (.A</try>
<fail/>
</output_wires>
<primitive>
<try>\n\nXOR21 gatexor5 (.A</try>
<primitive_gate>
<try>XOR21 gatexor5 (.A(B</try>
<fail/>
</primitive_gate>
<fail/>
</primitive>
<instance>
<try>\n\nXOR21 gatexor5 (.A</try>
<ident>
<try>XOR21 gatexor5 (.A(B</try>
<success> gatexor5 (.A(B) , .</success>
<attributes>[[X, O, R, 2, 1]]</attributes>
</ident>
<ident>
<try>gatexor5 (.A(B) , .C</try>
<success> (.A(B) , .C(D));\nen</success>
<attributes>[[g, a, t, e, x, o, r, 5]]</attributes>
</ident>
<connection_pair_list>
<try>.A(B) , .C(D));\nendm</try>
<connection_pair>
<try>.A(B) , .C(D));\nendm</try>
<ident>
<try>A(B) , .C(D));\nendmo</try>
<success>(B) , .C(D));\nendmod</success>
<attributes>[[A]]</attributes>
</ident>
<ident>
<try>B) , .C(D));\nendmodu</try>
<success>) , .C(D));\nendmodul</success>
<attributes>[[B]]</attributes>
</ident>
<success> , .C(D));\nendmodule</success>
<attributes>[[[A], [B]]]</attributes>
</connection_pair>
<connection_pair>
<try> .C(D));\nendmodule\n</try>
<ident>
<try>C(D));\nendmodule\n</try>
<success>(D));\nendmodule\n</success>
<attributes>[[C]]</attributes>
</ident>
<ident>
<try>D));\nendmodule\n</try>
<success>));\nendmodule\n</success>
<attributes>[[D]]</attributes>
</ident>
<success>);\nendmodule\n</success>
<attributes>[[[C], [D]]]</attributes>
</connection_pair>
<success>);\nendmodule\n</success>
<attributes>[[[[A], [B]], [[C], [D]]]]</attributes>
</connection_pair_list>
<success>;\nendmodule\n</success>
<attributes>[]</attributes>
</instance>
<success>;\nendmodule\n</success>
<attributes>[]</attributes>
</statement>
<statement>
<try>\nendmodule\n</try>
<input_wires>
<try>\nendmodule\n</try>
<input_wires>
<try>\nendmodule\n</try>
<fail/>
</input_wires>
<fail/>
</input_wires>
<output_wires>
<try>\nendmodule\n</try>
<fail/>
</output_wires>
<primitive>
<try>\nendmodule\n</try>
<primitive_gate>
<try>endmodule\n</try>
<fail/>
</primitive_gate>
<fail/>
</primitive>
<instance>
<try>\nendmodule\n</try>
<ident>
<try>endmodule\n</try>
<success>\n</success>
<attributes>[[e, n, d, m, o, d, u, l, e]]</attributes>
</ident>
<ident>
<try></try>
<fail/>
</ident>
<fail/>
</instance>
<fail/>
</statement>
<success>\nendmodule\n</success>
<attributes>[]</attributes>
</statements>
<success>\n</success>
<attributes>[]</attributes>
</module>
¹,只要涉及表达的一个操作数来自Qi原型表达域
¹ as long as one operand involved in the expression is from the Qi proto-expression domain
这篇关于带船长的Boost.Qi规则与“."不匹配特点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!