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;
};
and the following qi grammar:
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;
};
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?
Here is my main
code:
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;
}
A few things.
You need to brush up on skippers and lexemes:
Specifically,
qi::eol
is part ofqi::space
(notqi::blank
). I'd specify the skipper simply asEven 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"
.Next up your sample shows every statement terminated with
';'
. But your grammar says:This will allow
"S1"
,"S1;S2"
, ... but not"S1;"
. There are several ways to fix it. The simplest would appear to beAlternatively, if
"S1;;;;"
is also acceptable, you might be tempted to sayNote though that this would not accept
";;;S1;;"
, nor""
as you might have expected. A pattern I often employ is the optional element list:Which has a nice way of accepting
""
,";"
,";;"
,"S1"
,";;S1;"
etc. Note it's not as efficient as something more verbose likeI 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. Useqi::lit('(')
instead, or indeed, using bare character/string literals in your parser expression will promote them to parser expressions¹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:
Pay attention to the ordering and keyword matching. If you parse an identifier, a keyword like
nand
would match. If you have an identifier likexor21
however, the keywordxor
would match first. You may want/need to guard against this (How to parse reserved words correctly in boost spirit)Note that the presence of a semantic action (like e.g. the
found_smth
) inhibits automatic attribute propagation, unless you useoperator%=
to assign the parser expression to the rule.DEMO TIME
Applying the above...:
Live On Wandbox
Prints:
Or with debug information enabled (
BOOST_SPIRIT_DEBUG
):¹ as long as one operand involved in the expression is from the Qi proto-expression domain