就像其他许多问题一样,我正在尝试使用Boost.Spirit.Qi将简单语法解析为结构树.
我会尝试提炼我想要做的最简单的案例.我有:
struct Integer {
int value;
};
BOOST_FUSION_ADAPT_STRUCT(Integer, (int, value))
Run Code Online (Sandbox Code Playgroud)
后来,在语法结构中,我有以下成员变量:
qi::rule<Iterator, Integer> integer;
Run Code Online (Sandbox Code Playgroud)
这是我定义的
integer = qi::int_;
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试实际解析整数时,使用
qi::phrase_parse(iter, end, g, space, myInteger);
Run Code Online (Sandbox Code Playgroud)
myInteger.value在成功解析后始终未初始化.同样,我尝试了以下定义(显然那些不编译的定义是错误的):
integer = qi::int_[qi::_val = qi::_1]; //compiles, uninitialized value
integer = qi::int_[qi::_r1 = qi::_1]; //doesn't compile
integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; //doesn't
integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; //doesn't
Run Code Online (Sandbox Code Playgroud)
显然,我误解了一些关于精神,凤凰或其他东西的东西.我的理解是,当方括号中的部分作为函数对象执行时,这里qi::_1的第一个属性qi::int_应该表示已解析的整数.我假设函数对象将采用封闭integer属性qi::_val并尝试将解析后的整数分配给它.我的猜测是因为我的BOOST_FUSION_ADAPT_STRUCT调用,两者兼容,从静态分析的角度来看,情况似乎确实如此,但数据并未得到保留.
是否有参考(&)指定我在某处或某处遗漏?
到目前为止,我的语法一直使用标准boost::spirit::ascii::space/ boost::spirit::ascii::space_type队长.
我有一些使用船长的规则和一些不使用船长的规则
qi::rule<Iterator, PTR<Expression>(), ascii::space_type> expression;
qi::rule<Iterator, PTR<Term>()> term;
Run Code Online (Sandbox Code Playgroud)
当我在跳过非终结符(例如term)中使用非跳过非终结符(例如expression)时,一切都像我期望的那样工作 - 空格只对term非终结内部很重要.
此外,到目前为止,我一直很好,包括使用不使用qi::skip重新跳过的非终端内的队长的非终结者,例如
index = (qi::lit('[') >> qi::skip(ascii::space)[explist >> qi::lit(']')]);
Run Code Online (Sandbox Code Playgroud)
这样,在[]括号内部的空白并不重要,但在外面.
但是,现在我想添加我自己的自定义队列(我想让换行有意义,然后添加评论跳过).我的船长语法看起来像:
struct skip_grammar : qi::grammar<Iterator> {
qi::rule<Iterator> start;
skip_grammar() : skip_grammar::base_type(start) {
start = qi::char_("\t\r ");
}
};
Run Code Online (Sandbox Code Playgroud)
我已经能够将它添加到我的规则定义中就好了
qi::rule<Iterator, PTR<Expression>(), skip_grammar> expression;
Run Code Online (Sandbox Code Playgroud)
但我似乎无法弄清楚如何使用我的跳过语法作为参数qi::skip(和替换ascii::space).我尝试使用类型,本地实例变量和全局实例变量.我得到的最远的就是抱怨我的skip_grammar需要一个拷贝构造函数.所以我尝试将一个复制构造函数添加到我的跳过语法中,但显然boost::noncopyable基类是有原因的,因为我的二进制文件几乎立即就被发现了.
我应该如何使用它?
谢谢
首先,如果使用Boost Variant或Utree更容易,那么我将与他们达成和解,我将尝试在另一个主题中解决我们的问题.但是,我非常希望能够像下面一样构建一棵树.
背景,如果你想直接讨论这个问题,请忽略:我希望能够构建一个解析像
"({a} == 0) && ({b} > 5)"
Run Code Online (Sandbox Code Playgroud)
或标准的数学表达式
"(2 * a) + b"
Run Code Online (Sandbox Code Playgroud)
然后我将在评估树之前定义a和b是什么,如下所示:
a = 10;
double val = myExpression->Evaluate();
Run Code Online (Sandbox Code Playgroud)
我的问题来自于当我尝试构建try以将字符串解析为我的表达式树时.我正在使用一个抽象类"Expression",然后导出"变量","常量"和"二进制"表达式(它也会做一元,但它不应该影响我的问题.我一直有使用我的规则添加到树的问题所以我显然做错了什么.我很难绕着属性缠头.
我的树如下(Tree.h):
class BinaryExpression;
typedef double (*func)(double, double);
class Expression
{
public:
virtual double Evaluate() = 0;
};
class BinaryExpression : public Expression
{
private:
Expression* lhs;
Expression* rhs;
func method;
double Evaluate();
public:
BinaryExpression(void);
BinaryExpression(char op, Expression* lhs, Expression* rhs);
BinaryExpression(char op);
void operator()(Expression* lhs, Expression* rhs);
};
class ConstantExpression : public Expression
{
private: …Run Code Online (Sandbox Code Playgroud) 我对提升精神队长有困难.
我需要解析一个这样的文件:
ROW int
int [int, int]
int [int, int]
...
Run Code Online (Sandbox Code Playgroud)
只有在第一个int之后添加'_'时,我能够毫无问题地解析它(感谢stackoverflow;).
事实上,我认为船长在第一个int之后吃了行尾,所以第一个和第二个(在第二行)看起来只有一个int.我不明白如何保持eol但是吃空间.我找到了使用自定义解析器的示例,如此处和此处.
我尝试了qi :: blank,自定义解析器,单一规则点亮('')无论我使用什么队长,空间和eol总是吃.
我的语法是:
一行:
struct rowType
{
unsigned int number;
std::list<unsigned int> list;
};
Run Code Online (Sandbox Code Playgroud)
存储在结构中的完整问题:
struct problemType
{
unsigned int ROW;
std::vector<rowType> rows;
};
Run Code Online (Sandbox Code Playgroud)
行解析器:
template<typename Iterator>
struct row_parser : qi::grammar<Iterator, rowType(), qi::space_type>
{
row_parser() : row_parser::base_type(start)
{
list = '[' >> -(qi::int_ % ',') >> ']';
start = qi::int_ >> list;
}
qi::rule<Iterator, rowType(), qi::space_type> start;
qi::rule<Iterator, std::list<unsigned int>(), qi::space_type> list; …Run Code Online (Sandbox Code Playgroud) 在我的boost::spirit语法中,我有以下片段;
implicit_method_declaration = (-(qi::token(ABSTRACT)) >> ...)
Run Code Online (Sandbox Code Playgroud)
该类型-(qi::token(ABSTRACT)是boost::optional<boost::iterator_range<std::string::iterator>>不过我只使用此结构来检查,如果抽象关键字,其实是存在,那就是,我宁愿-(qi::token(ABSTRACT)有型bool与价值boost::optional<...> operator bool() const.
我将如何实现这一目标?
我希望我的boost :: spirit-based解析器能够解析文件,将解析后的规则转换为不同的类型,并发出包含它找到的所有匹配项的向量.作为属性发出的所有类型都应该从基类型继承,例如:
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapt_struct.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>
struct CommandBase
{
virtual void commandAction()
{
std::cout << "This is a base command. You should never see this!" << std::endl;
//Boost::spirit seems to get mad if I make this purely virtual. Clearly I'm doing it wrong.
}
};
struct CommandTypeA : public CommandBase
{
int valueA;
int valueB;
virtual void commandAction()
{
std::cout << "CommandType A! ValueA: " << valueA << " ValueB: " << valueB << std::endl; …Run Code Online (Sandbox Code Playgroud) 我正在寻找使用boost :: spirit :: lex编写词法分析器,但我能找到的所有示例似乎都假设您已将整个文件首先读入RAM.我想写一个不需要整个字符串在RAM中的词法分析器,这可能吗?或者我需要使用其他东西吗?
我尝试使用istream_iterator,但是boost会给我一个编译错误,除非我使用const char*作为迭代器类型.
例如,我能找到的所有例子基本上都是这样做的:
lex_functor_type< lex::lexertl::lexer<> > lex_functor;
// assumes entire file is in memory
char const* first = str.c_str();
char const* last = &first[str.size()];
bool r = lex::tokenize(first, last, lex_functor,
boost::bind(lex_callback_functor(), _1, ... ));
Run Code Online (Sandbox Code Playgroud)
另外,是否有可能以某种方式确定lex令牌的行/列号?
谢谢!
我的目标是让我的qi::grammar返回属性.spirit::lexer尽管如此,我在这方面遇到了很大的困难.
我希望用下面给定的语法,如果我用它来调用它spirit::qi::parse(begin, end, grammar, output);,struct ident output它将具有解析的lexeme的内容.
该错误似乎主要流出这一行: start %= lexer.identifier;
g++ -g -c -O0 -Wall -DBOOST_SPIRIT_DEBUG -DBOOST_SPIRIT_LEXERTL_DEBUG -DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT reduced.cpp
Run Code Online (Sandbox Code Playgroud)
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/lex.hpp>
#include <boost/spirit/home/lex/lexer/lexertl/lexer.hpp>
#include <boost/spirit/home/qi.hpp>
namespace spirit = boost::spirit;
struct ident {
std::string value;
};
BOOST_FUSION_ADAPT_STRUCT(ident,
(std::string, value)
)
struct my_lexer : spirit::lex::lexer< spirit::lex::lexertl::actor_lexer<> > {
spirit::lex::token_def<std::string> identifier;
};
struct my_grammar : spirit::qi::grammar<my_lexer::iterator_type, ident()> {
my_grammar(const …Run Code Online (Sandbox Code Playgroud) 我有以下规则boost::spirit:
typedef boost::tuple<int, int> Entry;
qi::rule<Iterator, Entry(), Skipper> entry;
entry = qi::int_ >> qi::int_;
Run Code Online (Sandbox Code Playgroud)
但第二个int没有写入元组.有没有办法让它工作而不必使用boost::fusion::tuple?
如果我使用它,它可以工作std::pair,为什么我不能使用boost::tuple?
这是一个完整的编译示例:
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/tuple.hpp>
#include <boost/tuple/tuple.hpp>
namespace qi = boost::spirit::qi;
// works:
// #include <boost/fusion/include/std_pair.hpp>
// typedef std::pair<int, int> Entry;
// doesn't work:
typedef boost::tuple<int, int> Entry;
template <typename Iterator, typename Skipper>
struct MyGrammar : qi::grammar<Iterator, Entry(), Skipper> {
MyGrammar() : MyGrammar::base_type(entry) {
entry = qi::int_ >> qi::int_;
} …Run Code Online (Sandbox Code Playgroud) 我的目标是创建一个解决方法,以便我可以在Boost Spirit Qi语义操作中使用C++ 11 lambdas,同时仍然可以访问更多扩展的qi占位符集,例如qi :: _ pass或qi :: _ r1,必须从上下文对象手动提取它们.我希望避免为一些非平凡的解析逻辑编写Phoenix lambdas,更喜欢C++ 11 lambdas中更直接的C++语法和语义.
下面的代码代表了我有一个解决方法的想法.我的想法是使用phoenix :: bind绑定到lambda并将它传递给我需要的特定占位符.但是,我得到了一个极长的模板编译器错误(gcc 4.7.0,Boost 1.54),我没有专业知识来解释.我选择了我认为最相关的部分并将其发布在代码下方.
我想知道我是否可以使用Boost Spirit在此代码中尝试做什么,如果有人能为我解释错误消息并告诉我出了什么问题.
#include <string>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
namespace phoenix = boost::phoenix;
int main() {
std::string input{"test1 test2 test3 FOO!"};
typedef decltype(input.begin()) StringIter;
qi::rule<StringIter, std::string()> parser =
*(
qi::char_
[
phoenix::bind(
[] (char value) {
std::cerr << value << std::endl;
},
qi::_1
)
]
);
qi::parse(input.begin(), input.end(), parser);
}
Run Code Online (Sandbox Code Playgroud)
(注意:我知道这个代码执行的特定任务对于直接的Phoenix结构会更简单,或者甚至可以通过Boost Spirit更新直接允许单参数C++ …