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

如何用Python Lex-Yacc为查询字符串添加括号以体现运算优先级?

问题描述

我是Lex-Yacc新手,现有一个用于解析字符串查询的Python Lex-Yacc解析器,当前设置的优先级规则如下:

self.precedence = (
            ('left', 'AND', 'OR', 'NOT'),
        )

self.parser = yacc.yacc(module=self, debug=debug, write_tables=debug)

该规则可正常工作,但我希望添加步骤,让查询语句按照优先级规则自动添加括号。例如将:

query1 = expression OR expression AND expression OR expression  
query2 = expression OR expression AND ( expression OR expression )  

转换为:

query1 = expression OR ( expression AND expression ) OR expression 
query2 = expression OR ( expression AND ( expression OR expression ))

请问该如何实现这一需求?

解决方案

1. 修正优先级规则

首先调整优先级顺序,符合常规逻辑:NOT优先级最高,其次是AND,OR优先级最低,同时设置正确的结合性(NOT为右结合,AND/OR为左结合)。错误的优先级会导致解析顺序不符合预期,后续加括号也会出错。

self.precedence = (
    ('right', 'NOT'),   # 单目运算符,右结合
    ('left', 'AND'),    # 优先级高于OR
    ('left', 'OR'),     # 优先级最低
)

2. 定义语法规则与括号生成逻辑

每个语法规则的动作函数返回**(生成的字符串片段, 表达式优先级)**的元组,通过辅助函数判断是否需要给子表达式添加括号。

辅助函数:判断是否添加括号

根据子表达式的优先级和类型,决定是否包裹括号:

def _maybe_parenthesize(self, sub_expr, current_precedence):
    sub_str, sub_prec = sub_expr
    # 基础表达式或带括号的表达式,直接返回原字符串(无需额外括号)
    if sub_prec == 4:
        return sub_str
    # 复合表达式:子优先级高于当前时,加括号明确运算顺序
    if sub_prec > current_precedence:
        return f"( {sub_str} )"
    # 右结合的NOT:同优先级子表达式需要加括号(如NOT NOT a → NOT (NOT a))
    elif sub_prec == current_precedence and current_precedence == 3:
        return f"( {sub_str} )"
    # 左结合的AND/OR:同优先级无需加括号(如a AND b AND c)
    return sub_str

语法规则实现

每个规则对应不同的表达式类型,生成带括号的字符串:

# OR表达式:优先级1
def p_expr_or(self, p):
    'expr : expr OR expr'
    left = self._maybe_parenthesize(p[1], 1)
    right = self._maybe_parenthesize(p[3], 1)
    p[0] = (f"{left} OR {right}", 1)

# AND表达式:优先级2
def p_expr_and(self, p):
    'expr : expr AND expr'
    left = self._maybe_parenthesize(p[1], 2)
    right = self._maybe_parenthesize(p[3], 2)
    p[0] = (f"{left} AND {right}", 2)

# NOT表达式:优先级3
def p_expr_not(self, p):
    'expr : NOT expr'
    sub = self._maybe_parenthesize(p[2], 3)
    p[0] = (f"NOT {sub}", 3)

# 带括号的表达式:优先级4(最高,无需额外括号)
def p_expr_group(self, p):
    'expr : LPAREN expr RPAREN'
    p[0] = (f"( {p[2][0]} )", 4)

# 基础表达式:优先级4(如你例子中的"expression",实际可替换为标识符等)
def p_expr_basic(self, p):
    'expr : EXPRESSION'
    p[0] = (p[1], 4)

# 错误处理
def p_error(self, p):
    print(f"Syntax error at {p.value if p else 'end of input'}")

3. 词法分析器补充

确保所有需要的Token被正确识别(示例匹配你给出的expression,实际可根据需求修改):

def t_AND(self, t):
    r'AND'
    return t

def t_OR(self, t):
    r'OR'
    return t

def t_NOT(self, t):
    r'NOT'
    return t

def t_LPAREN(self, t):
    r'\('
    return t

def t_RPAREN(self, t):
    r'\)'
    return t

def t_EXPRESSION(self, t):
    r'expression'
    return t

# 忽略空格与制表符
t_ignore = ' \t'

4. 使用示例

解析查询语句后,取返回元组的第一个元素即可得到带括号的结果:

# 假设你的解析器类名为QueryParser
parser = QueryParser(debug=False)
# 解析query1
result1 = parser.parser.parse("expression OR expression AND expression OR expression")
print(result1[0])  # 输出:expression OR ( expression AND expression ) OR expression
# 解析query2
result2 = parser.parser.parse("expression OR expression AND ( expression OR expression )")
print(result2[0])  # 输出:expression OR ( expression AND ( expression OR expression ))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 03:15:50