如何使用精神解析器获取错误位置 [英] How to get error position using the spirit parser

查看:131
本文介绍了如何使用精神解析器获取错误位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个简单的解析器与精神,类似于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);

//将输入迭代器转换为向前迭代器,由精神解析器使用
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;

//用位置迭代器包装前向迭代器,记录位置
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<<
文件中解析错误< 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 它工作正常,但当然它不跟踪错误位置。非常奇怪的是,这里工作正常。所以也许这个问题与我的语法有关。下面是:

 模板< typename Iterator,typename Skipper> 
struct property_set_grammar:qi :: grammar< Iterator,PropertyList(),
Skipper>
{
qi :: rule< Iterator,Property(),Skipper>支柱;
qi :: rule< Iterator,std :: string(),Skipper>名称;
qi :: rule< Iterator,std :: string(),Skipper>类型;
qi :: rule< Iterator,std :: string(),Skipper>值;
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;
使用qi :: alpha;
使用qi :: alnum;
使用qi :: lexeme;
using qi :: char_;

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

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

我使用g ++(Ubuntu / Linaro 4.7.2-2ubuntu1)4.7.2和1.50版提升库。



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

解决方案

:position_iterator有bug。



您可以按照 position_iterator .com / questions / 14005273 / strange-error-with-boostspiritposition-iterator2>这里



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



此外,从 istream 解析时,请务必设置 noskipws manip:

  //是>> std :: noskipws; 

EDIT: istreambuf_iterator不需要


I wrote a simple parser with spirit, akin to json (but simpler and more specialised). By following the advice in here, I tried to implement error handling by tracking the error position. In particular, my parsing function is as follows

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;
}

Unfortunately, it does not work. Function phrase_parse always returns false immediately, both for correct and for incorrect files, and never raises any exception.

However, when I modify the above code to use a simple forward_iterator instead of the classic::position_iterator2 it works fine, but of course it does not track the error position. The very strange thing is that the original example in here works fine. So maybe the problem is related to my grammar. Here it follows:

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) > '}' > ';';
    }
};   

I am using g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2 and version 1.50 of the boost libraries.

Is there anything stupid that I am overlooking? If needed, I can provide the complete code (it's just a few files).

解决方案

It seems that boost::spirit::position_iterator is bugged.

You can edit the headers of position_iterator as suggested in the answer here.

Or you can implement your own position_iterator, I did this by basically copy-and-paste the original code of boost::spirit::position_iterator, then remove some unneeded stuff.

Also, when parsing from istream, make sure to set the noskipws manip:

//is >> std::noskipws;

EDIT: Not needed with istreambuf_iterator

这篇关于如何使用精神解析器获取错误位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆