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”右括号之间的所有内容,并将字符串迭代器移到右括号之后。
因为你的代码无法工作并且不是独立的,所以我尝试了一下: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;
};
更改语法以匹配至少可以编译:
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";
}
}
}