惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
W
WeLiveSecurity
O
OpenAI News
N
News and Events Feed by Topic
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Webroot Blog
Webroot Blog
Google Online Security Blog
Google Online Security Blog
云风的 BLOG
云风的 BLOG
N
News | PayPal Newsroom
H
Hacker News: Front Page
博客园_首页
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Last Watchdog
The Last Watchdog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Heimdal Security Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
Schneier on Security
宝玉的分享
宝玉的分享
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Y
Y Combinator Blog
Cyberwarzone
Cyberwarzone
Microsoft Security Blog
Microsoft Security Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
GbyAI
GbyAI
Cloudbric
Cloudbric
TaoSecurity Blog
TaoSecurity Blog
人人都是产品经理
人人都是产品经理
P
Palo Alto Networks Blog
M
MIT News - Artificial intelligence
G
GRAHAM CLULEY
C
Check Point Blog
Apple Machine Learning Research
Apple Machine Learning Research
Last Week in AI
Last Week in AI
T
Troy Hunt's Blog
L
Lohrmann on Cybersecurity
www.infosecurity-magazine.com
www.infosecurity-magazine.com
P
Proofpoint News Feed
Blog — PlanetScale
Blog — PlanetScale
量子位
博客园 - 聂微东
S
Securelist
博客园 - 三生石上(FineUI控件)
F
Full Disclosure
G
Google Developers Blog
L
LINUX DO - 热门话题
P
Proofpoint News Feed
AI
AI
PCI Perspectives
PCI Perspectives

See you soon

试试将文章版本化管理吧 | See you soon 使用 Quadlet 将 Podman 中的 Postgres 当作 systemd 服务运行 | See you soon 大他者,那个无时无刻都在盯着你的东西 | See you soon Laws of Software Engineering,软件工程定律 | See you soon 浅记多因素身份认证 | See you soon Linux 内核中的度量单位 | See you soon 重置 GPG 智能密钥 | See you soon 向 NAS 引入 samba | See you soon 无法重复键入的 Fcitx5 | See you soon ZFS 降级事故 | See you soon 记被 XanMod Kernel 和 AppArmor 联合坑的一次踩坑 | See you soon agent 的 skill 与 toolcall | See you soon 记一次服务器被挂恶意挖矿二进制 | See you soon 活着的 Arc | See you soon 令 acme.sh 使用 Cloudflare 的 DNS API 签发与续签证书 | See you soon 于 Tokio 中卸载 CPU Bound 任务 | See you soon 如我所见,梦破碎的时候 | See you soon 74LS 家族手册 | See you soon JDK Projects 备忘录 | See you soon 关于历史 | See you soon 用 curl 下载 OnePlus 的 ROM | See you soon 实用命令切片 | See you soon 再见,Oh My Zsh。 | See you soon 你不应该复用 strings.Builder | See you soon 博客的明日 | See you soon 被 AppArmor 击杀的 Dockge | See you soon AI 时代的自我 | See you soon 支持删除的布隆过滤器 | See you soon 基于栈的虚拟机与基于寄存器的虚拟机 | See you soon RVA23 包含了什么 | See you soon Rust 的边界检查是否已经有很大的进步 | See you soon 使用 Rust 编写操作系统:Barebones | See you soon 使用 Rust 编写操作系统:引言 | See you soon 编译器笔记:rope | See you soon 编译器笔记:CST | See you soon Paradoxical 札记 | See you soon 简单的相似去重算法(基于向量) | See you soon 更加现代的 PaperMC Minecraft 插件设计指南 | See you soon 简单地使用 Caddy 实现 CORS 配置 | See you soon 让 OpenCV 可以被静态链接 | See you soon 图片搜索笔笺 | See you soon 电路板设计笔记-保护 | See you soon 使用 Rust 实现 SnowflakeId | See you soon 农夫乐事 FaQ 启示 | See you soon 使用 Rust 实现拓展系统札记 | See you soon 遗传学定律的代码实现 | See you soon EN:The Journey of Rust and Procps | See you soon ZH:Rust 与 Procps 之旅 | See you soon 使用 debootstrap 与 schroot 构建一个纯净环境 | See you soon GPG添加新的用户信息 | See you soon GSoC2024 笔记:使用 Rust 重新实现 procps | See you soon JWT 小册 | See you soon 使用密钥登录 SSH | See you soon Guava:Cache | See you soon 编译器笔记:增量编译 | See you soon Gradle秘境:添加一个类似modCompileOnly的依赖块 | See you soon Minecraft:原始经济系统设计简述 | See you soon TinyRemapper笔记 | See you soon MicroOS:进阶 | See you soon MicroOS:起步 | See you soon Swapfile 指北 | See you soon GPG 物理密钥的安装与密钥的迁移 | See you soon 用GPG签名告诉大家这就是我的提交 | See you soon DFS:深度优先搜索 | See you soon 文章翻译:从init.vim到init.lua | See you soon 目录遍历攻击 | See you soon 如何挂载.img文件,以及如何使用QEMU模拟arm64环境 | See you soon 在树莓派上编译 OpenCV | See you soon 关于卸载BlueStacks后遇到的问题 | See you soon
简单的 CFG 语法分析方法 | See you soon
Krysztal Huang · 2025-04-28 · via See you soon

有些时候吧人就是贱,想写点吃力不讨好的东西。今天就写点上下文无关文法(Context-Free Grammar, CFG)的两个算法吧。

请注意,这部分不是我擅长的领域,我只是因为好奇这方面的事情而自学过。如有纰漏,还请海涵。

本篇内容偏多偏杂,请善用右侧的 ToC 来快速导航 :)

文法(Grammar)

首先先明确一下,文法(Grammar)和语法(Syntax)是两个东西。

  • 文法是形式化的约定,使用一套符号系统来进行严格定义,为编译器或者解析器所使用的形式化规则
  • 语法则为语言设计者所定义的语言规范

我们在这里要做的是讨论解析器/编译器所使用的形式化规则,那么我们的重点则是文法而不是语法。

文法的形式化表达

先放一个例子在这里,免得无聊吧

E → T E’E’ → + T E’ | ε
T → F T’
T’ → * F T’ | ε
F → ( E ) | id\

无聊是不无聊了,但是看到符号就食欲不振。让我们更加深入一些:

终结符 Terminal Symbols

如其所述,终结符意味着终结,代表着该符号不可被再分解,例如 * ( ) id 等等等。(这里的 id 代指标识符,例如变量名或者关键字等)

以我们上文所给的例子:

  • id:标识符(如变量名、数字等)。
  • +, *:运算符。
  • (, ):括号。
  • $:输入结束符(过程中添加的标记,表示输入的末尾)。

再回去看上文的例子,就感觉清晰不少了不是吗?好,我们继续深入这个例子中各项的意义。

非终结符 Non-Terminal Symbols

非终结符是文法中需要进一步推导的符号,通常使用大写符号来表示:例如例子中的 E T,它们代表语法结构中的抽象概念,如表达式、项、因子等。

继续以我们上文提到的例子:

  • E:表达式 Expression
  • E':表达式后缀(用于消除左递归)。
  • T:项 Term
  • T':项后缀(用于消除左递归)。
  • F:因子 Factor

其他符号

要是你仔细点的话,会看到这里还有其他符号:

    • 推导关系,左侧是非终结符,右侧是可能产生的表达式
    • 如果不方便编写的话写作 := 也是可以的
  • |
    • 表达关系,意味着该非终结符可以被推导为多个可能的符号序列
    • 例子:E' → + T E' | εE' 可以被推导为 + T E' 或者 ε
  • ε
    • 空推导,意义为可以被推导为什么都不做
    • 还是以刚刚的例子,E' → ε 就可以认为 E' 什么都不做,则 E' 可以直接消失

产生式 Productions

基于上述规则,我们可以组合出更复杂的东西:产生式

产生式定义了对于非终结符号的定义规则,我们来看一些产生式例子:

  • E → T E'
    • 该产生式由一个项 T 和一个后缀构成 E'
      • T 处理项(如乘法、除法等)
      • E' 处理加法或减法的后缀
  • F → ( E ) | id
    • 因子 F 可以是括号内的表达式 E 或标识符 id
  • E' → + T E' | ε
    • 后缀 E' 可以是 + T E' 也可以是 ε

等等,E, T, F 又是什么东西?!

文法符号 Grammar Symbol

请注意,接下来有些概念可能会产生混淆:接下来的概念基本上都属于数学表达式的分层结构,而不是数字运算的优先级顺序

  • 因子,FFactor
    • 原子单元,他们无法被进一步分解,例如 id(E)
  • 项,TTerm
    • F 乘法除法组成的单元,例如 T → F * F
  • 表达式,EExpression
    • T 通过加法减法组成的单元,例如 E → T + T

特别的,id 是在我们当前的语境下引入的新原子单元,称之为标识符 identifier

等等,好像混进来奇怪的东西?(E) 又是啥玩意儿?

考虑到一个表达式可以被分解成由 F 构造的产生式,我们将分解这个步骤使用 () 进行封装成为一个整体,这样可以减轻各方面的压力

如果再允许 (E) 进行分解,那么很可能导致文法中出现左递归和更复杂的结构

举个例子单独说明 F → (E) 的情况,在这种情况下不能认为包含了 E 所以可以无限推导下去,因为 E 必须被完全推导为具体的符号:

F → ( E ) → ( T E' ) → ( F T' E' ) → ( id * F T' E' ) → ... → ( id * id )

以上的例子最终将 F → ( E ) 分解成为了具体的符号序列作为因子的实例