带有队长的Boost.Qi规则与''不匹配。字符

时间:2017-10-08 20:57:49

标签: c++ boost boost-spirit qi

所以我有以下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;
};

以及以下的qi语法:

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,并且解析失败,因为迭代器没有达到彼此:

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 个答案:

答案 0 :(得分:2)

一些事情。

  1. 你需要了解船长和词汇:

  2. 具体而言,qi::eolqi::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. 接下来,您的示例会显示以<{1}}终止的每个语句。但你的语法说:

    ';'

    这将允许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;"
  5. 我注意到你使用statements = *(*qi::lit(';') >> statement >> +qi::lit(';')); // require exactly one `;` always (和类似的)来揭示合成属性中的匹配字符。 极不可能 这就是你的意思。改为使用qi::char_('('),或者实际上,在解析器表达式中使用裸字符/字符串文字会将它们提升为解析器表达式¹

  6. 考虑使用BOOST_SPIRIT_DEBUG深入了解您的语法正在做什么

  7. 封装你的队长,因为调用者不应该为此烦恼,你可能不希望你的语法用户能够改变队长(这可能会破坏整个语法)。

  8. 考虑使用符号代替列出关键字,例如:

    qi::lit('(')
  9. 注意排序和关键字匹配。如果您解析标识符,则primitive_gate = qi::lit("nand") | "nor" | "and" | "or" | "xor" | "xnor" | "buf" | "not"; 之类的关键字将匹配。如果您有nand之类的标识符,则关键字xor21将首先匹配。您可能希望/需要防范此(How to parse reserved words correctly in boost spirit

  10. 请注意,语义操作(例如xor的存在会禁止自动属性传播,除非您使用found_smth将解析器表达式分配给规则。

  11. DEMO TIME

    应用上述......:

    Live On Wandbox

    operator%=

    打印:

    #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
    只要参与表达的一个操作数来自Qi原始表达结构域

    1