gpt4 book ai didi

c++ - Boost.Spirit语法问题

转载 作者:太空狗 更新时间:2023-10-29 20:12:59 26 4
gpt4 key购买 nike

我正在尝试解析术语信息定义文本文件。我是 Boost.Spirit 的新手。我从只解析注释行、空行和终端定义的简单语法开始。正如语法中的代码注释所示,取消对 definition[_val = _1] 的注释会中断编译。为什么?我可以修复它吗?

如果我忽略实际的 terminfo 文件,我希望下面的代码能够解析这种文本:

# comment line

first definition line
second
third line

# another comment line

代码:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_eol.hpp>
#include <boost/spirit/include/qi_eoi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <vector>
#include <iostream>
#include <string>

namespace termcxx
{

namespace parser
{

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

//using qi::double_;
using ascii::space;
//using px::ref;
using px::construct;

//using qi::eps;
//using qi::lit;
using qi::_val;
using qi::_1;
using ascii::char_;
using qi::eol;
using qi::eoi;


struct context
{
int dummy;

context () = default;
context (context const &) = default;
context (std::vector<char> a)
{ }
context (std::vector<char> a, std::vector<char> b)
{ }
};

} }


BOOST_FUSION_ADAPT_STRUCT(
termcxx::parser::context,
(int, dummy))


namespace termcxx
{

namespace parser
{

template <typename Iterator>
struct parser
: qi::grammar<Iterator, context()>
{
qi::rule<Iterator, std::vector<char> > comment_line
= (*space >> '#' >> *(char_ - eol) >> (eol | eoi))[_val = _1]
;

qi::rule<Iterator, std::vector<char> > empty_line
= (*space >> (eol | eoi))[_val = _1]
;

qi::rule<Iterator, std::vector<char> > def_first_line
= (+(char_ - eol) >> (eol | eoi))[_val = _1]
;

qi::rule<Iterator, std::vector<char> > def_subsequent_line
= (+space >> +(char_ - eol) >> (eol | eoi))[_val = _1]
;

qi::rule<Iterator, std::vector<char> > definition
= (def_first_line >> *def_subsequent_line)//[_val = _1] // Uncommenting the [_val = _1] breaks compilation. Why?
;

qi::rule<Iterator, context()> start
= (*(comment_line
| empty_line
| definition))[_val = construct<context> ()]
;

parser()
: parser::base_type(start)
{ }
};

template struct parser<std::string::iterator>;

} // namespace parser

} // namespace termcxx

最佳答案

你为什么坚持指定[_val=_1] ?这是多余的,因为默认属性传播会执行此操作。其实很痛,见下文

接下来是(def_first_line >> *def_subsequent_line)的属性类型(显然)与 std::vector<char> 不兼容.也许你可以

  • 只使用默认的属性传播(它有足够的智慧继续追加)
  • 使用raw[]得到完整匹配的输入
  • 定义BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT (我不确定这是否得到很好的支持)

此外,

更新

还有几个问题:

  • 您拼错了大多数规则的属性类型(缺少 () ):

    qi::rule<Iterator, std::string()> comment_line;
    qi::rule<Iterator, std::string()> empty_line;
    qi::rule<Iterator, std::string()> def_first_line;
    qi::rule<Iterator, std::string()> def_subsequent_line;
    qi::rule<Iterator, std::string()> definition;
  • empty_line匹配于 eoi在输入结束时导致无限循环

  • 使用char_也接受空格(改用 graph:)

        def_first_line      = graph >> +(char_ - eol)         >> (eol|eoi);
  • 使用qi::space也吃线尾!使用 qi::blank相反

  • 支持可靠性:

        empty_line          = *blank >> eol;
    comment_line = *blank >> '#' >> *(char_ - eol) >> (eol|eoi);
    def_first_line = graph >> +(char_ - eol) >> (eol|eoi);
    def_subsequent_line = +blank >> +(char_ - eol) >> (eol|eoi);

    definition = (def_first_line >> *def_subsequent_line);

    start = (
    *(comment_line | empty_line | definition)
    ) [ _val = px::construct<context>() ]
    ;

    这个简单的习惯将节省您数小时的工作时间,并在与 Spirit 合作时保持理智。

  • 您可以稍微简化包含

这是一个修复版本 Live On Coliru 输出:

<start>
<try># comment line\n\nfirs</try>
<comment_line>
<try># comment line\n\nfirs</try>
<success>\nfirst definition li</success>
<attributes>[[ , c, o, m, m, e, n, t, , l, i, n, e]]</attributes>
</comment_line>
<comment_line>
<try>\nfirst definition li</try>
<fail/>
</comment_line>
<empty_line>
<try>\nfirst definition li</try>
<success>first definition lin</success>
<attributes>[[]]</attributes>
</empty_line>
<comment_line>
<try>first definition lin</try>
<fail/>
</comment_line>
<empty_line>
<try>first definition lin</try>
<fail/>
</empty_line>
<definition>
<try>first definition lin</try>
<def_first_line>
<try>first definition lin</try>
<success> second \n third li</success>
<attributes>[[f, i, r, s, t, , d, e, f, i, n, i, t, i, o, n, , l, i, n, e]]</attributes>
</def_first_line>
<def_subsequent_line>
<try> second \n third li</try>
<success> third line\n\n# anot</success>
<attributes>[[f, i, r, s, t, , d, e, f, i, n, i, t, i, o, n, , l, i, n, e, , , s, e, c, o, n, d, ]]</attributes>
</def_subsequent_line>
<def_subsequent_line>
<try> third line\n\n# anot</try>
<success>\n# another comment l</success>
<attributes>[[f, i, r, s, t, , d, e, f, i, n, i, t, i, o, n, , l, i, n, e, , , s, e, c, o, n, d, , , , t, h, i, r, d, , l, i, n, e]]</attributes>
</def_subsequent_line>
<def_subsequent_line>
<try>\n# another comment l</try>
<fail/>
</def_subsequent_line>
<success>\n# another comment l</success>
<attributes>[[f, i, r, s, t, , d, e, f, i, n, i, t, i, o, n, , l, i, n, e, , , s, e, c, o, n, d, , , , t, h, i, r, d, , l, i, n, e]]</attributes>
</definition>
<comment_line>
<try>\n# another comment l</try>
<fail/>
</comment_line>
<empty_line>
<try>\n# another comment l</try>
<success># another comment li</success>
<attributes>[[]]</attributes>
</empty_line>
<comment_line>
<try># another comment li</try>
<success></success>
<attributes>[[ , a, n, o, t, h, e, r, , c, o, m, m, e, n, t, , l, i, n, e, !]]</attributes>
</comment_line>
<comment_line>
<try></try>
<fail/>
</comment_line>
<empty_line>
<try></try>
<fail/>
</empty_line>
<definition>
<try></try>
<def_first_line>
<try></try>
<fail/>
</def_first_line>
<fail/>
</definition>
<success></success>
<attributes>[]</attributes>
</start>
Success

完整代码供引用:

#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

#include <vector>
#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;

namespace termcxx { namespace parser {

namespace ascii = boost::spirit::ascii;
namespace px = boost::phoenix;

//using qi::double_;
using ascii::blank;
//using px::ref;
using px::construct;

//using qi::eps;
//using qi::lit;
using qi::_val;
using qi::_1;
using ascii::char_;
using ascii::graph;
using qi::eol;
using qi::eoi;

struct context
{
int dummy;

context () = default;
context (context const &) = default;
context (std::vector<char> a) { }
context (std::vector<char> a, std::vector<char> b) { }
};

} }

BOOST_FUSION_ADAPT_STRUCT(termcxx::parser::context, (int, dummy))

namespace termcxx { namespace parser {

template <typename Iterator>
struct parser : qi::grammar<Iterator, context()>
{
parser() : parser::base_type(start)
{
empty_line = *blank >> eol;
comment_line = *blank >> '#' >> *(char_ - eol) >> (eol|eoi);
def_first_line = graph >> +(char_ - eol) >> (eol|eoi);
def_subsequent_line = +blank >> +(char_ - eol) >> (eol|eoi);

definition = (def_first_line >> *def_subsequent_line);

start = (
*(comment_line | empty_line | definition)
) [ _val = px::construct<context>() ]
;

BOOST_SPIRIT_DEBUG_NODES((start)(def_first_line)(def_subsequent_line)(definition)(empty_line)(comment_line))
}

private:
qi::rule<Iterator, context()> start;
qi::rule<Iterator, std::string()> comment_line;
qi::rule<Iterator, std::string()> empty_line;
qi::rule<Iterator, std::string()> def_first_line;
qi::rule<Iterator, std::string()> def_subsequent_line;
qi::rule<Iterator, std::string()> definition;
};

} }

int main()
{
using It = boost::spirit::istream_iterator;
termcxx::parser::parser<It> g;

It f(std::cin >> std::noskipws), l;
termcxx::parser::context data;
if (qi::parse(f,l,g,data))
std::cout << "Success\n";
else
std::cout << "Failure\n";

if (f != l)
std::cout << "Remaining input: '" << std::string(f,l) << "'\n";
}

关于c++ - Boost.Spirit语法问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24251565/

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