C++ 使用Boost::Spirit解析前置条件和递归
我试图用Boost::Spirit解析PDDL文件,但在将前置条件解析为结构时遇到了一些问题。我正在努力理解Boost手册中关于如何将条件放入我的结构和递归的内容 我在下面给出一段代码,可以很好地说明这个问题。必须分析如下所示的字符串:C++ 使用Boost::Spirit解析前置条件和递归,c++,boost,boost-spirit,boost-spirit-qi,C++,Boost,Boost Spirit,Boost Spirit Qi,我试图用Boost::Spirit解析PDDL文件,但在将前置条件解析为结构时遇到了一些问题。我正在努力理解Boost手册中关于如何将条件放入我的结构和递归的内容 我在下面给出一段代码,可以很好地说明这个问题。必须分析如下所示的字符串: :precondition (and (at-pos ?r ?pos) (not (has-pos ?m ?pos)) ) 到目前为止,我的代码看起来是这样的,但我几乎可以肯定,在没有Boost::Phoenix方面的经验的情况下,我不理解at_c是如
:precondition
(and
(at-pos ?r ?pos)
(not (has-pos ?m ?pos))
)
到目前为止,我的代码看起来是这样的,但我几乎可以肯定,在没有Boost::Phoenix方面的经验的情况下,我不理解at_c是如何工作的
predi_param = '?' >> name_type;
predi = '('
>> name_type
>> +predi_param
>> ')';
literal = (
( '(' >> lit("not") >>
predi [at_c<0>(_val) = false]
>> ')'
)
| predi [at_c<0>(_val) = true]
)
>> ')';
pred_list = ( '(' >> lit("and") >> (*pred_list) >> ')')
| literal;
preconditions = lit(":precondition") >> pred_list;
qi::rule<Iterator, std::string(), ascii::space_type> predi_param;
qi::rule<Iterator, Predicate(), ascii::space_type> predi;
qi::rule<Iterator, Literal(), ascii::space_type> literal;
qi::rule<Iterator, std::vector<Literal>(), ascii::space_type> preconditions, pred_list;
predi_param='?'>>name_type;
predi='('
>>名称/类型
>>+预测参数
>> ')';
文字=(
('('>>lit(“not”)>>
预测值[at_c(_val)=假]
>> ')'
)
|预测值[at_c(_val)=真]
)
>> ')';
pred_list=('('>>lit(“and”)>>(*pred_list)>>'))
|文字;
前置条件=点亮(“:前置条件”)>>pred_列表;
qi::规则预测参数;
qi:规则预测;
qi::规则文本;
qi::规则先决条件,pred_列表;
我的AST如下所示:
struct Predicate
{
std::string name;
std::vector<std::string> predicate_params;
};
struct Literal
{
bool condition;
Predicate predicate;
};
BOOST_FUSION_ADAPT_STRUCT(
pddl_parser::Literal,
(bool, condition)
(pddl_parser::Predicate, predicate)
)
BOOST_FUSION_ADAPT_STRUCT(
pddl_parser::Predicate,
(std::string, name)
(std::vector<std::string>, predicate_params)
)
struct谓词
{
std::字符串名;
std::向量谓词参数;
};
结构文字
{
布尔条件;
谓词;
};
增强融合适应结构(
pddl_解析器::文本,
(布尔,条件)
(pddl_解析器::谓词,谓词)
)
增强融合适应结构(
pddl_解析器::谓词,
(std::字符串,名称)
(标准::向量,谓词参数)
)
编译此文件会导致编译错误:
parser.cpp:67:17: required from ‘pddl_parser::domain_parser<Iterator>::domain_parser() [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >]’
parser.cpp:136:10: required from here
/usr/include/boost/spirit/home/qi/detail/assign_to.hpp:153:20: error: no matching function for call to ‘pddl_parser::Literal::Literal(const std::vector<pddl_parser::Literal>&)’
attr = static_cast<Attribute>(val);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from parser.cpp:11:0:
./pddlast.h:23:10: note: candidate: pddl_parser::Literal::Literal()
struct Literal
^~~~~~~
./pddlast.h:23:10: note: candidate expects 0 arguments, 1 provided
./pddlast.h:23:10: note: candidate: pddl_parser::Literal::Literal(const pddl_parser::Literal&)
./pddlast.h:23:10: note: no known conversion for argument 1 from ‘const std::vector<pddl_parser::Literal>’ to ‘const pddl_parser::Literal&’
./pddlast.h:23:10: note: candidate: pddl_parser::Literal::Literal(pddl_parser::Literal&&)
./pddlast.h:23:10: note: no known conversion for argument 1 from ‘const std::vector<pddl_parser::Literal>’ to ‘pddl_parser::Literal&&’
parser.cpp:67:17:来自“pddl\u parser::domain\u parser::domain\u parser()[带迭代器=\uuuu gnu\u cxx::\uu normal\u迭代器]”的必需项
parser.cpp:136:10:此处为必填项
/usr/include/boost/spirit/home/qi/detail/assign\u to.hpp:153:20:错误:调用“pddl\u解析器::Literal::Literal(const std::vector&)”时没有匹配的函数
attr=静态(val);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
在parser.cpp:11:0中包含的文件中:
./pddlast.h:23:10:note:candidate:pddl_解析器::Literal::Literal()
结构文字
^~~~~~~
./pddlast.h:23:10:注意:候选者需要0个参数,提供1个参数
./pddlast.h:23:10:注意:候选:pddl_解析器::Literal::Literal(constpddl_解析器::Literal&)
./pddlast.h:23:10:注意:参数1从'const std::vector'到'const pddl_parser::Literal&'没有已知的转换
./pddlast.h:23:10:注意:候选:pddl_解析器::Literal::Literal(pddl_解析器::Literal&&)
./pddlast.h:23:10:注意:参数1从'const std::vector'到'pddl_parser::Literal&'没有已知的转换
如果出于测试目的将pred_列表
重新格式化为pred_列表=('('>*literal)>>')代码>虽然我去掉了(and)
,但代码编译后仍然没有成功。我的印象是我完全搞错了什么,但什么也找不到。这是我第一次尝试使用Boost::Spirit。你这么说吧
pred_list = ( '(' >> *literal) >> ')');
编译,但以下内容不编译:
pred_list = ( '(' >> lit("and") >> (*pred_list) >> ')') | literal;
如果你仔细观察,这是有道理的。由于pred_list
具有声明的属性类型std::vector
,显然重复的文本(*literal
)可能与自动属性传播的文本兼容
现在,看第二个规则定义。它解析一组无属性的文本(”(“
,”和“
,”)”
),然后<代码>*pred_列表
。如果pred_list
声明了std::vector
属性,那么*pred_list
肯定会合成std::vector
。更糟糕的是,“事后思考”使合成属性等同于变量
对。那有点乱。您的AST根本不反映规则,反之亦然
前面的路
您可能应该重述您的问题,删除失败的实现位并描述目标。如果我们能够知道真正的语法要求,/那么/我们就可以导出一个匹配的AST,它是正确的
间奏
在中场休息时,让我简化literal
的规则。(有关背景信息,请参见):
PS看来一只流浪猫也输入了额外的信息
>> ')';
最后呢
建设性的猜测
从仅仅查看示例输入来看,我打赌您只想解析表单的
(function_name arguments)
应用程序可以嵌套的位置。所以,参数要么是原子,要么是函数应用
好吧,让我们用AST,快点:
namespace AST {
using Atom = std::string;
struct Application;
using Expression = boost::variant<Atom, Application>;
struct Application {
Atom function;
std::vector<Expression> arguments;
};
}
并且启用了BOOST\u SPIRIT\u DEBUG
:
:前提条件\n
\n
获取更多高级信息)
它没有立即根据PDDL规范验证AST。我根本不确定您打算实现多少,所以我认为更通用的初学者可能会有所帮助
完整列表
#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
namespace AST {
using Atom = std::string;
struct Application;
using Expression = boost::variant<Atom, Application>;
struct Application {
Atom function;
std::vector<Expression> arguments;
friend std::ostream& operator<<(std::ostream& os, Application const& a) {
os << "(" << a.function;
for (auto& arg : a.arguments)
os << " " << arg;
return os << ")";
}
};
}
BOOST_FUSION_ADAPT_STRUCT(AST::Application, function, arguments)
namespace pddl_parser {
namespace qi = boost::spirit::qi;
template <typename Iterator>
struct Precondition : qi::grammar<Iterator, AST::Expression()> {
Precondition() : Precondition::base_type(precondition) {
using namespace qi;
atom = +(graph - '(' - ')');
application = '(' >> atom >> *expression >> ')';
expression = atom | application;
precondition = skip(ascii::space) [":precondition" >> expression];
BOOST_SPIRIT_DEBUG_NODES((precondition)(expression)(application)(atom))
}
private:
using Skipper = qi::ascii::space_type;
qi::rule<Iterator, AST::Application(), Skipper> application;
qi::rule<Iterator, AST::Expression(), Skipper> expression;
// lexemes
qi::rule<Iterator, AST::Expression()> precondition;
qi::rule<Iterator, AST::Atom()> atom;
};
}
int main() {
using It = std::string::const_iterator;
for (std::string const& input : {
R"--(:precondition
(and
(at-pos ?r ?pos)
(not (has-pos ?m ?pos))
))--"
})
{
std::cout << "-----\n";
It f = input.begin(), l = input.end();
AST::Expression precondition;
bool ok = parse(f, l, pddl_parser::Precondition<It>{}, precondition);
if (ok) {
std::cout << "Parsed " << precondition << "\n";
} else {
std::cout << "Parse Failed\n";
}
if (f != l) {
std::cout << "Remaining unparsed input: '" << std::string(f, l) << "'\n";
}
}
}
#定义BOOST\u SPIRIT\u DEBUG
#包括
#包括
名称空间AST{
使用Atom=std::string;
结构应用;
使用Expression=boost::variant;
结构应用程序{
原子函数;
向量参数;
friend std::ostream&operator>expression];
BOOST_SPIRIT_DEBUG_节点((前提条件)(表达式)(应用程序)(原子))
}
私人:
使用Skipper=qi::ascii::space\u类型;
qi:规则应用;
qi:规则表达;
//词素
规则前提;
规则原子;
};
}
int main(){
使用它=std::string::const_迭代器;
对于(标准::字符串常量和输入):{
R”--(:前提条件)
(及
(在r位置)
(没有(有pos?m?pos))
))--"
})
{
我不能谢谢你,我花了一些时间来理解并集成到我的代码的其余部分,但是现在它像一个符咒一样工作。一个更一般的附加问题:这是最佳实践吗
template <typename Iterator>
struct Precondition : qi::grammar<Iterator, AST::Expression()> {
Precondition() : Precondition::base_type(precondition) {
using namespace qi;
atom = +(graph - '(' - ')');
application = '(' >> atom >> *expression >> ')';
expression = atom | application;
precondition = skip(ascii::space) [":precondition" >> expression];
BOOST_SPIRIT_DEBUG_NODES((precondition)(expression)(application)(atom))
}
private:
using Skipper = qi::ascii::space_type;
qi::rule<Iterator, AST::Application(), Skipper> application;
qi::rule<Iterator, AST::Expression(), Skipper> expression;
// lexemes
qi::rule<Iterator, AST::Expression()> precondition;
qi::rule<Iterator, AST::Atom()> atom;
};
Parsed (and (at-pos ?r ?pos) (not (has-pos ?m ?pos)))
#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
namespace AST {
using Atom = std::string;
struct Application;
using Expression = boost::variant<Atom, Application>;
struct Application {
Atom function;
std::vector<Expression> arguments;
friend std::ostream& operator<<(std::ostream& os, Application const& a) {
os << "(" << a.function;
for (auto& arg : a.arguments)
os << " " << arg;
return os << ")";
}
};
}
BOOST_FUSION_ADAPT_STRUCT(AST::Application, function, arguments)
namespace pddl_parser {
namespace qi = boost::spirit::qi;
template <typename Iterator>
struct Precondition : qi::grammar<Iterator, AST::Expression()> {
Precondition() : Precondition::base_type(precondition) {
using namespace qi;
atom = +(graph - '(' - ')');
application = '(' >> atom >> *expression >> ')';
expression = atom | application;
precondition = skip(ascii::space) [":precondition" >> expression];
BOOST_SPIRIT_DEBUG_NODES((precondition)(expression)(application)(atom))
}
private:
using Skipper = qi::ascii::space_type;
qi::rule<Iterator, AST::Application(), Skipper> application;
qi::rule<Iterator, AST::Expression(), Skipper> expression;
// lexemes
qi::rule<Iterator, AST::Expression()> precondition;
qi::rule<Iterator, AST::Atom()> atom;
};
}
int main() {
using It = std::string::const_iterator;
for (std::string const& input : {
R"--(:precondition
(and
(at-pos ?r ?pos)
(not (has-pos ?m ?pos))
))--"
})
{
std::cout << "-----\n";
It f = input.begin(), l = input.end();
AST::Expression precondition;
bool ok = parse(f, l, pddl_parser::Precondition<It>{}, precondition);
if (ok) {
std::cout << "Parsed " << precondition << "\n";
} else {
std::cout << "Parse Failed\n";
}
if (f != l) {
std::cout << "Remaining unparsed input: '" << std::string(f, l) << "'\n";
}
}
}