statement; if_statement = lit("if") >> '(' -6ren">
gpt4 book ai didi

c++11 - 提升平凡语法的编译错误

转载 作者:行者123 更新时间:2023-12-02 10:42:37 27 4
gpt4 key购买 nike

我正在尝试使用以下规则编译解析器:

else_statement =
lit("else") > statement;

if_statement =
lit("if") >> '(' >> expression >> ')' >> statement >> -else_statement;
else_statement的属性是 statement,它使用的 statement规则也是如此。 if_statement的属性是一个结构,其成员的类型分别为 expressionstatement和可选的 statement( boost::optional<statement>)。

使用以下 BOOST_FUSION_ADAPT_STRUCT:
BOOST_FUSION_ADAPT_STRUCT(ast::statement, m_statement_node)
BOOST_FUSION_ADAPT_STRUCT(ast::if_statement, m_condition, m_then, m_else)

其中 m_statement_node是可能的不同语句的 boost::variant

我希望如果存在 else_statement,它将被放入 boost::optional<statement>中,因为 else_statement的属性是 statement。如果我用 注释掉lit("else") >规则中的else_statement ,则此 会起作用!但是随着 lit("else")的出现,发生了一些奇怪的事情:现在boost::spirit试图将 statement放入可选的 statement(boost::variant)的成员中,该文件显然不会编译,因为这只需要A或B。

产生的编译错误如下所示:
/usr/include/boost/variant/variant.hpp:1534:38: error: no matching function for call to ‘boost::variant<ast::A, ast::B>::initializer::initialize(void*, const ast::statement&)’

我究竟做错了什么?我该如何解决?

在显示错误的完整测试代码下面(并在 lit("else") >被注释掉时进行编译)。
// File: so.cpp
// Compile as: g++ -std=c++11 so.cpp

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/optional/optional_io.hpp>
#include <iostream>
#include <string>
#include <vector>

namespace ast
{

struct A { int a; friend std::ostream& operator<<(std::ostream& os, A const&) { return os << "A"; } };
struct B { int b; friend std::ostream& operator<<(std::ostream& os, B const&) { return os << "B"; } };
struct expression { int e; friend std::ostream& operator<<(std::ostream& os, expression const&) { return os << "expression"; } };

using statement_node = boost::variant<A, B>;

struct statement
{
statement_node m_statement_node;

friend std::ostream& operator<<(std::ostream& os, statement const& statement)
{ return os << "STATEMENT:" << statement.m_statement_node; }
};

struct if_statement
{
expression m_condition;
statement m_then;
boost::optional<statement> m_else;

friend std::ostream& operator<<(std::ostream& os, if_statement const& if_statement)
{
os << "IF_STATEMENT:" << if_statement.m_condition << "; " << if_statement.m_then;
if (if_statement.m_else)
os << "; " << if_statement.m_else;
return os;
}
};

} // namespace ast

BOOST_FUSION_ADAPT_STRUCT(ast::expression, e)
BOOST_FUSION_ADAPT_STRUCT(ast::A, a)
BOOST_FUSION_ADAPT_STRUCT(ast::B, b)
BOOST_FUSION_ADAPT_STRUCT(ast::statement, m_statement_node)
BOOST_FUSION_ADAPT_STRUCT(ast::if_statement, m_condition, m_then, m_else)

namespace client
{

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

template <typename Iterator>
class test_grammar : public qi::grammar<Iterator, ast::if_statement(), qi::space_type>
{
private:
template<typename T> using rule = qi::rule<Iterator, T(), qi::space_type>;

rule<ast::A> a;
rule<ast::B> b;
rule<ast::statement> statement;
rule<ast::statement> else_statement;
rule<ast::if_statement> if_statement;
rule<int> expression;

public:
test_grammar() : test_grammar::base_type(if_statement, "result_grammar")
{
using namespace qi;

statement =
a | b;

else_statement =
lit("else") > statement;

if_statement =
lit("if") >> '(' >> expression >> ')' >> statement >> -else_statement;

expression =
int_;

a = 'A';
b = 'B';

BOOST_SPIRIT_DEBUG_NODES(
(statement)
(else_statement)
(if_statement)
(expression)
(a)
(b)
);
}
};

} // namespace client

int main()
{
std::string const input{"if (1) A B"};
using iterator_type = std::string::const_iterator;
using test_grammar = client::test_grammar<iterator_type>;
namespace qi = boost::spirit::qi;

test_grammar program;
iterator_type iter{input.begin()};
iterator_type const end{input.end()};
ast::if_statement out;
bool r = qi::phrase_parse(iter, end, program, qi::space, out);

if (!r || iter != end)
{
std::cerr << "Parsing failed." << std::endl;
return 1;
}
std::cout << "Parsed: " << out << std::endl;
}

最佳答案

对于由单个元素组成的Fusion序列,自动属性传播规则会带来一些麻烦。您可以在这里声明以下内容来解决此问题:

rule<ast::statement_node> statement;

(从 ast::statement更改为 ast::statement_node)。

这有效: 在Coliru上直播

替代解决方法

更繁琐的解决方法是避免在那里出现单元素融合序列。您可以向 statement添加一个虚拟字段:
struct statement
{
statement_node m_statement_node;
int dummy;

friend std::ostream& operator<<(std::ostream& os, statement const& statement)
{ return os << "STATEMENT:" << statement.m_statement_node; }
};

BOOST_FUSION_ADAPT_STRUCT(ast::statement, m_statement_node, dummy)

然后为其添加一个值:
statement = (a | b) >> attr(42);

这也消除了困惑。

Live On Wandbox
// File: so.cpp
// Compile as: g++ -std=c++11 so.cpp
//#define BOOST_SPIRIT_DEBUG

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/optional/optional_io.hpp>
#include <iostream>
#include <string>
#include <vector>

namespace ast
{

struct A { int a; friend std::ostream& operator<<(std::ostream& os, A const&) { return os << "A"; } };
struct B { int b; friend std::ostream& operator<<(std::ostream& os, B const&) { return os << "B"; } };
struct expression { int e; friend std::ostream& operator<<(std::ostream& os, expression const&) { return os << "expression"; } };

using statement_node = boost::variant<A, B>;

struct statement
{
statement_node m_statement_node;
int dummy;

friend std::ostream& operator<<(std::ostream& os, statement const& statement)
{ return os << "STATEMENT:" << statement.m_statement_node; }
};

struct if_statement
{
expression m_condition;
statement m_then;
boost::optional<statement> m_else;

friend std::ostream& operator<<(std::ostream& os, if_statement const& if_statement)
{
os << "IF_STATEMENT:" << if_statement.m_condition << "; " << if_statement.m_then;
if (if_statement.m_else)
os << "; " << if_statement.m_else;
return os;
}
};

} // namespace ast

BOOST_FUSION_ADAPT_STRUCT(ast::expression, e)
BOOST_FUSION_ADAPT_STRUCT(ast::A, a)
BOOST_FUSION_ADAPT_STRUCT(ast::B, b)
BOOST_FUSION_ADAPT_STRUCT(ast::statement, m_statement_node, dummy)
BOOST_FUSION_ADAPT_STRUCT(ast::if_statement, m_condition, m_then, m_else)

namespace client
{

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

template <typename Iterator>
class test_grammar : public qi::grammar<Iterator, ast::if_statement(), qi::space_type>
{
private:
template<typename T> using rule = qi::rule<Iterator, T(), qi::space_type>;

rule<ast::A> a;
rule<ast::B> b;
rule<ast::statement> statement;
rule<ast::statement> else_statement;
rule<ast::if_statement> if_statement;
rule<int> expression;

public:
test_grammar() : test_grammar::base_type(if_statement, "result_grammar")
{
using namespace qi;

statement = (a | b) >> attr(42);

else_statement = lit("else") > statement;

if_statement = lit("if") >> '(' >> expression >> ')' >> statement >> -else_statement;

expression = int_;

a = 'A' >> attr(1);
b = 'B' >> attr(2);

BOOST_SPIRIT_DEBUG_NODES( (statement) (else_statement) (if_statement) (expression) (a) (b));
}
};

} // namespace client

int main()
{
for (std::string const input : {
"if (1) A else B",
})
{
using iterator_type = std::string::const_iterator;
using test_grammar = client::test_grammar<iterator_type>;
namespace qi = boost::spirit::qi;

test_grammar program;
iterator_type iter = input.begin(), end = input.end();
ast::if_statement out;
bool r = qi::phrase_parse(iter, end, program, qi::space, out);

if (!r || iter != end)
{
std::cerr << "Parsing failed." << std::endl;
return 1;
}
std::cout << "Parsed: " << out << std::endl;
}
}

版画
Parsed: IF_STATEMENT:expression; STATEMENT:A;  STATEMENT:B

背景

但是请注意,如果错误地使 else_statement规则也具有相同的长度,则会产生相同的困惑:
else_statement = lit("else") > statement > attr(42); // this is wrong

当然,这实际上没有任何意义,但是错误消息确实可以帮助解释真正的问题是什么(如果“上游”融合序列看起来“兼容”,那么它将“解构”以进行传播)。 qi/nonterminal/rule.hpp中的相关注释:
// do up-stream transformation, this integrates the results
// back into the original attribute value, if appropriate
traits::post_transform(attr_param, attr_);

关于c++11 - 提升平凡语法的编译错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44730979/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com