编译原理基础: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 管后续。试着自己写个小文法,建个分析表跑跑看,动手玩玩就更明白了!加油哦!

相关推荐
m0_640602447 分钟前
2026 年餐饮收银系统前后端技术实现——核心架构与原理详解
后端·微服务·云原生·架构
Scene21610 分钟前
Flux 与 Mono:Project Reactor 核心响应式类型深度解析
后端
lingran__15 分钟前
C++ STL unordered系列(哈希) 底层剖析与模拟实现万字详解 | 基于哈希表,复刻 SGI-STL 泛型哈希容器架构
开发语言·c++·后端·哈希算法·哈希表·泛型编程·unordered系列
小林ixn26 分钟前
NestJS 入门实战:从 0 到 1 撸一个 Todo CRUD,感受装饰器与模块化的优雅
后端·mvc·nestjs
阿弱32 分钟前
graph-core 的边与命令模式设计
java·后端·agent
智驭未来掌门人33 分钟前
利用Qt设计实现一款桌面程序
后端
长栎40 分钟前
你以为抽象工厂是「创建一组对象」——其实它是「锁定产品族兼容性」
后端
长栎42 分钟前
你的 AI 品控规则越来越多了——但它们已经在打架了,你没看见
后端
有脚就行1 小时前
第24篇-Go-gRPC推理服务-高性能跨语言通信
开发语言·人工智能·后端·golang
不好听6131 小时前
NestJS 是什么?一张图看懂企业级后端的骨架
后端·nestjs