文法的定义和记号
$$ G = (V_N, V_T, P, S) \qquad (V_N \cap V_T = \varnothing, V_N \cup V_T = V) $$
是 N.Chomsky 在 1956 年描述形式语言时首先给出的。同时,Chomsky 还对产生式的形式给以不同的限制而定义了四类基本的文法,分别称之为 0 型文法,1 型文法,2 型文法和 3 型文法。
明确定义
- 0 型文法:对任一产生式 $\alpha \to \beta$,都有 $\alpha \in V^+, \quad \beta \in V^*$
- 1 型文法:对任一产生式 $\alpha \to \beta$,都有 $\mid\beta\mid \ge \mid\alpha\mid, \quad \alpha,\beta \in V^+$,仅仅 $\alpha \to \epsilon$ 除外
- 2 型文法:对任一产生式 $A \to \beta$,都有 $A \in V_N, \quad \beta \in V^+$
- 3 型文法:任一产生式都形如 $A \to Ba$ 或 $A \to a$,其中 $A,B \in V_N, \quad a \in V_T$,该文法称为右线性文法。类似可定义左线性文法。
判断思路
0 型文法
字符串 $\alpha$ 的范围是 $V^+$,是全符号集的一个正闭包,即符号集中所有符号的任意组合,且不包含 $\epsilon$ 元素
字符串 $\beta$ 的范围是 $V^*$,是全符号集的自反传递闭包,也即 $V^+ \cup {\epsilon}$
要判断一个文法是否是 0 型文法,只需要判断左侧非空且不全为小写即可
任何 0 型语言都是递归可枚举的,故 0 型语言又称递归可枚举集
1 型文法
首先 1 型文法必须是 0 型文法
1 型文法除了 $\alpha \to \epsilon$ 这个特例外,其他情况都满足 $\beta$ 的长度大于 $\alpha$ 的长度
1 型文法也叫上下文相关(敏感)文法
2 型文法
首先 2 型文法必须是 1 型文法
2 型文法左侧必须是一个非终结符
2 型文法也叫上下文无关文法
3 型文法
首先 3 型文法必须是 2 型文法
3 型文法必须满足以下两种形式之一
- $A \to aB$ 或 $A \to a$
- $A \to Ba$ 或 $A \to a$
- 3 型文法也叫正规文法
代码实现
保存产生式集
可以使用 List
来保存所有产生式,用内部类来表示具体的产生式:
1 | public class Chomsky { |
判断 0 型文法
遍历产生式集,如果有一个产生式不符合条件,则直接退出。
1 | public boolean isZero() { |
关于判断左部是否全为小写,使用 String.toLowerCase()
将其转换为小写后再与原产生式比较,相等则原产生式为小写。
判断 1 型文法
1 | public boolean isFirst() { |
1 型文法必须先是 0 型文法。
1 型文法的判断跳过了右部为 $\epsilon$ 的情况,即允许右部为 $\epsilon$。
判断 2 型文法
1 | public boolean isSecond() { |
2 型文法必须先是 1 型文法。
首先限制左部长度必须为 1,然后利用正则判断是否为小写,[a-z]
匹配一个小写字符。
判断 3 型文法
1 | public boolean isThird() { |
3 型文法必须先是 2 型文法。
全部源代码
Chomsky.java:
1 | import java.util.*; |