使用pyparsing解析嵌套函数时,exprStack为何未包含tag函数?
问题:Pyparsing解析嵌套函数时tag元组未加入exprStack
我用pyparsing解析以tag开头的嵌套函数,示例语句为:tag("tag_name_1", value_equal("proxy.province", "value", "return_value", test(1,2)))。运行代码后控制台打印出('tag', 2),但exprStack中却未包含该tag函数元组,当前exprStack内容为['tag_name_1', 'proxy.province', 'value', 'return_value', '1', '2', ('test', 2), ('value_equal', 4)],预期应追加('tag', 2),请问该问题的原因是什么?
相关代码如下:
import pyparsing as pp from typing import Any, List, Dict def debug(*args, **kwargs): print("debug"+"---"*10) print(*args, **kwargs) print("debug"+"---"*10) return "debug" def insert_fn_argcount_tuple(t): fn = t.pop(0) num_args = len(t) print((fn, num_args)) t.insert(0, (fn, num_args)) def push_first(toks): exprStack.append(toks[0]) def to_string(toks): pass LPAREN, RPAREN, COMMA = map(pp.Suppress, '(),') ident = pp.Word(pp.alphas, pp.alphanums+"_") integer = pp.Word(pp.nums) string = (pp.QuotedString("'") | pp.QuotedString('"')).setParseAction() expr = pp.Forward() expr_list = pp.delimitedList(pp.Group(expr)) tag_fn = ("tag" + LPAREN + expr_list + RPAREN).setParseAction(insert_fn_argcount_tuple) fn_call = (ident + LPAREN + expr_list + RPAREN).setParseAction(insert_fn_argcount_tuple) atom = ( (fn_call | string | integer) | pp.Group(LPAREN+expr+RPAREN)).addParseAction(push_first) expr <<= atom bnf = pp.Forward() bnf <<= tag_fn funcs = """tag value_equal value_contain value_match value """ # functions def tag(tag_name: str, value:Any)->Dict: if not tag_name or not value: return {} return {"tag_name": tag_name, "tag_value": value} def test(*args, **kwargs): return "" def value_equal(key: str, value, default=None, test=None): print(f"---{value_equal}---") print(f"key: {key}, value: {value}, defaul: {default}, test:{test}") return "value-1" fns = { "tag": tag, "value_equal": value_equal, "test": test } exprStack = [] def evaluate_stack(s:List): fn, arg_nums = s.pop(), 0 if isinstance(fn, tuple): fn, arg_nums = fn if fn in fns: args = reversed([evaluate_stack(s) for _ in range(arg_nums)]) return fns[fn](*args) else: return fn test_str = """tag("tag_name_1", value_equal("proxy.province", "value", "return_value", test(1,2)))""" p = bnf.parse_string(test_str) print(f"\nexprStack:{exprStack}\n") t = evaluate_stack(exprStack) print(f"tag:{t}")
运行输出:
('test', 2) ('value_equal', 4) ('tag', 2) exprStack:['tag_name_1', 'proxy.province', 'value', 'return_value', '1', '2', ('test', 2), ('value_equal', 4)]
原因分析
核心问题是**tag_fn规则未绑定push_first解析动作**,导致处理后的('tag',2)元组没有被加入exprStack:
- 你定义的
fn_call规则在执行insert_fn_argcount_tuple生成元组后,会通过atom规则上绑定的push_first把元组推到栈中。 - 但
tag_fn是单独定义的规则,仅绑定了insert_fn_argcount_tuple用于生成元组,却没有绑定push_first来将元组添加到exprStack。 - 同时你把
bnf直接指向tag_fn,完全绕开了atom的解析路径,进一步导致push_first没有被触发。
解决方案
有两种简单的修复方式:
方式一:让tag函数复用fn_call规则
删除单独的tag_fn定义,让tag函数被fn_call匹配,自动触发push_first:
# 删除原tag_fn定义 # tag_fn = ("tag" + LPAREN + expr_list + RPAREN).setParseAction(insert_fn_argcount_tuple) # 修改bnf规则 bnf <<= expr
方式二:给tag_fn添加push_first动作
如果需要保留单独的tag_fn规则,直接给它绑定push_first动作:
tag_fn = ("tag" + LPAREN + expr_list + RPAREN).setParseAction(insert_fn_argcount_tuple, push_first)
修复后重新运行,exprStack末尾会出现('tag',2),evaluate_stack也能正确调用tag函数返回预期结果。
内容的提问来源于stack exchange,提问作者Burson
相关产品推荐
相关产品推荐

