上下文无关文法 (CFG) 实战:3步构建无二义性四则运算语法树
📅 2026/7/13 6:20:16
👁️ 阅读次数
📝 编程学习
上下文无关文法实战:三步构建无二义性四则运算语法树
在编程语言和数学表达式处理中,上下文无关文法(CFG)扮演着至关重要的角色。它不仅是编译原理的理论基础,更是解决实际语法解析问题的利器。本文将以四则运算表达式为例,展示如何设计无二义性的CFG,并通过Python代码实现语法树的构建。
1. 理解上下文无关文法基础
上下文无关文法由四个部分组成:
- 终结符(Terminals):构成语言基本元素的符号,如数字、运算符
- 非终结符(Non-terminals):表示语法结构的变量
- 产生式规则(Productions):定义非终结符如何展开
- 开始符号(Start symbol):语法分析的起点
四则运算的简单文法可能如下:
Expr → Expr + Term | Expr - Term | Term Term → Term * Factor | Term / Factor | Factor Factor → ( Expr ) | number这种分层结构有效解决了运算符优先级问题:
- Factor处理括号和基本单元
- Term处理乘除运算
- Expr处理加减运算
2. 消除二义性的关键技巧
原始文法E → E + E | E * E | (E) | number存在二义性,无法确定运算顺序。通过引入层级结构消除二义性:
# 优先级从低到高分层 grammar = { 'Expr': [['Expr', '+', 'Term'], ['Expr', '-', 'Term'], ['Term']], 'Term': [['Term', '*', 'Factor'], ['Term', '/', 'Factor'], ['Factor']], 'Factor': [['(', 'Expr', ')'], ['number']] }结合性处理方案:
- 左递归实现左结合(如
Expr → Expr + Term) - 右递归实现右结合(如
Expr → Term + Expr)
3. Python实现语法树构建
以下是完整的语法解析器实现:
import re class TreeNode: def __init__(self, value): self.value = value self.children = [] def add_child(self, node): self.children.append(node) def __str__(self, level=0): ret = " " * level + repr(self.value) + "\n" for child in self.children: ret += child.__str__(level+1) return ret class Parser: def __init__(self, expression): self.tokens = re.findall(r'\d+|[()+*/-]', expression) self.current_token = None self.next_token() def next_token(self): if self.tokens: self.current_token = self.tokens.pop(0) else: self.current_token = None return self.current_token def parse(self): tree = self.parse_expr() if self.current_token is not None: raise SyntaxError("Unexpected token") return tree def parse_expr(self): node = self.parse_term() while self.current_token in ('+', '-'): op = self.current_token self.next_token() right = self.parse_term() new_node = TreeNode(op) new_node.add_child(node) new_node.add_child(right) node = new_node return node def parse_term(self): node = self.parse_factor() while self.current_token in ('*', '/'): op = self.current_token self.next_token() right = self.parse_factor() new_node = TreeNode(op) new_node.add_child(node) new_node.add_child(right) node = new_node return node def parse_factor(self): if self.current_token == '(': self.next_token() node = self.parse_expr() if self.current_token != ')': raise SyntaxError("Expected ')'") self.next_token() return node elif self.current_token.isdigit(): node = TreeNode(self.current_token) self.next_token() return node else: raise SyntaxError("Unexpected token") # 示例使用 expression = "(1+2)*3" parser = Parser(expression) syntax_tree = parser.parse() print(syntax_tree)输出结果示例:
'*' '+' '1' '2' '3'4. 文法设计与调试技巧
常见问题排查表:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无法识别括号表达式 | Factor规则未正确定义 | 检查Factor → ( Expr )规则 |
| 运算符优先级错误 | 层级结构不正确 | 确保乘除在加减上层 |
| 右结合变成左结合 | 递归方向错误 | 将左递归改为右递归 |
扩展支持更多运算符:
# 添加指数运算(右结合) grammar['Term'].append(['Factor', '^', 'Term'])通过这种结构化方法,我们可以逐步构建复杂的语法解析器,同时保持代码的可维护性和扩展性。
编程学习
技术分享
实战经验