Python/YACC 词法分析器:令牌优先级?

12 投票
2 回答
4172 浏览
提问于 2025-04-15 23:10

我正在尝试在我的语法中使用一些保留字:

reserved = {
   'if' : 'IF',
   'then' : 'THEN',
   'else' : 'ELSE',
   'while' : 'WHILE',
}

tokens = [
 'DEPT_CODE',
 'COURSE_NUMBER',
 'OR_CONJ',
 'ID',
] + list(reserved.values())

t_DEPT_CODE = r'[A-Z]{2,}'
t_COURSE_NUMBER  = r'[0-9]{4}'
t_OR_CONJ = r'or'

t_ignore = ' \t'

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

但是,t_ID 这个规则似乎把 DEPT_CODE 和 OR_CONJ 给吞掉了。我该怎么解决这个问题呢?我希望这两个能比保留字更优先被识别。

2 个回答

0

我想到两件事:

  • 首先,'or' 是一个保留字,就像 'if'、'then' 等等。
  • 其次,你的 t_ID 正则表达式匹配的字符串范围比 DEPT_CODE 更广。

因此,我会这样解决这个问题:把 'or' 当作保留字处理,然后在 t_ID 中检查字符串的长度是否为 2,并且是否只包含大写字母。如果是这样,就返回 DEPT_CODE。

16

谜团解开了!

今天我自己遇到了这个问题,找了解决办法 - 在Stack Overflow上没找到,但在手册里找到了: http://www.dabeaz.com/ply/ply.html#ply_nn6

在构建主正则表达式时,规则是按以下顺序添加的:

  • 所有通过函数定义的标记会按照它们在词法分析器文件中出现的顺序添加。
  • 通过字符串定义的标记会接着按正则表达式长度从长到短的顺序添加(长度更长的表达式会先添加)。

这就是为什么 t_ID 会“优先”于字符串定义。一个简单(虽然有点粗暴)的解决办法是把 def t_DEPT_CODE(token): r'[A-Z]{2,}'; return token 放在 def t_ID 之前。

撰写回答