2

我用精神写了一个简单的解析器,类似于 json(但更简单,更专业)。按照这里的建议,我尝试通过跟踪错误位置来实现错误处理。特别是我的解析函数如下

bool parse_properties(std::istream& is, const std::string &filename, PropertyList &pset)
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;
    namespace classic = boost::spirit::classic;

    typedef std::istreambuf_iterator<char> base_iterator_type;
    base_iterator_type in_begin(is);

    // convert input iterator to forward iterator, usable by spirit parser
    typedef boost::spirit::multi_pass<base_iterator_type> forward_iterator_type;
    forward_iterator_type fwd_begin = boost::spirit::make_default_multi_pass(in_begin);
    forward_iterator_type fwd_end;

    // wrap forward iterator with position iterator, to record the position
    typedef classic::position_iterator2<forward_iterator_type> pos_iterator_type;
    pos_iterator_type position_begin(fwd_begin, fwd_end, filename);
    pos_iterator_type position_end;

    qi::rule<pos_iterator_type> skipper = ascii::space | 
    '#' >> *(ascii::char_ - qi::eol) >> qi::eol; 

    property_set_grammar<pos_iterator_type, qi::rule<pos_iterator_type> > g;
    bool r = false;
    try {
        r = phrase_parse(position_begin, 
                         position_end, 
             g, skipper, pset);
    }
    catch(const qi::expectation_failure<pos_iterator_type>& e) {
        const classic::file_position_base<std::string>& pos = e.first.get_position();
        std::stringstream msg;
        msg <<
            "parse error at file " << pos.file <<
            " line " << pos.line << " column " << pos.column << std::endl <<
            "'" << e.first.get_currentline() << "'" << std::endl <<
            std::setw(pos.column) << " " << "^- here";
        throw std::runtime_error(msg.str());
    }

    return r;
}

不幸的是,它不起作用。phrase_parse对于正确和不正确的文件,函数总是立即返回 false,并且从不引发任何异常。

但是,当我修改上面的代码以使用简单forward_iterator的而不是它时,classic::position_iterator2它工作正常,但它当然不会跟踪错误位置。非常奇怪的是,这里的原始示例运行良好。所以也许这个问题与我的语法有关。如下:

template <typename Iterator, typename Skipper>
struct property_set_grammar : qi::grammar<Iterator, PropertyList(),
                                          Skipper>
{
    qi::rule<Iterator, Property(), Skipper> prop;
    qi::rule<Iterator, std::string(), Skipper> name;
    qi::rule<Iterator, std::string(), Skipper> type;
    qi::rule<Iterator, std::string(), Skipper> value;
    qi::rule<Iterator, std::string(), Skipper> value_simple;
    qi::rule<Iterator, std::string(), Skipper> value_quoted;
    qi::rule<Iterator, PropertyList(), Skipper> plist;

    property_set_grammar() : 
        property_set_grammar::base_type(plist, "Set of Properties") {
        using qi::lit;
        using qi::alpha;
        using qi::alnum;
        using qi::lexeme;
        using qi::char_;

        name = lexeme[alpha >> *alnum];
        type = lexeme[alpha >> *alnum];
        value_simple = lexeme[*(alnum - lit('"'))];
        value_quoted = lit('"') > lexeme[*(char_ - lit('"'))] > lit('"');
        value = (value_quoted | value_simple);

        prop = name >> '=' > value > ';';
        plist = type >> '(' > name > ')' > '{' >> *(prop | plist) > '}' > ';';
    }
};   

我正在使用 g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2 和 1.50 版的 boost 库。

有什么我忽略的愚蠢吗?如果需要,我可以提供完整的代码(只是几个文件)。

4

1 回答 1

2

似乎 boost::spirit::position_iterator 被窃听了。

您可以按照此处position_iterator答案中的建议编辑标题。

或者你可以实现你自己的 position_iterator,我基本上是通过复制和粘贴的原始代码来实现的boost::spirit::position_iterator,然后删除一些不需要的东西。

此外,从 解析时istream,请确保设置noskipwsmanip:

//is >> std::noskipws;

编辑:不需要 istreambuf_iterator

于 2013-01-10T11:52:45.383 回答