Правило Boost.Qi со шкипером не соответствует ‘.’ персонаж

Итак, у меня есть следующий шкипер ци:

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 функция до символа точки в грамматике. Я чувствую, что правила верны, но я не могу сопоставить пары соединений в следующих входных данных, и анализ не выполняется, поскольку итераторы не достигают друг друга:

module mymod (A, B);

input A, B;

XOR21 gatexor5 (.A(B) , .C(D));
endmodule

Шкипер поглощает точку? Я должен получить спичку на месте сразу же, верно? Может кто-нибудь помочь мне определить проблему?

Вот мой main код:

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;
}

1

Решение

Несколько вещей.

  1. Вам нужно освежить шкиперы и лексемы:

  2. В частности, qi::eol это часть qi::space (не qi::blank). Я бы указал шкипера просто как

    skip = qi::ascii::space | line_comment;
    line_comment = "//" >> *(qi::char_ - qi::eol) >> (qi::eol|qi::eoi);
    
  3. Более конкретно, вам нужно / нужно / убедиться, что идентификаторы являются лексемой. Самый простой способ — исключить шкипера из декларации правила. Иначе "a b\nc" это совершенно правильное написание идентификатора "abc",

    // lexemes
    qi::rule<Iterator, std::string()> primitive_gate, ident;
    
  4. Далее ваши образцы шоу каждый заявление прекращено ';', Но ваша грамматика говорит:

    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
    
  5. Я отмечаю, что вы используете qi::char_('(') (и аналогичный), который будет выставлять соответствующий символ в синтезированном атрибуте. это очень маловероятно это то, что вы имеете в виду. использование qi::lit('(') вместо этого или действительно, использование пустых символьных / строковых литералов в выражении вашего синтаксического анализатора приведет к их преобразованию в выражения синтаксического анализатора¹

  6. Подумайте об использовании BOOST_SPIRIT_DEBUG, чтобы понять, что делает ваша грамматика

  7. Инкапсулируйте свой шкипер, так как вызывающий не должен беспокоиться об этом, и вы, вероятно, не хотите, чтобы пользователи вашей грамматики могли менять шкипер (который может нарушить всю грамматику).

  8. Попробуйте использовать символы вместо перечисления ключевых слов, например:

    primitive_gate       = qi::lit("nand") | "nor" | "and" | "or" | "xor" |
    "xnor" | "buf" | "not";
    
  9. Обратите внимание на порядок и соответствие ключевых слов. Если вы анализируете идентификатор, ключевое слово, как nand будет соответствовать. Если у вас есть такой идентификатор, как xor21 однако ключевое слово xor будет соответствовать в первую очередь. Вы можете / должны принять меры против этого (Как правильно анализировать зарезервированные слова в духе буста)

  10. Обратите внимание, что наличие семантического действия (например, 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

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]