编译原理基础:FIRST 集合与提取公共左因子

编译原理基础:FIRST 集合与提取公共左因子

嗨!如果你正在学编译原理,可能会觉得有些概念听起来很高大上,比如 FIRST 集合和提取公共左因子。别担心,今天我们就来聊聊这两个东西,用简单的话讲明白它们是什么,以及为什么它们在编译器设计里很重要。

FIRST 集合:从哪开始?

感性理解

想象你在写一个程序,编译器得搞清楚你的代码从哪里开始解析。比如你写了个表达式,编译器得知道第一个符号可能是啥------是数字?变量?还是括号?这个"第一个可能出现的符号"的集合,就是 FIRST 集合。简单来说,它就像是编译器的小抄,告诉它:"嘿,这串代码开头可能是这些东西哦!"

形式化表达

在文法里(比如上下文无关文法),FIRST 集合是针对某个非终结符(non-terminal)或产生式,计算出它能推导出的字符串的第一个终结符(terminal)的集合。

定义一下:

  • 对于文法中的非终结符 A,FIRST(A) 就是所有从 A 推导出的字符串的第一个终结符的集合。
  • 如果 A 能推导出空串 ε,那么 ε 也算在 FIRST(A) 里。

举个例子:

假设有文法:

r 复制代码
E → T + E | T  
T → id | ( E )  
  • FIRST(T) 是啥?T 可以推导出 "id" 或 "( E )",所以 FIRST(T) = { id, ( }。
  • FIRST(E) 呢?E 可以推导出 T 开头的东西,所以 FIRST(E) = FIRST(T) = { id, ( }。

这个集合的作用是啥?它帮编译器在预测式分析(比如 LL(1) 文法)里快速判断下一步该走哪条路。

提取公共左因子:让文法更"干净"

感性理解

假设你在写代码,编译器看到你写的语句开头老是重复,比如"if (条件) ..." 和 "if (条件) ...",它会觉得有点晕:这两条路开头一样,咋分啊?提取公共左因子就像是把这些重复的开头抽出来,整理一下,让编译器更容易看懂你的文法。

形式化表达

在文法里,如果一个非终结符的多个产生式有相同的开头(公共左因子),就会导致解析时出现二义性。提取公共左因子的方法是把这些公共部分抽出来,变成一个新的产生式,剩下的部分单独处理。

比如:

css 复制代码
A → α β1 | α β2  

这里 α 是公共左因子,可以改成:

css 复制代码
A → α A'  
A' → β1 | β2  

举个例子:

假设有文法:

bash 复制代码
S → id = E | id + T  

两个产生式都以 "id" 开头,提取公共左因子后变成:

bash 复制代码
S → id S'  
S' → = E | + T  

这样,编译器看到 "id" 就知道先走 S,然后再看后面是 "=" 还是 "+",一步步解析就清晰多了。

为什么这两个东西重要?

  • FIRST 集合:它是预测式语法分析的核心工具,帮助编译器快速决定从哪个产生式开始推导,避免瞎猜。
  • 提取公共左因子:它能消除文法中的二义性,让编译器解析时不"撞车",特别在 LL(1) 文法里很关键。

小结

FIRST 集合像是文法的"导航仪",告诉编译器每一步可能的方向;提取公共左因子像是"整理大师",把乱糟糟的文法收拾得井井有条。学编译原理的时候,这俩是基础中的基础,理解了它们,你就离写一个自己的编译器更近一步啦!下次我们再聊聊 FOLLOW 集合和怎么用这些工具做预测分析,加油哦!

相关推荐
鬼火儿7 小时前
SpringBoot】Spring Boot 项目的打包配置
java·后端
cr7xin7 小时前
缓存三大问题及解决方案
redis·后端·缓存
间彧8 小时前
Kubernetes的Pod与Docker Compose中的服务在概念上有何异同?
后端
间彧8 小时前
从开发到生产,如何将Docker Compose项目平滑迁移到Kubernetes?
后端
间彧8 小时前
如何结合CI/CD流水线自动选择正确的Docker Compose配置?
后端
间彧8 小时前
在多环境(开发、测试、生产)下,如何管理不同的Docker Compose配置?
后端
间彧8 小时前
如何为Docker Compose中的服务配置健康检查,确保服务真正可用?
后端
间彧8 小时前
Docker Compose和Kubernetes在编排服务时有哪些核心区别?
后端
间彧8 小时前
如何在实际项目中集成Arthas Tunnel Server实现Kubernetes集群的远程诊断?
后端
brzhang9 小时前
读懂 MiniMax Agent 的设计逻辑,然后我复刻了一个MiniMax Agent
前端·后端·架构