编译原理基础:LL(1) 文法与 LL(1) 分析法

编译原理基础:LL(1) 文法与 LL(1) 分析法

嗨!学编译原理是不是觉得有点像解谜游戏?今天我们要聊聊 LL(1) 文法和 LL(1) 分析法,这俩是编译器设计里的"预测大师",能让解析代码变得简单又高效。别怕,我会用大白话讲明白它们是啥,还会带点形式化的定义,帮你一步步搞懂!

LL(1) 文法:不纠结的文法

感性理解

想象你在做选择题,每个题目的开头都长得不一样,你一看就能知道选哪个答案,完全不用犹豫。LL(1) 文法就像这样的"完美选择题":编译器读到代码的某个符号,只看一眼(一个 token),就能立刻决定走哪条路解析,不用猜来猜去。简单说,它是让编译器"果断"的文法。

形式化表达

LL(1) 是一种上下文无关文法(CFG),名字里的意思是:

  • 第一个 L:从左到右扫描输入。
  • 第二个 L:用最左推导(leftmost derivation)。
  • 1:只看一个符号(lookahead 一个 token)就能决定用哪个产生式。

一个文法是 LL(1) 的,必须满足:

  1. 对于非终结符 A 的每个产生式 A → α | β,FIRST(α) 和 FIRST(β) 没有交集(开头不能撞车)。
  2. 如果 α 或 β 能推 ε(空串),则 FIRST(β) 或 FIRST(α) 不能和 FOLLOW(A) 有交集(空串时后续也不能冲突)。

例子

css 复制代码
S → a S | b
  • FIRST(a S) = { a },FIRST(b) = { b },没交集,是 LL(1)。 但如果改成:
css 复制代码
S → a S | a T
  • FIRST(a S) = { a },FIRST(a T) = { a },有交集,就不是 LL(1)。

LL(1) 分析法:一步到位的解析

感性理解

LL(1) 分析法就像是拿着一个"导航表"开车。编译器一边读代码,一边查表,看到当前符号和栈顶的非终结符,就能立刻知道下一步是推导啥,还是跳过啥。整个过程干净利落,像玩拼图一样,步步到位,最后拼出整个程序。

形式化表达

LL(1) 分析法是一种自顶向下的预测分析法,用一个预测分析表(parsing table)和栈来解析输入。核心步骤:

  1. 构建预测分析表
    • 行是文法的非终结符,列是终结符(包括 $)。
    • 根据 FIRST 和 FOLLOW 集合填表:
      • 对于 A → α,若 t ∈ FIRST(α),表[A, t] = A → α。
      • 若 α 能推 ε,则对 t ∈ FOLLOW(A),表[A, t] = A → α。
  2. 解析过程
    • 用栈保存推导状态,从开始符号 S 入栈。
    • 读输入符号,栈顶如果是:
      • 终结符:匹配就弹出,继续读。
      • 非终结符:查表,替换成对应产生式。
    • 栈空且输入读完,解析成功。

例子: 文法:

css 复制代码
S → a S | b
  • FIRST(S → a S) = { a },FIRST(S → b) = { b }。

  • FOLLOW(S) = { $ }(假设 S 是开始符号)。

  • 预测分析表:

    a b $
    S S→aS S→b
  • 输入 "aab":

    • 栈:[S],输入:aab$
    • 查表 S,a → S→aS,栈:[a S],匹配 a,栈:[S]
    • 查表 S,a → S→aS,栈:[a S],匹配 a,栈:[S]
    • 查表 S,b → S→b,栈:[b],匹配 b,栈:[]
    • 输入读完,栈空,成功!

为啥 LL(1) 这么重要?

  • 简单高效:只看一个符号就能决定下一步,解析速度快。
  • 好实现:预测分析表直接告诉编译器怎么走,不用回溯。
  • 有限制但实用:虽然不是所有文法都是 LL(1),但通过提取公共左因子、消除左递归,可以改成 LL(1)。

小结

LL(1) 文法是"果断"的文法,保证编译器不纠结;LL(1) 分析法是"导航"的方法,让解析一步到位。它们靠 FIRST 和 FOLLOW 集合合作,FIRST 管开头,FOLLOW 管后续。试着自己写个小文法,建个分析表跑跑看,动手玩玩就更明白了!加油哦!

相关推荐
橡果的笔记1 分钟前
基础通用接口复用
后端
kfhj2 分钟前
Spring Cloud 框架为什么能处理高并发
后端·spring·spring cloud
struggleupwards3 分钟前
Gin 模板自动生成 DDD 代码结构
后端
zm就是zm3 分钟前
一天一个知识点 - HTTPSTATUS 100
后端
为神敬酒者4 分钟前
uri标签导致http.client.requests指标膨胀问题
后端
Asthenia041215 分钟前
博客:八股文网站验证码解锁与JWT登录机制解析/前端Vuex实现
后端
滕昕瑜27 分钟前
Pascal语言的操作系统安全
开发语言·后端·golang
Asthenia041240 分钟前
Java 后端实现 App 列表滚动加载:用游标优化深翻页问题
后端
stark张宇1 小时前
三步接入DeepSeek智能对话API:PHP代码实现与响应解析
后端·php·deepseek
Asthenia04121 小时前
深入探讨DDD中的聚合根:以电商业务场景为例
后端