3 分钟阅读

0. OverviewPermalink

为什么需要化简?为提高编译器的执行效率。比如提高 “判定 w?L” 的效率。因为同一个 language L 可以有多种 grammar G,它们是有 “复杂程度”、”冗余度” 上的区分的。比如 CD,Dε 就是很冗余,你需要额外 lookup & apply 一次 production.

Types of Redundancy:

  1. ε-productions,i.e. 形如 Aε 的产生式
    • 会得到语言 L{ε}
  2. unit productions (单元产生式),i.e. 形如 AB 的产生式
  3. useless productions (无用产生式),i.e. 对文法定义语言没有贡献的产生式,分两类:
    1. non-reachable productions
      • 比如 {SABCc,这个 Cc 不可能被 S 触及,属于 non-reachable
    2. non-generating productions
      • 比如 {SABAaA,这个 AaA 不可能终结,属于 non-generating

工程中做 simplification 的可靠顺序是:

  1. Eliminate ε-productions
  2. Eliminate unit productions
  3. Eliminate non-generating productions
  4. Eliminate non-reachable productions

1. Eliminate ε-productionsPermalink

如果有一个 CFG G 和它的 CFL L,消除 ε-productions 之后会得到一个新的 CFG G 和新的 CFL L=L{ε}.

你也可以选择在 L 中保留 ε. 如果你需要这么做,可以在 G 保留一个 Sε.

Dummy Start Symbol: 工程中还有一个 preprocessing practice 是给 G 加一个 dummy production S0S,目的是 “确保 start symbol 不会出现在 production 的 body (i.e. RHS) 中”。因为如果你允许 Sε 并同时有 AS 时,会 imply Aε,工程上处理起来不是很清爽。我个人认为即时你没有允许 Sε,这个 preprocessing 也是个 good practice.

Procedure:

  1. Eliminate all Aε production from P (可以允许 A=S,也可以要求 AS,看你需求)
  2. 如果你消除了一个具体的 Aε,然后有 BβAγ
    • 你可能原来是 Aεα,你消除了 Aε 但仍然有 Aα,所以你不能直接把 BβAγ 中的 A 直接删掉
    • 如果原来就只有 Aε,你是可以直接把 BβAγ 中的 A 直接删掉,但记住我们后面还有 ”消除 non-generating symbols“ 的步骤,所以你保留 BβAγ 中的 A 也是 ok 的
    • 以上两种情况,有一个统一的解决方案就是:把 BβAγ 改写成 BβAγβγ
    • 归纳一下就是: occurrence of A on the body of a production rule, add a new rule to P with that occurrence of A deleted.
    • 一个更复杂的例子是:BβAγAθ,它要改写成 BβAγAθβγAθβAγθβγθ
  3. 如果你消除了一个具体的 Aε,然后有 BA,可以改写成 BAε
    • 是的,这里你有引入了一个新的 Bε,但我们可以 repeatedly 继续 eliminate
  4. Repeat step 1~3 直到所有的 ε-production 都被消除

2. Eliminate unit productionsPermalink

Procedure:

  1. Eliminate all AB production from P
  2. 如果你消除了一个具体的 AB,然后有 Bβ:可以直接添加一条 AβP
  3. Repeat step 1~2 直到所有的 unit-production 都被消除

Bonus: cycle-free grammar

A cycle in a grammar means a derivation A+A. Consider the following cases:

  1. If we have AAα, following the above procedure, we drop AA but keep Aα in P
  2. If we have {ABαBAβ, we drop AB and then augment into AαAβ. Problem is reduced to Case 1.

Therefore, eliminating unit productions (with ε-productions already eliminated) guarantees a cycle-free grammar.

3. Eliminate useless productionsPermalink

Procedure: Remove non-generating productions

  1. 初始化 V1=
  2. Repeat until no more variables are added:
    • AV with Ax1x2xn where xi(TV1), add A to V1
    • V1 becomes the set of generating variables
  3. Define P1=ppP and p.rhs(TV1)
    • P1 is the set of generating productions

The grammar G1=(V1,T,S,P1) is fully generating.

Definition: VDG (Variable Dependency Graph) of a given Grammar G=(V,T,S,P) can be constructed like below:

  1. For each variable AV, draw a vertex
  2. For each production AxByP, draw an edge AB

Procedure: Remove non-reachable productions (by VDG):

  1. Construct a VDG G=(V1,E?) for the generating grammar G1=(V1,T,S,P1)
  2. Find all variable AV1 that has no SA path
    • DFS or BFS
    • 注意是这里要求的是 directed path
  3. Remove such A from V1, get V2
  4. Remove production from P1 whose LHS is such an A, get P2

The grammar G2=(V2,T,S,P2) has no useless productions.

此时 T 中可能有 unreachable 的 terminal,可能需要额外扫描一遍 P2 来确定。

分类:

更新时间:

留下评论