1

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

1 回答 1

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. 接下来,您的示例显示了以 .结尾的每个';'语句。但是你的语法说:

    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. 封装你的skipper,因为调用者不应该为此烦恼,而且你可能不希望你的语法用户能够更改skipper(这可能会破坏整个语法)。

  8. 考虑使用符号而不是列出关键字,例如:

    primitive_gate       = qi::lit("nand") | "nor" | "and" | "or" | "xor" |
        "xnor" | "buf" | "not";
    
  9. 注意排序和关键字匹配。如果你解析一个标识符,一个关键字 likenand会匹配。但是,如果您有类似的标识符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 原始表达式域

于 2017-10-08T22:03:12.140 回答