提升精神气:在某些条件下,船长解析器不会跳过

时间:2016-05-27 02:28:29

标签: c++ boost boost-spirit boost-spirit-qi

我目前正在实施一个解析器,该解析器在最强大的"匹配精神::气。对于这样的事情有有意义的应用。例如,匹配对简单引用(例如" willy")或命名空间限定引用(例如" willy :: anton")的引用。这不是我真正的现实案例,但我想这几乎是不言自明的。至少它帮助我找到了问题。

我找到了解决方案。当没有涉及队长解析器时(即没有什么可跳过),它完美地工作。如果存在需要跳过的区域,则无法按预期工作。

我相信,我追查了这个问题。似乎在某些条件下,空间实际上并没有被跳过,尽管它们应该是。

下面是一个非常有用的例子。它循环一些规则和一些输入以提供足够的信息。如果在启用BOOST_SPIRIT_DEBUG的情况下运行它,则会特别获得输出:

<qualifier>
  <try>  ::      anton</try>
  <fail/>
</qualifier>

我认为,这个不应该失败。我猜对了吗?有没有人知道解决这个问题的方法?或者只是我对气语的理解不足?非常感谢您的宝贵时间。 :)

我的环境:MSVC 2015最新版,目标是win32控制台

#define BOOST_SPIRIT_DEBUG
#include <io.h>
#include<map>
#include <boost/spirit/include/qi.hpp>

typedef std::string::const_iterator iterator_type;
namespace qi = boost::spirit::qi;
using map_type = std::map<std::string, qi::rule<iterator_type, std::string()>&>;

namespace maxence { namespace parser {

    template <typename Iterator>
    struct ident : qi::grammar<Iterator, std::string()>
    {
        ident();
        qi::rule<Iterator, std::string()>
            id, id_raw;

        qi::rule<Iterator, std::string()>
            not_used,
            qualifier, 
            qualified_id, simple_id,
            id_reference, id_reference_final;

        map_type rules = {
            { "E1", id },
            { "E2", id_raw}
        };
    };

    template <typename Iterator>
    // we actually don't need the start rule (see below)
    ident<Iterator>::ident() : ident::base_type(not_used)
    {

        id_reference = (!simple_id >> qualified_id) | (!qualified_id >> simple_id);
        id_reference_final = id_reference;

        ///////////////////////////////////////////////////
        // standard simple id (not followed by 
        // delimiter "::")
        simple_id = (qi::alpha | '_') >> *(qi::alnum | '_') >> !qi::lit("::");

        ///////////////////////////////////////////////////
        // this is qualifier <- "::" simple_id 
        // I repeat the simple_id pattern here to make sure 
        // this demo has no  "early match" issues
        qualifier = qi::string("::") > (qi::alpha | '_') >> *(qi::alnum | '_');

        ///////////////////////////////////////////////////
        // this is: qualified_id <- simple_id qualifier*
        qualified_id = (qi::alpha | '_') >> *(qi::alnum | '_') >> +(qualifier) >> !qi::lit("::");

        id = id_reference_final;
        id_raw = qi::raw[id_reference_final];

        BOOST_SPIRIT_DEBUG_NODES(
            (id)
            (id_raw)
            (qualifier)
            (qualified_id)
            (simple_id)
            (id_reference)
            (id_reference_final)
        )
    }

}}

int main()
{
    maxence::parser::ident<iterator_type> ident;
    using ss_map_type = std::map<std::string, std::string>;
    ss_map_type parser_input =
    {
        { "Simple id (behaves ok)", "willy" },              
        { "Qualified id (behaves ok)", "willy::anton" },    
        { "Skipper involved (unexpected)", "willy  ::      anton" }
    };

    for (ss_map_type::const_iterator input = parser_input.begin(); input != parser_input.end(); input++) {
        for (map_type::const_iterator example = ident.rules.begin(); example != ident.rules.end(); example++) {
            std::string to_parse = input->second;
            std::string result;
            std::string parser_name = (example->second).name();
            std::cout << "--------------------------------------------" << std::endl;
            std::cout << "Description: " << input->first << std::endl;
            std::cout << "Parser [" << parser_name << "] parsing [" << to_parse << "]" << std::endl;
            auto b(to_parse.begin()), e(to_parse.end());

            // --- test for parser success
            bool success = qi::phrase_parse(b, e, (example)->second, qi::space, result);
            if (success) std::cout << "Parser succeeded. Result: " << result << std::endl;
            else std::cout << " Parser failed. " << std::endl;

            //--- test for EOI
            if (b == e) {
                std::cout << "EOI reached.";
                if (success) std::cout << " The sun is shining brightly. :)";
            } else {
                std::cout << "Failure: EOI not reached. Remaining: [";
                while (b != e) std::cout << *b++; std::cout << "]";
            }
            std::cout << std::endl << "--------------------------------------------" << std::endl;
        }
    }
    return 0;
}

0 个答案:

没有答案
相关问题