当前位置: 首页 > news >正文

上下文无关文法 (CFG) 实战:3步构建无二义性四则运算语法树

上下文无关文法实战:三步构建无二义性四则运算语法树

在编程语言和数学表达式处理中,上下文无关文法(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'])

通过这种结构化方法,我们可以逐步构建复杂的语法解析器,同时保持代码的可维护性和扩展性。

http://www.jsqmd.com/news/1178802/

相关文章:

  • AWS Lambda 入门与生产实践:原理、调优与避坑指南
  • 模板驱动型文档自动化:从填空式生成到智能合规输出
  • 硬盘数据恢复实战:从故障分类到完整解决方案
  • # 360安全卫士极速版:从安装到入门完全指南
  • 【多线程 】线程状态 线程停止 线程休眠 线程礼让 线程插队(Join) 线程状态观测 线程优先级 守护线程 并发 线程同步 队列和锁 线程同步
  • HarmonyOS7 多线程:Worker 让耗时任务不再卡 UI
  • CentOS 7 搭建 DNS 主从服务
  • 我的本地化AI项目(三)
  • Claude 被封号,字节免费提供 GLM-5.2
  • 生产环境Socket编程落地实战指南(TCP/UDP工程化方案)
  • 百度网盘解析工具完整指南:三步告别限速困扰,实现高速下载自由
  • Ubuntu 20.04源码编译ROS2 Foxy实战指南
  • 等价类划分法实战:城市电话号码15个测试用例设计,覆盖4有效11无效
  • Prometheus Pushgateway v1.2.0 部署与配置:Kubernetes 集群 3 步集成实战
  • TPS61170与TM4C129XNCZAD的高效DC-DC升压方案解析
  • 高精度ADC选型与MCP3551应用指南
  • Android Studio完整界面汉化指南:5分钟实现IDE本地化终极方案
  • BepInEx框架解析:解决Unity插件开发三大痛点与实战优化
  • AI FDE 能力模型详解:从价值判断到资产复用的七项能力
  • 无血性者,难以为领
  • 读代码、修 Bug、补测试、写文档:四套拿来即用的工作流模板
  • ArcGIS Pro 3.2 三维地质建模:从钻孔数据到MultiPatch体模型的7步实战
  • 模板驱动型文档自动化:结构化组装替代手工写作
  • Tableau 自定义地理编码指南:解决 3 类无法识别位置数据的实战方案
  • IEEE 754 标准解析:从 32 位 float 到 64 位 double 的精度与范围对比
  • 电脑上的功能键到底都是干啥的?一篇文章教你使用功能键
  • Pixhawk固件加载全流程:从Bootloader刷写到飞行验证
  • ADS 2021 三大仿真模型导入实战:DesignKit/SNP/SPICE 的 3 种场景化应用
  • 从 HydroShear 93% Sim-to-Real 成功率看触觉数据标注工具的技术演进
  • C++实现KD-Tree:从原理到实战,解决多维空间最近邻搜索难题