Boost Spiri Qi 递归表达式解析器

问题描述 投票:0回答:1
    struct NestedStr;

    typedef boost::variant<std::string, boost::recursive_wrapper< NestedStr>> expression;

    struct NestedStr
    {
        vector<expression> children;  // variant instantiated here...

        NestedStr(const vector<expression> & child) : children(child)        
        {
        }

        NestedStr()
        {
        }
    };

    template <typename Iterator>
        struct TimingGrammar : qi::grammar<Iterator, SDFDelayInfo(), ascii::space_type>
    {
        TimingGrammar() : TimingGrammar::base_type(start)
        {

            str_rule            %= +(qi::char_ - (qi::lit('(') | qi::lit(')')));
            brace_rule          %= '(' >> str_rule >> brace_rule >> ')'; 

            start   %= '(' >> qi::lit("TIMING") >> brace_rule ')';
        }

        qi::rule<Iterator, string(), ascii::space_type> str_rule;
        qi::rule<Iterator, NestedStr(), ascii::space_type> start;


    };

我正在解析这个嵌套表达式,并想解析到右括号。

(时机 (恢复(COND(COND(COND(COND))))) (宽度(COND AB == 1'b1(位置 CK))(0.040::0.040)) )

但是面临着很长的编译器错误。

第二个问题是,每当遇到“(TIMING”时,有什么方法可以省略“(TIMING”右括号之间的所有内容,并将字符串迭代器移到右括号之后。

parsing c++11 boost-spirit-qi
1个回答
0
投票

因为你的代码无法工作并且不是独立的,所以我尝试了一下:Live On Coliru

现在显然,这可能与您遇到的问题相同,也可能不同。

但是,它确实凸显了一个概念问题:

/home/sehe/custom/superboost/libs/spirit/include/boost/spirit/home/qi/detail/assign_to.hpp|153 col 20| error: no matching function for call to ‘AST::SubNode::SubNode(const std::__cxx11::basic_string<char>&)’

将合成属性传播到实际属性类型时存在问题。

最有趣的是,您的子节点产量是

"(" >> key >> subnode >> ")"
。它与任何 AST 节点都不匹配。另外,由于该规则中没有任何内容是可选的并且它会递归,因此根据定义它永远不会解析,因为除非输入是无限的,否则在某些时候它将无法匹配。

从这个例子来看,我猜你实际上需要更多类似的东西:

using Value = std::string;
using Nodes = std::vector<struct Node>;

struct Node {
    Value value;
    Nodes children;
};

更改语法以匹配至少可以编译:

住在Coliru

template <typename Iterator>
struct TimingGrammar                                        //
    : qi::grammar<Iterator, SDFDelayInfo(), qi::space_type> //
{
    TimingGrammar() : TimingGrammar::base_type(start) {
        value_ = +~qi::char_(")(");
        node_  = '(' >> value_ >> *node_ >> ')';
        start  = '(' >> qi::string("TIMING") >> *node_ >> ')';

        BOOST_SPIRIT_DEBUG_NODES((value_)(node_)(start))
    }

  private:
    qi::rule<Iterator, AST::Value()>                value_;
    qi::rule<Iterator, AST::Node(), qi::space_type> node_;
    qi::rule<Iterator, AST::Node(), qi::space_type> start;
};

印刷:

Parsed failed

调试解析失败

您会注意到我准备了 BOOST_SPIRIT_DEBUG_NODES,启用它

#define BOOST_SPIRIT_DEBUG

更微妙的笔记

上面容易忽略的事情:

  • value_
    不再有船长 - 否则它会丢失较长键内的空格;另请参阅提升精神船长问题
  • *node_
    Kleene-star 重复,这意味着它是可选的
  • TIMING
    包装到
    qi::string
    解析器中,而不是
    qi::lit
    很重要,因为您需要与
    Node::value
  • 对应的属性

完整列表供参考

https://coliru.stacked-crooked.com/a/76079323e03ee328

//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;

namespace AST {
    using Value = std::string;
    using Nodes = std::vector<struct Node>;

    struct Node {
        Value value;
        Nodes children;

        // for debug output
        friend std::ostream& operator<<(std::ostream& os, Node const& n) {
            os << quoted(n.value);
            if (!n.children.empty()) {
                os << "(";
                for (auto& child : n.children)
                    os << " " << child << " ";

                os << ")";
            }

            return os;
        }
    };

} // namespace AST

BOOST_FUSION_ADAPT_STRUCT(AST::Node, value, children)

using SDFDelayInfo = AST::Node;

template <typename Iterator>
struct TimingGrammar                                        //
    : qi::grammar<Iterator, SDFDelayInfo(), qi::space_type> //
{
    TimingGrammar() : TimingGrammar::base_type(start) {
        value_ = +~qi::char_(")(");
        node_  = '(' >> value_ >> *node_ >> ')';
        start  = '(' >> qi::string("TIMING") >> *node_ >> ')';

        BOOST_SPIRIT_DEBUG_NODES((value_)(node_)(start))
    }

  private:
    qi::rule<Iterator, AST::Value()>                value_;
    qi::rule<Iterator, AST::Node(), qi::space_type> node_;
    qi::rule<Iterator, AST::Node(), qi::space_type> start;
};

int main() {
    using It = std::string::const_iterator;
    for (std::string const input : {
             "(TIMING  )",
             "(TIMING (RECOVERY ))",
             "(TIMING (RECOVERY (COND)))",
             "(TIMING (RECOVERY (COND(COND(COND(COND))))) )",
             "(TIMING (WIDTH (COND AB == 1'b1 (pos CK)) ))",
             "(TIMING (WIDTH (0.040::0.040)))",
             "(TIMING (WIDTH (COND AB == 1'b1 (pos CK)) (0.040::0.040)))",
             // everything combined
             "(TIMING (RECOVERY (COND(COND(COND(COND))))) (WIDTH (COND AB == 1'b1 (pos CK)) (0.040::0.040)))",
         }) {
        SDFDelayInfo info;
        if (phrase_parse(begin(input), end(input), TimingGrammar<It>{}, qi::space, info)) {
            std::cout << "Parsed into: " << info << "\n";
        } else {
            std::cout << "Parsed failed\n";
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.