Сравнение строк с учетом регистра символов Boost::Spirit Token в семантическом действии

У меня есть токенизатор и парсер. синтаксический анализатор имеет специальный тип токена, 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 ответ

Небольшое обучение прошло долгий путь. Я добавил следующее в свой лексер:

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 вместо итератора и избежать изменения моей входной последовательности?

Я попытался вернуть std:: string, скопированный из ip.begin() в ip.end() и в верхнем регистре, используя boost::toupper(...), присвоив его _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')

Я понятия не имею, почему это решило проблему, поэтому, если кто-то может поделиться со своим опытом, я готовый студент.

Другие вопросы по тегам