如何在错误消息“与众不同"的可能符号中增强精神? [英] how to get boost spirit build in error message 'distinct' possible symbols?

查看:62
本文介绍了如何在错误消息“与众不同"的可能符号中增强精神?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个语法,其中输入了规则集的关键字.

i have a grammar with key words on entry for a rule set.

下面的一些伪代码..如果有人现在写"XPUBLIC",作为输入,解析器在catch处理程序中为'boost :: spirit :: qi :: expectation_failureparser :: Iterator :: what_'创建一个'distinct'异常.可以,但是解析器还可以返回此节点上可能的条目的列表.同样,on_error处理程序获得相等的输入.有没有一种方法可以使解析器上的可能的输入符号失败?在该示例中,我想获得"PUBLIC","PRIVATE"..

some pseudo code below .. if somebody write now "XPUBLIC" as input the parser create an 'distinct' exception in the catch handler for 'boost::spirit::qi::expectation_failureparser::Iterator::what_'. This is ok but the parser could also return the list of possible entries at this node. Also the on_error handler get equal inputs. Is there a way to get the possible entry symbols on parser fails? In this sample i like to get "PUBLIC","PRIVATE" ..

#define nocaselit(p) distinct(boost::spirit::standard_wide::alnum | L'_')[no_case[p]]

rule=  
  nocaselit(L"PUBLIC")
| nocaselit(L"PRIVATE")
| nocaselit(L"PROTECTED")
| nocaselit(L"SHARED")

推荐答案

当我们简化情况以跳过 distinct 指令时,这就是处理 info 的方式code>从期望失败中提取替代方案:

When we simplify the situation to skip the distinct directive, then this is how you could deal with the info from the expectation failure to extract the alternatives:

在Coliru直播

Live On Coliru

#include <boost/spirit/include/qi.hpp>
namespace enc = boost::spirit::standard_wide;
namespace qi = boost::spirit::qi;
using It = std::wstring::const_iterator;

#define kw(p) qi::lit(p)

int main() {
    qi::rule<It> rule;

    rule
        = qi::eps > 
            ( kw(L"PUBLIC")
            | kw(L"PRIVATE")
            | kw(L"PROTECTED")
            | kw(L"SHARED")
            )
        ;

    for (std::wstring const input : {
            L"PUBLIC",
            L"PRIVATE",
            L"PROTECTED",
            L"SHARED",
            L"XPUBLIC", // obviously no match
            L"PUBLICX", // actually test of distinct
        }) 
    try {
        It f = begin(input), l = end(input);
        auto ok = qi::parse(f, l, rule);
        std::wcout << input << " " << std::boolalpha << ok << std::endl;
    } catch(qi::expectation_failure<It> const& ef) {

        auto value = ef.what_.value;
        auto elements = boost::get<std::list<boost::spirit::info> >(value);

        std::ostringstream oss;
        oss << ef.what_.tag << "(";
        for (auto el : elements) oss << " " << el;
        oss << " )";

        std::wcout << input << " -> Expected " << oss.str().c_str() << std::endl;
    }
}

打印

PUBLIC true
PRIVATE true
PROTECTED true
SHARED true
XPUBLIC -> Expected alternative( "PUBLIC" "PRIVATE" "PROTECTED" "SHARED" )
PUBLICX true

请注意, spirit :: info 的内部假定采用UTF8编码的 std :: string .在这里,我对codecvt方面并不过分.作为练习,我将可靠地转换为宽字符串.

Note that the internals of spirit::info assume std::string in UTF8 encoding. I'm not overly explicit here with codecvt facets. I'll leave a reliable conversion to wide strings as an exercise to the reader.

使用 distinct()

幼稚的方法将产生以下输出:

With distinct()

The naive approach will result in this output:

PUBLIC true
PRIVATE true
PROTECTED true
SHARED true
XPUBLIC -> Expected alternative( <distinct> <distinct> <distinct> <disti
nct> )
PUBLICX -> Expected alternative( <distinct> <distinct> <distinct> <disti
nct> )

可悲的是,这可能不是您想要的.更糟糕的是,这也在存储库指令中进行了硬编码:

Sadly, that is probably not what you want. Even worse, that's also hardcoded in the repository directive:

template <typename Context>
info what(Context& /*ctx*/) const
{
    return info("distinct");
}

如果我们可以 公正 将其更改为:

If we could just change that to read:

template <typename Context>
info what(Context& ctx) const
{
    return info("distinct", subject.what(ctx));
}

我们本来可以解决的.为了不过多影响库的实现细节,让我们将 distinct 指令子类化为 my_distinct :

We would have solved things. In order to not impinge on the library implementation details too much, let's subclass the distinct directive into my_distinct to that:

template <typename Subject, typename Tail, typename Modifier>
struct my_distinct_parser
  : distinct_parser<Subject, Tail, Modifier>
{
    using distinct_parser<Subject, Tail, Modifier>::distinct_parser;

    template <typename Context> info what(Context& ctx) const {
        return info("my_distinct", this->subject.what(ctx));
    }
};

遗憾的是,我们需要更多的红色磁带才能将其注册到解析器编译和组合机制中:

Sadly, we need some more red-tape to get things registered with the parser compilation and composition machinery:

#pragma once
#include <boost/spirit/repository/home/qi/directive/distinct.hpp>

namespace boost::spirit::repository {
    BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(( my_distinct, my_distinct_type ))
}

namespace boost::spirit {
    template <typename Tail>
    struct use_directive<qi::domain
          , terminal_ex<repository::tag::my_distinct, fusion::vector1<Tail> > >
      : mpl::true_ {};

    template <>
    struct use_lazy_directive<qi::domain, repository::tag::my_distinct, 1> 
      : mpl::true_ {};
}

namespace boost::spirit::repository::qi {
    using repository::my_distinct;
    using repository::my_distinct_type;

    template <typename Subject, typename Tail, typename Modifier>
    struct my_distinct_parser
      : distinct_parser<Subject, Tail, Modifier>
    {
        using distinct_parser<Subject, Tail, Modifier>::distinct_parser;

        template <typename Context> info what(Context& ctx) const {
            return info("my_distinct", this->subject.what(ctx));
        }
    };
}

namespace boost::spirit::qi {
    template <typename Tail, typename Subject, typename Modifiers>
    struct make_directive<
        terminal_ex<repository::tag::my_distinct, fusion::vector1<Tail> >
      , Subject, Modifiers>
    {
        typedef typename result_of::compile<qi::domain, Tail, Modifiers>::type
            tail_type;

        typedef repository::qi::my_distinct_parser<
            Subject, tail_type, Modifiers> result_type;

        template <typename Terminal>
        result_type operator()(Terminal const& term, Subject const& subject
          , Modifiers const& modifiers) const
        {
            return result_type(subject
              , compile<qi::domain>(fusion::at_c<0>(term.args), modifiers));
        }
    };
}

namespace boost::spirit::traits {
    template <typename Subject, typename Tail, typename Modifier>
    struct has_semantic_action<
            repository::qi::my_distinct_parser<Subject, Tail, Modifier> >
      : unary_has_semantic_action<Subject> {};
}

实时演示

在魔盒上直播

LIVE DEMO

Live On Wandbox

#include <boost/spirit/include/qi.hpp>
#include "my_distinct.hpp"
namespace enc = boost::spirit::standard_wide;
namespace qi = boost::spirit::qi;
namespace qr = boost::spirit::repository::qi;
using It = std::wstring::const_iterator;

#define kw(p) qr::my_distinct(enc::alnum | L'_') \
        [ enc::no_case[p] ]

int main() {
    qr::my_distinct(enc::alnum | L'_');
    qi::rule<It> rule;

    rule
        = qi::eps > 
            ( kw(L"public")
            | kw(L"private")
            | kw(L"protected")
            | kw(L"shared")
            )
        ;

    for (std::wstring const input : {
            L"PUBLIC",
            L"private",
            L"PROTECTED",
            L"shared",
            L"XPUBLIC", // obviously no match
            L"PUBLICX", // actually test of my_distinct
        }) 
    try {
        It f = begin(input), l = end(input);
        auto ok = qi::parse(f, l, rule);
        std::wcout << input << " " << std::boolalpha << ok << std::endl;
    } catch(qi::expectation_failure<It> const& ef) {

        auto value = ef.what_.value;
        auto elements = boost::get<std::list<boost::spirit::info> >(value);

        std::ostringstream oss;
        oss << ef.what_.tag << "(";
        for (auto el : elements) oss << " " << el;
        oss << " )";

        std::wcout << input << " -> Expected " << oss.str().c_str() << std::endl;
    }
}
    

打印

PUBLIC true
private true
PROTECTED true
shared true
XPUBLIC -> Expected alternative( "public" "private" "protected" "shared" )
PUBLICX -> Expected alternative( "public" "private" "protected" "shared" )

这篇关于如何在错误消息“与众不同"的可能符号中增强精神?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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