You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PLY使用正则定义NAME token后变量赋值出现语法错误问题排查

问题原因

核心是词法分析阶段的token匹配优先级冲突:

  • is字符串同时满足IS token的正则规则r'is'和NAME token的正则规则r"[a-zA-Z]+\w*",两者匹配的字符串长度相同,当前规则下is被识别为NAME类型而非预期的IS类型,导致语法规则NAME IS STRING匹配失败,触发语法错误。
  • PLY处理token匹配时,函数定义的token规则和字符串定义的t_*规则排序逻辑特殊,相同匹配长度下,保留字的简单规则很容易被覆盖性更强的NAME规则吞掉,这也是这类问题的常见诱因。
  • 另外你代码中STRING的正则r'\".*?\"'是HTML转义后的错误写法,实际需要调整为匹配双引号的正常正则。
解决方案

采用PLY官方推荐的保留字处理方案,将所有保留字放到NAME token的处理逻辑中判断,避免匹配冲突,修改后代码如下:

import ply.lex as lex
import ply.yacc as yacc

# 定义保留字字典
reserved = {
    'show': 'SHOW',
    'is': 'IS'
}

# tokens需要包含所有保留字对应的类型
tokens = ('LPAREN','RPAREN','STRING','NAME', *reserved.values())

t_LPAREN ='\('
t_RPAREN = '\)'
t_STRING = r'"[^"]*"' # 修复STRING正则,匹配双引号包裹的内容
t_ignore = " \t"

def t_NAME(t):
    r"[a-zA-Z]+\w*"
    # 判断当前匹配到的字符串是不是保留字
    t.type = reserved.get(t.value.lower(), 'NAME')
    return t

def t_error(t):
    print("Syntax error at %s"%t.value)
    t.lexer.skip(1)

Variables = {}

def p_show(p):
    '''statement : SHOW LPAREN STRING RPAREN
    | SHOW LPAREN NAME RPAREN'''
    value = p.slice[3]
    if value.type == 'NAME':
        print(Variables[value.value])
    else:
        print(value.value)

def p_is(p):
    'statement : NAME IS STRING'
    Variables[p[1]] = p[3]

def p_variable(p):
    'statement : NAME'
    return Variables[p.slice[1].value]

def p_error(p):
    print("Syntax error at %s"%p.value)

lex.lex()
yacc.yacc()
s ='MY_STRING is "this is a string"'
yacc.parse(s)
# 测试读取变量
yacc.parse('show(MY_STRING)')
补充说明

如果你不想调整NAME的处理逻辑,也可以把IS、SHOW的规则改成函数定义,并且放在t_NAME函数的前面,相同匹配长度下,先定义的规则优先级更高,也能解决冲突。但保留字字典的方案扩展性更强,后续新增保留字只需要更新字典即可,不需要调整其他逻辑。

内容的提问来源于stack exchange,提问作者Jael Andres

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 04:21:03