Spirit Lex: Какое определение токена сгенерировало этот токен?

Извините, если это вопрос новичка, но мне нужно знать, какое определение токена создало определенный токен. Когда я печатаю идентификатор токена, я просто получаю целое число. Мне нужно знать, какое регулярное выражение сгенерировало этот токен.

Изменить:

Вот как я определяю свои токены:

   template <typename LexerT>
   class Tokens: public lex::lexer<LexerT>
   {
      public:
         Tokens(const std::string& input):
            lineNo_(1)
         {
            using boost::spirit::lex::_start;
            using boost::spirit::lex::_end;
            using boost::spirit::lex::_pass;
            using boost::phoenix::ref;
            using boost::phoenix::construct;

            // macros
            this->self.add_pattern
               ("EXP",     "(e|E)(\\+|-)?\\d+")
               ("SUFFIX",  "[yzafpnumkKMGTPEZY]")
               ("INTEGER", "-?\\d+")
               ("FLOAT",    "-?(((\\d+)|(\\d*\\.\\d+)|(\\d+\\.\\d*))({EXP}|{SUFFIX})?)")
               ("SYMBOL",  "[a-zA-Z_?@](\\w|\\?|@)*")
               ("STRING",  "\\\"([^\\\"]|\\\\\\\")*\\\"");

            // whitespaces and comments
            whitespaces_ = "\\s+";
            comments_    = "(;[^\\n]*\\n)|(\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\/)";

            // literals
            integer_ = "{INTEGER}";
            float_   = "{FLOAT}";
            symbol_  = "{SYMBOL}";
            string_  = "{STRING}";

            // operators
            quote_         = "'";
            backquote_     = '`';

            // ... other tokens

            // whitespace and comment rules
            this->self += whitespaces_ [ref(lineNo_) += count(_start, _end, '\n'), _pass = lex::pass_flags::pass_ignore];
            this->self += comments_    [ref(lineNo_) += count(_start, _end, '\n'), _pass = lex::pass_flags::pass_ignore];

            // literal rules
            this->self += integer_ | float_ | string_ | symbol_;
            // this->self += ... other tokens
         }

         ~Tokens() {}

         size_t lineNo() { return lineNo_; }


      private:
         // ignored tokens
         lex::token_def<lex::omit> whitespaces_, comments_;

         // literal tokens
         lex::token_def<int>          integer_;
         lex::token_def<std::string>  float_, symbol_, string_;

         // operator tokens
         lex::token_def<> quote_, backquote_;
         // ... other token definitions of type lex::token_def<>

         // current line number
         size_t lineNo_;
   };

Спасибо, Хайтам.


person Haitham Gad    schedule 19.06.2012    source источник
comment
Просто найдите перечисление, в котором объявлены ваши токены. Или запустите GDB, установите точку останова в вашей функции, ожидающей токен, и распечатайте токен с помощью GDB; он напечатает свое правильное имя перечисления.   -  person    schedule 19.06.2012
comment
Привет, H2CO3, я не использую перечисление для определения своих токенов. Большинство моих токенов хранятся в значениях по умолчанию для аргументов шаблона (например, token_def‹›). Idtype по умолчанию в моей версии Spirit — std::size_t. Вы хотите изменить Idtype в моих определениях токенов, чтобы использовать какое-то перечисление, а не значение по умолчанию?   -  person Haitham Gad    schedule 19.06.2012
comment
Если вы не используете перечисления, как они определяются? Вы должны показать код в своем вопросе.   -  person    schedule 19.06.2012
comment
Я добавил свой код для определения токенов.   -  person Haitham Gad    schedule 19.06.2012
comment
Благодарить. Я подозреваю, что token ID = индекс шаблона; поэтому 0 = EXP, 2 = целое число и т. д.   -  person    schedule 19.06.2012
comment
На самом деле, идентификатор, который я получаю для токена, который я ищу, — 65536!   -  person Haitham Gad    schedule 20.06.2012


Ответы (1)


Из документов http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/lex/tutorials/lexer_quickstart2.html:

Чтобы убедиться, что каждому токену присвоен идентификатор, библиотека Spirit.Lex внутренне присваивает определениям токенов уникальные номера, начиная с константы, определенной boost::spirit::lex::min_token_id.

Таким образом, вы можете фактически получить идентификатор токена, назначенный постепенно. Однако, чтобы сделать вещи немного более удобными/надежными, я предлагаю создать вспомогательную функцию для определения имени токена, поэтому вы можете сделать что-то вроде этого:

while (iter != end && token_is_valid(*iter))
{
    std::cout << "Token: " << 
       (iter->id() - lex::min_token_id) << ": " << 
       toklexer.nameof(iter) << " ('" << iter->value() << "')\n";
    ++iter;
}
if (iter == end) { std::cout << "lineNo: " << toklexer.lineNo() << "\n"; }

Что для ввода, например:

const std::string str = "symbol \"string\" \n"
    "this /* is a comment */\n"
    "31415926E-7 123";

Будет печатать:

Token: 5: symbol_ ('symbol')
Token: 4: string_ ('"string"')
Token: 5: symbol_ ('this')
Token: 3: float_ ('31415926E-7')
Token: 2: integer_ ('123')
lineNo: 3

Примечания

  • Я не думаю, что это возможно идентифицировать до выражения шаблона, поскольку информация не раскрывается и становится недоступной после того, как лексер возвращает токен.
  • Кажется, я помню, что видел токены с отладочной информацией (похожие на qi::rule<>::name()?), но в настоящее время я не могу найти для них документацию. Реализация функции Tokens::nameof(It) была бы значительно упрощена, если бы вы могли повторно использовать имя отладки.

КОД

Полностью рабочий демонстрационный код (слегка адаптированный для Boost 1_49-1_57, GCC -std=c++0x):

Жить на Coliru

#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/phoenix/function/adapt_callable.hpp>

namespace qi  = boost::spirit::qi;
namespace lex = boost::spirit::lex;
namespace phx = boost::phoenix;

///////////////////////////////////////////////////////////////////////////
// irrelevant for question: needed this locally to make it work with my boost
// version
namespace detail {
    struct count {
        template<class It1, class It2, class T> struct result { typedef ptrdiff_t type; };
        template<class It1, class It2, class T>
            typename result<It1, It2, T>::type operator()(It1 f, It2 l, T const& x) const {
                return std::count(f, l, x);
            }
    };
}

BOOST_PHOENIX_ADAPT_CALLABLE(count, detail::count, 3);
///////////////////////////////////////////////////////////////////////////

template <typename LexerT>
   class Tokens: public lex::lexer<LexerT>
   {

      public:
         Tokens():
            lineNo_(1)
         {
            using lex::_start;
            using lex::_end;
            using lex::_pass;
            using phx::ref;

            // macros
            this->self.add_pattern
               ("EXP",     "(e|E)(\\+|-)?\\d+")
               ("SUFFIX",  "[yzafpnumkKMGTPEZY]")
               ("INTEGER", "-?\\d+")
               ("FLOAT",    "-?(((\\d+)|(\\d*\\.\\d+)|(\\d+\\.\\d*))({EXP}|{SUFFIX})?)")
               ("SYMBOL",  "[a-zA-Z_?@](\\w|\\?|@)*")
               ("STRING",  "\\\"([^\\\"]|\\\\\\\")*\\\"");

            // whitespaces and comments
            whitespaces_ = "\\s+";
            comments_    = "(;[^\\n]*\\n)|(\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\/)";

            // literals
            integer_ = "{INTEGER}";
            float_   = "{FLOAT}";
            symbol_  = "{SYMBOL}";
            string_  = "{STRING}";

            // operators
            quote_         = "'";
            backquote_     = '`';

            // ... other tokens

            // whitespace and comment rules
            //this->self.add(whitespaces_, 1001)
                          //(comments_,    1002);
            this->self = whitespaces_ [phx::ref(lineNo_) += count(_start, _end, '\n'), _pass = lex::pass_flags::pass_ignore]
                       | comments_    [phx::ref(lineNo_) += count(_start, _end, '\n'), _pass = lex::pass_flags::pass_ignore];

            // literal rules
            this->self += integer_ | float_ | string_ | symbol_;
            // this->self += ... other tokens
         }

         template <typename TokIter>
         std::string nameof(TokIter it)
         {
             if (it->id() == whitespaces_.id()) return "whitespaces_";
             if (it->id() == comments_.id())    return "comments_";
             if (it->id() == integer_.id())     return "integer_";
             if (it->id() == float_.id())       return "float_";
             if (it->id() == symbol_.id())      return "symbol_";
             if (it->id() == string_.id())      return "string_";

             if (it->id() == quote_.id())       return "quote_";
             if (it->id() == backquote_.id())   return "backquote_";
             return "other";
         }

         ~Tokens() {}

         size_t lineNo() { return lineNo_; }


      private:
         // ignored tokens
         lex::token_def</*lex::omit*/> whitespaces_, comments_;

         // literal tokens
         lex::token_def<int>          integer_;
         lex::token_def<std::string>  float_, symbol_, string_;

         // operator tokens
         lex::token_def<> quote_, backquote_;
         // ... other token definitions of type lex::token_def<>

         // current line number
         size_t lineNo_;
   };

int main()
{
    const std::string str = "symbol \"string\" \n"
        "this /* is a comment */\n"
        "31415926E-7 123";

    typedef lex::lexertl::token<char const*> token_type;
    typedef lex::lexertl::actor_lexer<token_type> lexer_type;

    Tokens<lexer_type> toklexer;

    char const* first = str.c_str();
    char const* last = &first[str.size()];

    lexer_type::iterator_type iter = toklexer.begin(first, last);
    lexer_type::iterator_type end = toklexer.end();

    while (iter != end && token_is_valid(*iter))
    {
        std::cout << "Token: " << 
           (iter->id() - lex::min_token_id) << ": " << 
           toklexer.nameof(iter) << " ('" << iter->value() << "')\n";
        ++iter;
    }

    if (iter == end) { std::cout << "lineNo: " << toklexer.lineNo() << "\n"; }
    else {
        std::string rest(first, last);
        std::cout << "Lexical analysis failed\n" << "stopped at: \""
            << rest << "\"\n";
    }
    return 0;
}
person sehe    schedule 20.06.2012