上下文无关文法与下推自动机
比正则高一级的语言类:上下文无关(CFL)——大多数编程语法的层次。本章讲 CFG 的推导与语法树、歧义性、Chomsky 范式、下推自动机与 CFL 的泵引理,以及 LR 解析器的位置(→ 语法与语义)。
CFG 与语法树
Section titled “CFG 与语法树”上下文无关文法:产生式左端是单个非终结符()——"一个符号展开成什么",与上下文无关(这正是名字的来源):
推导(从 S 出发反复应用产生式)对应语法树(parse tree)——叶子连起来是串。语法分析 = 给定串,重建语法树(或证明不存在)。
歧义文法:同一串有两个不同的语法树——语义随之不明。经典例子悬空 else:
if a then if b then x else y 中 else 归属哪个 if?两个语法树都合法。歧义文法是语言设计的常见问题:解决靠改文法(无歧义版本,配对结构化)或语义约定("最近 if")。注意:有些语言天生无歧义文法不存在(固有歧义),但多数实用语言可以消除。
下推自动机(PDA)
Section titled “下推自动机(PDA)”给 NFA 加一个栈:转移可以读写栈顶。PDA 与 CFG 等价(识别同样的语言):
- 栈匹配嵌套结构:读到
(压栈、)弹栈——括号配对需要一个栈,这就是 CFL 超出正则的能力; - 是 CFL(压 弹 )但 不是——一个栈只能同时记住一个计数;
- CFL 的泵引理证明非 CFL(如 、)。
Chomsky 范式与 CYK
Section titled “Chomsky 范式与 CYK”Chomsky 范式(CNF):产生式只允许 与 ——任何 CFG 都能转换(可能引入新符号)。CNF 的回报:CYK 算法用动态规划判定成员资格与重建语法树:
——CYK 算法 O(n³) 判定成员资格,是 CFL 解析的理论基线(工程解析器更快,见下)。
LR 解析器:确定性的 CFL
Section titled “LR 解析器:确定性的 CFL”通用 CFL 解析(CYK、Earley)太慢。LR(k) 解析器处理确定性 CFL(每一步看 k 个前瞻符号就能定):
- 自底向上:从叶子向根归约,用栈 + 状态机(LALR 表);
- 线性时间 ;LR 解析器处理确定性 CFL——yacc/bison 的 LALR(1) 与多数编译器(递归下降)处理的都是这个类;
- CFG 的实用子集:编程语言的语法几乎都在确定性 CFL 里——上下文无关够用(表达嵌套),确定性够快(线性)。
而语义不是上下文无关:类型检查、变量声明先于使用——这些是上下文相关的约束,由语义分析(符号表)处理,不塞进文法(→ 语法与语义)。
- 括号配对需要一个栈:PDA 与 CFG 等价,栈是超出正则的能力
- 是 CFL, 不是——一个栈记一个计数
- 歧义文法是语言设计的常见问题(悬空 else);多数可消除
- CYK 算法 O(n³) 判定成员资格(Chomsky 范式的回报)
- LR 解析器处理确定性 CFL,线性时间;语义约束(类型)不是 CFL,交给符号表