Нужна помощь с лексером runtime_error - PullRequest
0 голосов
/ 21 августа 2011

Я пытаюсь написать синтаксический анализатор Си-Си для модифицированного языка Си.Когда я отменяю комментарий к разделу t_in_op и ниже, я получаю ошибку run_time, сообщающую

Синтаксическая ошибка: нажмите BEGIN, когда '+' в индексе 1 (или что-то в этом духе, точно не помню).В чем проблема с этим лексером?

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

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

#include <boost/spirit/home/support/detail/lexer/runtime_error.hpp>

template <typename Lexer>
struct iLexer : lex::lexer<Lexer>
{
    iLexer()
    {
        // define tokens and associate them with the lexer
        identifier      = "[a-zA-Z_][a-zA-Z_0-9]*";
        intNum          = "([0-9]+)|(0x[0-9a-fA-F]+)|(0b[01]+)";
        floatNum        = "(([0-9]+|(([0-9]+\\.[0-9]*[fF]?)|(\\.[0-9]+)))([eE][-+]?[0-9]+)?[fF]?)";
        hexFloatNum     = "(0x[01](\\.[0-9a-fA-F]*)?p[-+]?[0-9]+[fF]?)";
        swizzle         = "([01]+[w-z]+)+|([01]+[rgba]+)+|([01]+[uv]+)+";
        t_inc_op        = "++";
        t_dec_op        = "--";

        // white space
        ws              = "[ \t\n]+";

        this->self = ws [lex::_pass = lex::pass_flags::pass_ignore];

        this->self += identifier
            | floatNum
            | hexFloatNum
            | intNum
            | swizzle
            | t_inc_op
            | t_dec_op
            ;

        // these are passed on to parser as they are defined ('{' is passed as '{')
        this->self += lex::token_def<>('(') | ')' | '{' | '}' | '=' | '<' | '>' | '&' | '|' | ';';
    }

    lex::token_def<> ws;
    lex::token_def<> identifier, intNum, floatNum, hexFloatNum, swizzle;
    lex::token_def<> t_inc_op, t_dec_op;
};

template <typename Iterator>
struct iGrammar : qi::grammar<Iterator>
{
    template <typename TokenDef>
    iGrammar(TokenDef const& tok)
        // construct the base with the start symbol of our grammar
      : iGrammar::base_type(translation_unit)
    {
        translation_unit
            = *external_declaration
            ;
        BOOST_SPIRIT_DEBUG_NODE(translation_unit);

        external_declaration
            = function_defnition
            | declaration
            ;
        BOOST_SPIRIT_DEBUG_NODE(external_declaration);

        function_defnition
            = (tok.identifier >> '(' >> ')')
            ;
        BOOST_SPIRIT_DEBUG_NODE(function_defnition);

        declaration
            = ( tok.identifier >> '=' >> tok.intNum >> ';')
            ;
        BOOST_SPIRIT_DEBUG_NODE(declaration);
    }

    qi::rule<Iterator> translation_unit;
    qi::rule<Iterator> external_declaration;
    qi::rule<Iterator> function_defnition;
    qi::rule<Iterator> declaration;
};

int main(int argc, char* argv[])
{
    // iterator type used to expose the underlying input stream
    typedef std::string::iterator base_iterator_type;

    // lexer type
    typedef lex::lexertl::actor_lexer<
        lex::lexertl::token<
            base_iterator_type, boost::mpl::vector2<double, int> 
        > > lexer_type;

    // iterator type exposed by the lexer 
    typedef iLexer<lexer_type>::iterator_type iterator_type;

    // now we use the types defined above to create the lexer and grammar
    // object instances needed to invoke the parsing process
    iLexer<lexer_type> tokenizer;            // Our lexer
    iGrammar<iterator_type> g (tokenizer);   // Our parser 

    std::string str (read_from_file("simple.ic"));
    base_iterator_type first = str.begin();

    try {
        bool r = lex::tokenize_and_parse(first, str.end(), tokenizer, g);
        if (r) {
        std::cout << "-------------------------\n";
        std::cout << "Parsing succeeded\n";
        std::cout << "-------------------------\n";
        }
        else {
            std::string rest(first, str.end());
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            std::cout << "stopped at: \"" << rest << "\"\n";
            std::cout << "-------------------------\n";
        }
    }
    catch(const boost::lexer::runtime_error &re)
    {
        std::cerr << re.what() << std::endl;
    }

    std::cout << "Bye... :-) \n\n";
    return 0;
}

simple.ic int i32 = 1;

1 Ответ

2 голосов
/ 21 августа 2011

Символ '+' имеет особое значение в регулярных выражениях. Поэтому вам нужно экранировать его, чтобы он соответствовал простому «+»:

t_inc_op = "\\+\\+";

Единственное исключение, при котором вам не нужно экранировать специальные символы регулярного выражения в Spirit.Lex, когда вы определяете токены из одного символа, например

this->self += char_('+');

В этом случае библиотека спасается за вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...