一些东西。
你需要复习一下船长和词位:
具体来说,qi::eol
是qi::space
(不是qi::blank
)的一部分。我会简单地指定船长
skip = qi::ascii::space | line_comment;
line_comment = "//" >> *(qi::char_ - qi::eol) >> (qi::eol|qi::eoi);
更具体地说,您将 / 需要 / 确保标识符是一个词位。最简单的方法是从规则声明中删除船长。否则"a b\nc"
是一个完全有效的标识符拼写"abc"
。
// lexemes
qi::rule<Iterator, std::string()> primitive_gate, ident;
接下来,您的示例显示了以 .结尾的每个';'
语句。但是你的语法说:
statements = statement % ';';
这将允许"S1"
, "S1;S2"
, ... 但不允许 "S1;"
。有几种方法可以修复它。最简单的似乎是
statements = +(statement >> ';'); // require exactly one `;` always
或者,如果"S1;;;;"
也可以接受,您可能会想说
statements = +(statement >> +qi::lit(';')); // require at least one `;` always
请注意,虽然这不会接受";;;S1;;"
,也不会""
像您预期的那样。我经常使用的一种模式是可选元素列表:
statements = -statement % ';'; // simple and flexible
它有一种很好的接受""
, ";"
, ";;"
,等的方式。请注意,它"S1"
不像更冗长的东西那样有效";;S1;"
statements = *(*qi::lit(';') >> statement >> +qi::lit(';')); // require exactly one `;` always
我注意到您使用qi::char_('(')
(和类似的)将在合成属性中公开匹配的字符。这不太可能是你的意思。相反,或者实际上,在解析器表达式中使用qi::lit('(')
裸字符/字符串文字会将它们提升为解析器表达式¹
考虑使用 BOOST_SPIRIT_DEBUG 来深入了解您的语法在做什么
封装你的skipper,因为调用者不应该为此烦恼,而且你可能不希望你的语法用户能够更改skipper(这可能会破坏整个语法)。
考虑使用符号而不是列出关键字,例如:
primitive_gate = qi::lit("nand") | "nor" | "and" | "or" | "xor" |
"xnor" | "buf" | "not";
注意排序和关键字匹配。如果你解析一个标识符,一个关键字 likenand
会匹配。但是,如果您有类似的标识符xor21
,则关键字xor
将首先匹配。您可能希望/需要注意这一点(如何以增强精神正确解析保留字)
请注意,语义操作(例如found_smth
)的存在会禁止自动属性传播,除非您使用operator%=
将解析器表达式分配给规则。
演示时间
应用上述...:
Live On Wandbox
#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
):
<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 原始表达式域