【问题标题】:Ply Lex parsing problemPly Lex 解析问题
【发布时间】:2011-02-16 21:09:30
【问题描述】:

我使用 ply 作为我的 lex 解析器。我的规格如下:

t_WHILE = r'while'  
t_THEN = r'then'  
t_ID = r'[a-zA-Z_][a-zA-Z0-9_]*'  
t_NUMBER = r'\d+'  
t_LESSEQUAL = r'<='  
t_ASSIGN = r'='  
t_ignore  = r' \t'  

当我尝试解析以下字符串时:

"while n <= 0 then h = 1"

它给出以下输出:

LexToken(ID,'while',1,0)  
LexToken(ID,'n',1,6)  
LexToken(LESSEQUAL,'<=',1,8)  
LexToken(NUMBER,'0',1,11)  
LexToken(ID,'hen',1,14)      ------> PROBLEM!  
LexToken(ID,'h',1,18)  
LexToken(ASSIGN,'=',1,20)  
LexToken(NUMBER,'1',1,22)  

它不识别令牌 THEN,而是将“hen”作为标识符。

有什么想法吗?

【问题讨论】:

  • 其实我发现因为t_ignore = r" \t",它忽略了字母"t"(别问我为什么!)。所以我删除了它,现在它开始将“then”作为令牌。
  • @Karan: r' \t' 是一个 raw 字符串。我的猜测是 \t 无法在其中转义,如果你删除了最初的 r => t_ignore = ' \t'

标签: parsing lex ply


【解决方案1】:

这不起作用的原因与 ply 优先考虑令牌匹配的方式有关,首先测试最长的令牌正则表达式。

防止这个问题最简单的方法是匹配相同类型的标识符和保留字,并根据匹配选择合适的令牌类型。以下代码类似于ply documentation中的示例

import ply.lex

tokens = [ 'ID', 'NUMBER', 'LESSEQUAL', 'ASSIGN' ]
reserved = {
    'while' : 'WHILE',
    'then' : 'THEN'
}
tokens += reserved.values()

t_ignore    = ' \t'
t_NUMBER    = '\d+'
t_LESSEQUAL = '\<\='
t_ASSIGN    = '\='

def t_ID(t):
    r'[a-zA-Z_][a-zA-Z0-9_]*'
    if t.value in reserved:
        t.type = reserved[ t.value ]
    return t

def t_error(t):
    print 'Illegal character'
    t.lexer.skip(1)

lexer = ply.lex.lex()
lexer.input("while n <= 0 then h = 1")
while True:
    tok = lexer.token()
    if not tok:
        break
    print tok

【讨论】:

    【解决方案2】:

    PLY 根据最长的正则表达式对声明为简单字符串的标记进行优先级排序,但声明为函数的标记具有优先顺序。

    来自文档:

    在构建主正则表达式时,会在 以下顺序:

    1. 函数定义的所有标记都按照它们在词法分析器文件中出现的顺序添加。
    2. 接下来添加由字符串定义的标记,方法是按照正则表达式长度递减的顺序对它们进行排序(添加更长的表达式 首先)。

    因此,另一种解决方案是将您希望优先考虑的标记指定为函数,而不是字符串,如下所示:

    def t_WHILE(t): r'while'; return t
    def t_THEN(t): r'then'; return t
    t_ID = r'[a-zA-Z_][a-zA-Z0-9_]*'
    t_NUMBER = r'\d+'
    t_LESSEQUAL = r'<='
    t_ASSIGN = r'='
    t_ignore = ' \t'
    

    这样,WHILE 和 THEN 将是要添加的第一条规则,并且您会获得预期的行为。

    作为旁注,您使用 r' \t'(原始字符串)作为 t_ignore,因此 Python 将 \ 视为反斜杠。它应该是一个简单的字符串,如上例所示。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-19
      • 1970-01-01
      相关资源
      最近更新 更多