1

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

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,然后将其余部分解析为第二个状态?请举个例子?

4

1 回答 1

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(如果您阅读为gametypeML: move lineMV: move ,目的会相对清楚;请注意此处的eoland的存在gametype_eol:Lex 不允许将相同的标记添加到不同的状态)

于 2013-10-28T10:30:31.233 回答