我想将包含函数原型的输入缓冲区解析为函数原型的向量。我创建了一个具有3个成员的函数原型结构:returnType,名称和参数列表。我遇到编译器错误,抱怨它无法将已解析的结果移入结构。我想念什么吗?
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <list>
#include <iostream>
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
using boost::spirit::x3::ascii::space;
namespace ast {
struct identifier {
std::string name;
};
struct argument {
identifier typeName;
identifier value;
};
struct function_call {
identifier name;
std::list<argument> arguments;
};
struct function_prototype {
identifier returnType;
identifier name;
std::list<argument> arguments;
};
} // namespace ast
BOOST_FUSION_ADAPT_STRUCT(ast::identifier, (std::string, name))
BOOST_FUSION_ADAPT_STRUCT(ast::argument, (struct identifier, typeName) (struct identifier, value))
BOOST_FUSION_ADAPT_STRUCT(ast::function_call, (struct identifier, name) (struct identifier, arguments))
BOOST_FUSION_ADAPT_STRUCT(ast::function_prototype, (struct identifier, returnType) (struct identifier, name) (std::list<struct argument>, arguments))
namespace parser
{
struct identifier_class;
typedef x3::rule<identifier_class, ast::identifier> identifier_type;
identifier_type const identifier = "identifier";
auto const identifier_def = x3::raw[x3::lexeme[(x3::alpha | '_') >> *(x3::alnum | '_')]];
BOOST_SPIRIT_DEFINE(identifier)
struct argument_class;
typedef x3::rule<argument_class, ast::argument> argument_type;
argument_type const argument = "argument";
auto const argument_def = x3::raw[identifier >> identifier];
BOOST_SPIRIT_DEFINE(argument)
struct function_call_class;
typedef x3::rule<function_call_class, ast::function_call> function_call_type;
function_call_type const function_call = "function_call";
auto const function_call_def = x3::raw[identifier >> '(' > -(argument % ',') > ')'];
BOOST_SPIRIT_DEFINE(function_call)
struct function_prototype_class;
typedef x3::rule<function_prototype_class, ast::function_prototype> function_prototype_class_type;
function_prototype_class_type const function_prototype = "function_prototype";
auto const function_prototype_def =
x3::raw[identifier >> identifier >> '(' > -(argument % ',') > ')'];
BOOST_SPIRIT_DEFINE(function_prototype)
auto const functionProtos = function_prototype >> *(function_prototype);
}
namespace Application {
class Parser {
public:
void functionParser(const std::string& input) {
std::vector<ast::function_call> output;
x3::phrase_parse(input.begin(), input.end(), parser::functionProtos, x3::space, output);
std::cout << "success\n";
}
};
} // namespace parser
答案 0 :(得分:1)
一个问题是改编:您正在提供类型,但将它们拼写为全局名称空间中类型的前向声明:
BOOST_FUSION_ADAPT_STRUCT(ast::argument, (struct identifier, typeName) (struct identifier, value))
BOOST_FUSION_ADAPT_STRUCT(ast::function_call, (struct identifier, name) (struct identifier, arguments))
BOOST_FUSION_ADAPT_STRUCT(ast::function_prototype, (struct identifier, returnType) (struct identifier, name) (std::list<struct argument>, arguments))
可能可以通过替换为例如来修复ast::identifier
,但何必呢?您绝对可以使用c ++ 11版本,并让编译器找出类型:
BOOST_FUSION_ADAPT_STRUCT(ast::identifier, name)
BOOST_FUSION_ADAPT_STRUCT(ast::argument, typeName, value)
BOOST_FUSION_ADAPT_STRUCT(ast::function_call, name, arguments)
BOOST_FUSION_ADAPT_STRUCT(ast::function_prototype, returnType, name, arguments)
第二个肚带是x3::raw[]
。 raw
指令将迭代器范围公开为属性,并且与绑定的属性类型(例如ast::identifier
)不兼容。
在这种情况下,您正在解析(与我在the previous answer中所做的评论(不解析,仅匹配)进行比较)。因此,您需要将综合属性与目标属性类型进行匹配:
auto const identifier_def = x3::lexeme[(x3::alpha | x3::char_('_')) >> *(x3::alnum | x3::char_('_'))];
Qi / X3存在一个挥之不去的问题,这导致单元素序列的属性传播变得混乱。在这种情况下,只需将identifier
解析为std::string
(融合将从那里正确地将其分配给ast::identifier
),就会有帮助:
auto const identifier_def = x3::lexeme[(x3::alpha | x3::char_('_')) >> *(x3::alnum | x3::char_('_'))];
删除其余的rawp[]
指令使其可以编译:
#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <list>
#include <iostream>
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
using boost::spirit::x3::ascii::space;
namespace ast {
struct identifier {
std::string name;
};
struct argument {
identifier typeName;
identifier value;
};
struct function_call {
identifier name;
std::list<argument> arguments;
};
struct function_prototype {
identifier returnType;
identifier name;
std::list<argument> arguments;
};
} // namespace ast
BOOST_FUSION_ADAPT_STRUCT(ast::identifier, name)
BOOST_FUSION_ADAPT_STRUCT(ast::argument, typeName, value)
BOOST_FUSION_ADAPT_STRUCT(ast::function_call, name, arguments)
BOOST_FUSION_ADAPT_STRUCT(ast::function_prototype, returnType, name, arguments)
namespace parser
{
struct identifier_class;
typedef x3::rule<identifier_class, std::string> identifier_type;
identifier_type const identifier = "identifier";
auto const identifier_def = x3::lexeme[(x3::alpha | x3::char_('_')) >> *(x3::alnum | x3::char_('_'))];
BOOST_SPIRIT_DEFINE(identifier)
struct argument_class;
typedef x3::rule<argument_class, ast::argument> argument_type;
argument_type const argument = "argument";
auto const argument_def = identifier >> identifier;
BOOST_SPIRIT_DEFINE(argument)
struct function_call_class;
typedef x3::rule<function_call_class, ast::function_call> function_call_type;
function_call_type const function_call = "function_call";
auto const function_call_def = identifier >> '(' > -(argument % ',') > ')';
BOOST_SPIRIT_DEFINE(function_call)
struct function_prototype_class;
typedef x3::rule<function_prototype_class, ast::function_prototype> function_prototype_class_type;
function_prototype_class_type const function_prototype = "function_prototype";
auto const function_prototype_def =
identifier >> identifier >> '(' > -(argument % ',') >> x3::expect[')'] >> ';';
BOOST_SPIRIT_DEFINE(function_prototype)
auto const functionProtos = +function_prototype;
}
namespace Application {
class Parser {
public:
void functionParser(const std::string& input) {
if (0) {
ast::identifier output;
x3::phrase_parse(input.begin(), input.end(), parser::identifier, x3::space, output);
}
if (0) {
ast::argument output;
x3::phrase_parse(input.begin(), input.end(), parser::argument, x3::space, output);
}
if (0) {
ast::function_call output;
x3::phrase_parse(input.begin(), input.end(), parser::function_call, x3::space, output);
}
if (0) {
ast::function_prototype output;
x3::phrase_parse(input.begin(), input.end(), parser::function_prototype, x3::space, output);
}
{
std::vector<ast::function_prototype> output;
x3::phrase_parse(input.begin(), input.end(), parser::functionProtos, x3::space, output);
std::cout << "success: " << output.size() << " prototypes parsed\n";
}
}
};
} // namespace parser
int main()
{
Application::Parser p;
p.functionParser("void foo(int a); float bar(double b, char c);");
}
打印
success: 2 prototypes parsed
只要您不跨翻译单元共享规则或需要递归规则,就无需定义/宏。而是简化:
auto const identifier = as<std::string>("identifier", x3::lexeme[(x3::alpha | x3::char_('_')) >> *(x3::alnum | x3::char_('_'))]);
auto const argument = as<ast::argument>("argument", identifier >> identifier);
auto const function_call = as<ast::function_call>("function_call", identifier >> '(' > -(argument % ',') > ')');
auto const function_prototype = as<ast::function_prototype>("function_prototype",
identifier >> identifier >> '(' > -(argument % ',') >> x3::expect[')'] >> ';');
这是使用非常简单的速记来键入规则attirbutes:
template <typename T> auto as = [](auto name, auto p) { return x3::rule<struct _, T> {name} = p; };
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted.hpp>
#include <list>
#include <iostream>
namespace x3 = boost::spirit::x3;
using boost::spirit::x3::ascii::space;
namespace ast {
struct identifier {
std::string name;
};
struct argument {
identifier typeName;
identifier value;
};
struct function_call {
identifier name;
std::list<argument> arguments;
};
struct function_prototype {
identifier returnType;
identifier name;
std::list<argument> arguments;
};
} // namespace ast
BOOST_FUSION_ADAPT_STRUCT(ast::identifier, name)
BOOST_FUSION_ADAPT_STRUCT(ast::argument, typeName, value)
BOOST_FUSION_ADAPT_STRUCT(ast::function_call, name, arguments)
BOOST_FUSION_ADAPT_STRUCT(ast::function_prototype, returnType, name, arguments)
namespace parser
{
template <typename T> auto as = [](auto name, auto p) { return x3::rule<struct _, T> {name} = p; };
auto const identifier = as<std::string>("identifier", x3::lexeme[(x3::alpha | x3::char_('_')) >> *(x3::alnum | x3::char_('_'))]);
auto const argument = as<ast::argument>("argument", identifier >> identifier);
auto const function_call = as<ast::function_call>("function_call", identifier >> '(' > -(argument % ',') > ')');
auto const function_prototype = as<ast::function_prototype>("function_prototype",
identifier >> identifier >> '(' > -(argument % ',') >> x3::expect[')'] >> ';');
auto const functionProtos = +function_prototype;
}
namespace Application {
class Parser {
public:
void functionParser(const std::string& input) {
std::vector<ast::function_prototype> output;
x3::phrase_parse(input.begin(), input.end(), parser::functionProtos, x3::space, output);
std::cout << "success: " << output.size() << " prototypes parsed\n";
}
};
} // namespace parser
int main()
{
Application::Parser p;
p.functionParser("void foo(int a); float bar(double b, char c);");
}
还会打印
success: 2 prototypes parsed