gpt4 book ai didi

c++ - 使用 boost::spirit,我如何要求记录的一部分在其自己的行上?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:29:28 24 4
gpt4 key购买 nike

我有一个记录解析器,它抛出多个异常之一以指示哪个规则失败。

前题:

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/classic_position_iterator.hpp>

using namespace boost::spirit;
using namespace boost::spirit::ascii;
using namespace boost::spirit::qi;
using namespace boost::spirit::qi::labels;

using boost::phoenix::function;
using boost::phoenix::ref;
using boost::spirit::qi::eol;
using boost::spirit::qi::fail;
using boost::spirit::qi::lit;
using boost::spirit::qi::on_error;

using BOOST_SPIRIT_CLASSIC_NS::file_position;
using BOOST_SPIRIT_CLASSIC_NS::position_iterator;

我们使用 position_iterator来自 Spirit.Classic , 所以下面的流插入运算符很方便。

std::ostream&
operator<<(std::ostream& o, const file_position &fp)
{
o << fp.file << ": " << fp.line << ',' << fp.column;
return o;
}

模板 err_t 分解出用于抛出与不同形式的解析失败相关的异常的样板。

template <typename Exception>
struct err_t {
template <typename, typename, typename>
struct result { typedef void type; };

template <typename Iterator>
void operator() (info const &what, Iterator errPos, Iterator last) const
{
std::stringstream ss;
ss << errPos.get_position()
<< ": expecting " << what
<< " near '" << std::string(errPos, last) << "'\n";
throw Exception(ss.str());
}
};

与它们的 err_t 包装器一起使用的异常:

class MissingA : public std::runtime_error {
public: MissingA(const std::string &s) : std::runtime_error(s) {}
};

class MissingB : public std::runtime_error {
public: MissingB(const std::string &s) : std::runtime_error(s) {}
};

class MissingC : public std::runtime_error {
public: MissingC(const std::string &s) : std::runtime_error(s) {}
};

function<err_t<MissingA> > const missingA = err_t<MissingA>();
function<err_t<MissingB> > const missingB = err_t<MissingB>();
function<err_t<MissingC> > const missingC = err_t<MissingC>();
function<err_t<std::runtime_error> > const other_error =
err_t<std::runtime_error>();

语法寻找简单的序列。没有eps , start 规则在空输入时失败而不是 a

template <typename Iterator, typename Skipper>
struct my_grammar
: grammar<Iterator, Skipper>
{
my_grammar(int &result)
: my_grammar::base_type(start)
, result(result)
{
a = eps > lit("Header A") > eol;
b = eps > lit("Header B") > eol;
c = eps > lit("C:") > int_[ref(result) = _1] > eol;
start = a > b > c;

a.name("A");
b.name("B");
c.name("C");

on_error<fail>(start, other_error(_4, _3, _2));
on_error<fail>(a, missingA(_4, _3, _2));
on_error<fail>(b, missingB(_4, _3, _2));
on_error<fail>(c, missingC(_4, _3, _2));
}

rule<Iterator, Skipper> start;
rule<Iterator, Skipper> a;
rule<Iterator, Skipper> b;
rule<Iterator, Skipper> c;
int &result;
};

my_parse 中,我们将流的内容转储到 std::string 中,并使用 position_iterator 来跟踪解析的位置。

int
my_parse(const std::string &path, std::istream &is)
{
std::string buf;
is.unsetf(std::ios::skipws);
std::copy(std::istream_iterator<char>(is),
std::istream_iterator<char>(),
std::back_inserter(buf));

typedef position_iterator<std::string::const_iterator> itertype;
typedef my_grammar<itertype, boost::spirit::ascii::space_type> grammar;
itertype it(buf.begin(), buf.end(), path);
itertype end;

int result;
grammar g(result);

bool r = phrase_parse(it, end, g, boost::spirit::ascii::space);
if (r && it == end) {
std::cerr << "success!\n";
return result;
}
else {
file_position fpos = it.get_position();
std::cerr << "parse failed at " << fpos << '\n';
return -9999;
}
}

最后是主程序

int main()
{
std::stringstream ss;
ss << "Header A\n"
<< "Header B\n"
<< "C: 3\n";

int val = my_parse("path", ss);
std::cout << "val = " << val << '\n';

return 0;
}

上面的代码抛出MissingA:

terminate called after throwing an instance of 'MissingA'  what():  path: 2,1: expecting  near 'Header BC: 3'

我认为船长可能已经使用了换行符,但尝试 lexeme[eol] 却产生了相同的结果。

我一定遗漏了一些明显的东西,因为这似乎是要编写的最微不足道的解析器之一。我做错了什么?

最佳答案

是的,船长吃换行符。 lexeme[eol] 也无济于事,因为 lexeme 指令在切换到无船长模式之前调用船长(更多详细信息,请参见 here)。

为了避免跳过换行符,要么使用不同的 skipper 类型,要么将 eol 组件包装到 no_skip[eol] 中,这在语义上等同于 lexeme[],除了它不调用船长。不过请注意,no_skip[] 是最近才添加的,因此它将仅在下一个版本 (Boost V1.43) 中可用。但它已经在 Boost SVN 中(请参阅 here 了解初步文档)。

关于c++ - 使用 boost::spirit,我如何要求记录的一部分在其自己的行上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2428371/

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