语义动作中Boost :: Spirit Token文本的不敏感字符串比较

时间:2014-12-14 11:45:56

标签: parsing boost boost-spirit boost-spirit-qi boost-spirit-lex

我有一个tokeniser和一个解析器。解析器有一个特殊的令牌类型KEYWORD,用于关键字(有~50)。在我的解析器中,我想确保令牌是我所期望的,所以我为每个令牌都有规则。像这样:

KW_A = tok.KEYWORDS[_pass = (_1 == "A")];
KW_B = tok.KEYWORDS[_pass = (_1 == "B")];
KW_C = tok.KEYWORDS[_pass = (_1 == "C")];

这很好用,但它不是不区分大小写(我试图处理的语法是!)。我想使用boost :: iequals,但尝试将_1转换为std :: string会导致以下错误:

error: no viable conversion from 'const _1_type' (aka 'const actor<argument<0> >') to 'std::string' (aka 'basic_string<char>')

如何将这些关键字视为字符串并确保它们是预期的文本而不考虑情况?

1 个答案:

答案 0 :(得分:2)

一点点学习取得了很大进展。我在lexer中添加了以下内容:

struct normalise_keyword_impl
{
    template <typename Value>
    struct result
    {
        typedef void type;
    };

    template <typename Value>
    void operator()(Value const& val) const
    {
        // This modifies the original input string.
        typedef boost::iterator_range<std::string::iterator> iterpair_type;
        iterpair_type const& ip = boost::get<iterpair_type>(val);
        std::for_each(ip.begin(), ip.end(),
            [](char& in)
            {
                in = std::toupper(in);
            });
    }
};

    boost::phoenix::function<normalise_keyword_impl> normalise_keyword;

    // The rest...
};

然后使用phoenix将动作绑定到构造函数中的关键字标记,如下所示:

this->self =
    KEYWORD [normalise_keyword(_val)]
    // The rest...
    ;

虽然这实现了我的目标,但它修改了原始输入序列。我可以做一些修改,以便我可以使用const_iterator而不是迭代器,并避免修改我的输入序列吗?

我尝试使用boost :: toupper(...)将从ip.begin()复制的std :: string返回到ip.end()和uppercased,并将其分配给_val。虽然编译和运行,但它产生的内容显然存在一些问题:

Enter a sequence to be tokenised: select a from b
Input is 'select a from b'.
result is SELECT
Token: 0: KEYWORD ('KEYWOR')
Token: 1: REGULAR_IDENTIFIER ('a')
result is FROM
Token: 0: KEYWORD ('KEYW')
Token: 1: REGULAR_IDENTIFIER ('b')

非常奇怪,似乎我还有更多的学习要做。

最终解决方案

好的,我最终使用了这个功能:

struct normalise_keyword_impl
{
    template <typename Value>
    struct result
    {
        typedef std::string type;
    };

    template <typename Value>
    std::string operator()(Value const& val) const
    {
        // Copy the token and update the attribute value.
        typedef boost::iterator_range<std::string::const_iterator> iterpair_type;
        iterpair_type const& ip = boost::get<iterpair_type>(val);

        auto result = std::string(ip.begin(), ip.end());
        result = boost::to_upper_copy(result);
        return result;
    }
};

这个语义行为:

KEYWORD [_val = normalise_keyword(_val)]

使用(并将其排序),修改后的token_type:

typedef std::string::const_iterator base_iterator;
typedef boost::spirit::lex::lexertl::token<base_iterator, boost::mpl::vector<std::string> > token_type;
typedef boost::spirit::lex::lexertl::actor_lexer<token_type> lexer_type;
typedef type_system::Tokens<lexer_type> tokens_type;
typedef tokens_type::iterator_type iterator_type;
typedef type_system::Grammar<iterator_type> grammar_type;

// Establish our lexer and our parser.
tokens_type lexer;
grammar_type parser(lexer);

// ...

重要的补充是boost::mpl::vector<std::string> >。结果:

Enter a sequence to be tokenised: select a from b
Input is 'select a from b'.
Token: 0: KEYWORD ('SELECT')
Token: 1: REGULAR_IDENTIFIER ('a')
Token: 0: KEYWORD ('FROM')
Token: 1: REGULAR_IDENTIFIER ('b')

我不知道为什么这已经纠正了这个问题所以如果有人可以使用他们的专业知识,我就是一个自愿的学生。