【问题标题】:Troubles with boost::spirit::lex & whitespaceboost::spirit::lex 和空格的问题
【发布时间】:2012-11-13 13:26:33
【问题描述】:

我尝试学习使用 boost::spirit。为此,我想创建一些简单的词法分析器,将它们组合起来,然后开始使用 Spirit 进行解析。我尝试修改示例,但它没有按预期运行(结果 r 不正确)。

这是词法分析器:

#include <boost/spirit/include/lex_lexertl.hpp>

namespace lex = boost::spirit::lex;

template <typename Lexer>
struct lexer_identifier : lex::lexer<Lexer>
{
    lexer_identifier()
        : identifier("[a-zA-Z_][a-zA-Z0-9_]*")
        , white_space("[ \\t\\n]+")
    {
        using boost::spirit::lex::_start;
        using boost::spirit::lex::_end;

        this->self = identifier;
        this->self("WS") = white_space;
    }
    lex::token_def<> identifier;
    lex::token_def<> white_space;
    std::string identifier_name;
};

这是我正在尝试运行的示例:

#include "stdafx.h"

#include <boost/spirit/include/lex_lexertl.hpp>
#include "my_Lexer.h"

namespace lex = boost::spirit::lex;

int _tmain(int argc, _TCHAR* argv[])
{
    typedef lex::lexertl::token<char const*,lex::omit, boost::mpl::false_> token_type;
    typedef lex::lexertl::lexer<token_type> lexer_type;

    typedef lexer_identifier<lexer_type>::iterator_type iterator_type;

    lexer_identifier<lexer_type> my_lexer;

    std::string test("adedvied das934adf dfklj_03245");

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

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

    while (iter != end && token_is_valid(*iter))
    {
        ++iter;
    }

    bool r = (iter == end);

    return 0;
}
只要字符串中只有一个标记,

r 就为真。为什么会这样?

问候 托比亚斯

【问题讨论】:

    标签: c++ boost boost-spirit boost-spirit-lex


    【解决方案1】:

    您已经创建了第二个词法分析器状态,但从未调用它。

    化繁为简:


    在大多数情况下,获得所需效果的最简单方法是在可跳过标记上使用带有 pass_ignore 标志的单态词法分析:

        this->self += identifier
                    | white_space [ lex::_pass = lex::pass_flags::pass_ignore ];
    

    请注意,这需要 actor_lexer 以允许语义操作:

    typedef lex::lexertl::actor_lexer<token_type> lexer_type;
    

    完整样本:

    #include <boost/spirit/include/lex_lexertl.hpp>
    #include <boost/spirit/include/lex_lexertl.hpp>
    namespace lex = boost::spirit::lex;
    
    template <typename Lexer>
    struct lexer_identifier : lex::lexer<Lexer>
    {
        lexer_identifier()
            : identifier("[a-zA-Z_][a-zA-Z0-9_]*")
            , white_space("[ \\t\\n]+")
        {
            using boost::spirit::lex::_start;
            using boost::spirit::lex::_end;
    
            this->self += identifier
                        | white_space [ lex::_pass = lex::pass_flags::pass_ignore ];
        }
        lex::token_def<> identifier;
        lex::token_def<> white_space;
        std::string identifier_name;
    };
    
    int main(int argc, const char *argv[])
    {
        typedef lex::lexertl::token<char const*,lex::omit, boost::mpl::false_> token_type;
        typedef lex::lexertl::actor_lexer<token_type> lexer_type;
    
        typedef lexer_identifier<lexer_type>::iterator_type iterator_type;
    
        lexer_identifier<lexer_type> my_lexer;
    
        std::string test("adedvied das934adf dfklj_03245");
    
        char const* first = test.c_str();
        char const* last = &first[test.size()];
    
        lexer_type::iterator_type iter = my_lexer.begin(first, last);
        lexer_type::iterator_type end = my_lexer.end();
    
        while (iter != end && token_is_valid(*iter))
        {
            ++iter;
        }
    
        bool r = (iter == end);
        std::cout << std::boolalpha << r << "\n";
    }
    

    打印

    true
    

    “WS”作为船长状态


    您也可能遇到了一个使用第二个解析器状态作为船长 (lex::tokenize_and_phrase_parse) 的示例。让我花一分钟或 10 分钟为此创建一个工作示例。

    更新花了我 10 多分钟 (waaaah) :) 这是一个对比测试,展示了词法分析器状态如何交互,以及如何使用 Spirit Skipper 解析来调用第二个解析器状态:

    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/lex_lexertl.hpp>
    namespace lex = boost::spirit::lex;
    namespace qi  = boost::spirit::qi;
    
    template <typename Lexer>
    struct lexer_identifier : lex::lexer<Lexer>
    {
        lexer_identifier()
            : identifier("[a-zA-Z_][a-zA-Z0-9_]*")
            , white_space("[ \\t\\n]+")
        {
            this->self       = identifier;
            this->self("WS") = white_space;
        }
        lex::token_def<> identifier;
        lex::token_def<lex::omit> white_space;
    };
    
    int main()
    {
        typedef lex::lexertl::token<char const*, lex::omit, boost::mpl::true_> token_type;
        typedef lex::lexertl::lexer<token_type> lexer_type;
    
        typedef lexer_identifier<lexer_type>::iterator_type iterator_type;
    
        lexer_identifier<lexer_type> my_lexer;
    
        std::string test("adedvied das934adf dfklj_03245");
    
        {
            char const* first = test.c_str();
            char const* last = &first[test.size()];
    
            // cannot lex in just default WS state:
            bool ok = lex::tokenize(first, last, my_lexer, "WS");
            std::cout << "Starting state WS:\t" << std::boolalpha << ok << "\n";
        }
    
        {
            char const* first = test.c_str();
            char const* last = &first[test.size()];
    
            // cannot lex in just default state either:
            bool ok = lex::tokenize(first, last, my_lexer, "INITIAL");
            std::cout << "Starting state INITIAL:\t" << std::boolalpha << ok << "\n";
        }
    
        {
            char const* first = test.c_str();
            char const* last = &first[test.size()];
    
            bool ok = lex::tokenize_and_phrase_parse(first, last, my_lexer, *my_lexer.self, qi::in_state("WS")[my_lexer.self]);
            ok = ok && (first == last); // verify full input consumed
            std::cout << std::boolalpha << ok << "\n";
        }
    }
    

    输出是

    Starting state WS:  false
    Starting state INITIAL: false
    true
    

    【讨论】:

    • "WS" as a Skipper state 下添加了带有演示的“WS”状态方法。干杯
    • 糟糕。我复制了错误的 token_type 声明。在处理有状态的词法分析器时,它需要mpl::true_ 用于HasState——显然! 固定
    • 首先-感谢您提供的广泛示例。不过我还有一些问题:lex::omit 是做什么的?关于 tokenize_and_parse 调用:什么是 my_lexer.self & qi::in_state("WS")[my_lexer.self]?
    • my_lexer.self 是默认词法分析器状态 (INITIAL) 的所有标记,in_state("WS")[my_lexer.self] 表示 WS 词法分析器状态的所有标记。那些是由定义的。第一个表达式作为解析器表达式传递(简单:匹配任意数量的标记),第二个作为跳过器传递(简单:跳过任何空格)。
    猜你喜欢
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多