Boost Spirit x3 - 解析器无法识别行尾

Boost Spirit x3 - parser doesn't recognize end of line

我正在尝试解析 .obj 文件,但我不知道如何让 x3 在行尾停止。

我的代码如下所示:

#include <iostream>


#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/support/iterators/istream_iterator.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <fstream>
#include <sstream>

namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;

  

namespace objParser
{
    template <typename Iterator>
    bool parse_obj(Iterator first, Iterator last)
    {
        using boost::spirit::x3::char_;
        using boost::spirit::x3::eol;
        using boost::spirit::x3::eps;
        using boost::spirit::x3::_attr;
        using boost::spirit::x3::phrase_parse;

        auto printText = [&](auto& ctx) { std::cout << _attr(ctx) << std::endl;                 };

        bool result = phrase_parse(first, last,

            //  Begin grammar
            (
                *( char_('#') >> *(~char_('\r\n'))[printText] >> eol)
            ),
            //  End grammar

            eps(false));


        if (!result || first != last) // fail if we did not get a full match
            return false;
        return result;
    }
}

int main()
{
    std::string modelPath = "file.obj";
    
    std::ifstream inFile(modelPath, std::ifstream::in);
    if (inFile.good()) {
        std::cout << "input found" << std::endl;
    }
   
    typedef std::istreambuf_iterator<char> base_iterator_type;
    typedef boost::spirit::multi_pass<base_iterator_type> forward_iterator_type;
    base_iterator_type in_begin(inFile);
    base_iterator_type in_end;
    forward_iterator_type fwd_begin = boost::spirit::make_default_multi_pass(in_begin);
    forward_iterator_type fwd_end = boost::spirit::make_default_multi_pass(in_end);

    objParser::parse_obj(fwd_begin, fwd_end);

    return 0;
}

语法应该以“#”开头的注释并打印所有内容直到行尾。相反,解析器会打印所有内容,直到文件末尾。 另外,我如何打包 *(~char_('\r\n'))[printText] 以便将行内容作为字符串?目前每个字符都是单独打印的。

正如评论者所说。这就是为什么 you enable warnings:

<source>:33:43: warning: multi-character character constant [-Wmultichar]
   33 |                 *( char_('#') >> *(~char_('\r\n'))[printText] >> eol)
      |                                           ^~~~~~

接下来,simplify-time:https://compiler-explorer.com/z/hdWhsndMe

return parse(first, last,                                          //
             *('#' >> *(~x3::char_("\r\n"))[printText] >> x3::eol) //
                 >> x3::eoi                                        //
);

改用 eoi 指令,如果不打算跳过,则不使用 phrase_parse

Also how can I pack the *(~char_('\r\n'))[printText] so, that it takes the line content as a string? currently every char is printed separately.

就这么说吧:https://compiler-explorer.com/z/GaPMdzoGr

return parse(first, last,                                          //
             *('#' >> (*~x3::char_("\r\n"))[printText] >> x3::eol) //
                 >> x3::eoi);

演示

#include <boost/spirit/home/support/iterators/istream_iterator.hpp>
#include <boost/spirit/home/x3.hpp>
#include <sstream>
#include <iostream>

namespace x3    = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;

namespace objParser {
    template <typename Iterator> bool parse_obj(Iterator first, Iterator last) {
        auto printText = [&](auto& ctx) {
            std::cout << _attr(ctx) << std::endl;
        };

        return parse(first, last,                                          //
                    *('#' >> (*~x3::char_("\r\n"))[printText] >> x3::eol) //
                        >> x3::eoi);
    }
} // namespace objParser

int main() {
    std::istringstream inFile(R"(# this is presumably a comment
# and so is this
    )");

    boost::spirit::istream_iterator b(inFile >> std::noskipws), e;
    objParser::parse_obj(b, e);
}

版画

 this is presumably a comment
 and so is this