如何避免定义与boost :: spirit :: lex中的所有内容匹配的标记

时间:2013-10-28 09:19:17

标签: c++ boost boost-spirit

我想创建一个语法和词法分析器来解析下面的字符串:

100 reason phrase

正则表达式为:“\ d {3} [^ \ r \ n] *”

令牌定义:

template <typename Lexer>
struct custom_tokens : lex::lexer<Lexer>
{
    custom_tokens()
    {
        this->self.add_pattern
            ("STATUSCODE", "\\d{3}")                
            ("SP", " ")
            ("REASONPHRASE", "[^\r\n]*")
            ;                

        this->self.add                          
            ("{STATUSCODE}", T_STATUSCODE)
            ("{SP}", T_SP)
            ("{REASONPHRASE}", T_REASONPHRASE)
            ;
    }   
};

语法:

template <typename Iterator>
struct custom_grammar : qi::grammar<Iterator >
{
    template <typename TokenDef>
    custom_grammar(TokenDef const& tok)
        : custom_grammar::base_type(start)            
    {            
        start = (qi::token(T_STATUSCODE) >> qi::token(T_SP) >> qi::token(T_REASONPHRASE));
    }

    qi::rule<Iterator> start;
};

然而,我意识到我无法定义标记“T_REASONPHRASE”,因为它将匹配包括“T_STATUSCODE”在内的所有内容。我能做的是

  1. 取消定义T_REASONPHRASE并使用qi :: lexeme在custom_grammar中编写规则?

  2. 我可以使用lex state来做到这一点吗?例如在第二个状态中定义“T_REASONPHRASE”,如果它在第一个状态中看到T_STATUSCODE然后将其余部分解析为第二个状态?请举个例子?

1 个答案:

答案 0 :(得分:2)

我认为确实没有问题,因为令牌按照它们被添加到令牌定义的顺序“贪婪地”匹配(对于特定的词法分析器状态)。

所以,给定

    this->self.add                          
        ("{STATUSCODE}", T_STATUSCODE)
        ("{SP}", T_SP)
        ("{REASONPHRASE}", T_REASONPHRASE)
        ;

T_STATUSCODE将在T_REASONPHRASE之前始终匹配(如果存在歧义)。


关于使用单独的Lexer状态,这里是我曾经在玩具项目中使用的标记器的摘录:

this->self = fileheader     [ lex::_state = "GT" ];

this->self("GT") =
    gametype_label |
    gametype_63000 | gametype_63001 | gametype_63002 |
    gametype_63003 | gametype_63004 | gametype_63005 |
    gametype_63006 |
    gametype_eol            [ lex::_state = "ML" ];

this->self("ML") = mvnumber [ lex::_state = "MV" ];

this->self("MV") = piece | field | op | check | CASTLEK | CASTLEQ 
         | promotion
         | Checkmate | Stalemate | EnPassant
         | eol              [ lex::_state = "ML" ]
         | space            [ lex::_pass = lex::pass_flags::pass_ignore ];

(如果您将GT视为游戏类型ML移动行MV,目的就会相对清晰: move ;请注意此处eolgametype_eol的存在:Lex不允许向不同的州添加相同的令牌)