📜  将上下文无关语法转换为 Greibach 范式(1)

📅  最后修改于: 2023-12-03 14:53:46.588000             🧑  作者: Mango

将上下文无关语法转换为 Greibach 范式

什么是上下文无关语法?

上下文无关语法(Context-Free Grammar,简称CFG)是一种描述语言结构形式的形式语言,它通过一系列产生式描述语言的句子结构。上下文无关语法中每个产生式的左部是非终结符,右部是由非终结符和终结符组成的符号串,其中非终结符可以被替换为其他符号串。

什么是Greibach范式?

Greibach范式是一种特殊的上下文无关语法表示方法,其定义如下:

  • S -> aA₁|bB₁
  • A → aA₁|bB₁|cC₁
  • B → bB₁|cC₁|ε
  • C → cC₁|bB₁|aA₁

其中,S是起始符号,a、b、c是终结符,A、B、C是非终结符,ε表示空串。

在Greibach范式中,每个产生式的右部都是一个非终结符跟一个终结符或一串非终结符,左部只有一个非终结符。

将CFG转换为Greibach范式

将一个给定的CFG转换为Greibach范式需要按照以下步骤进行:

  1. 定义一个新的非终结符S'作为起始符号。

  2. 消除CFG中右部长度超过1的产生式,即将产生式的右部中包含多个终结符和/或非终结符的产生式转化为多个只包含一个非终结符和终结符的产生式。

  3. 消除CFG中的左递归,即将产生式左部与右部都以相同的非终结符开头的产生式转化为右递归的产生式。

  4. 对转换后的CFG进行左因式分解,即将产生式左部相同的产生式归为一组,将每组中包含多个产生式的左部非终结符拆分为新的非终结符。

  5. 将每个产生式的右部中的非终结符替换为它能够推导出的字符串的列表,并将列表按照字典序升序排列,从而得到转换后的Greibach范式。

代码示例
def to_greibach(grammar):
  # Step 1
  grammar['S\''] = [grammar['S'][0][0]]
  # Step 2
  for nt in grammar:
    productions = grammar[nt]
    for p in productions:
      rhs = p[1]
      if len(rhs) > 1:
        new_nt = nt + '_' + rhs[1:]
        grammar[new_nt] = [rhs[1:], ('@', new_nt)]
        grammar[nt].remove(p)
        grammar[nt].append((rhs[0], new_nt))
  # Step 3
  for nt in grammar:
    productions = grammar[nt]
    alpha = []
    beta = []
    for p in productions:
      rhs = p[1]
      if rhs.startswith(nt):
        alpha.append(p)
      else:
        beta.append(p)
    if alpha:
      new_nt = nt + '\''
      grammar[new_nt] = [('@', new_nt)]
      grammar[nt] = [(p[1][1:], new_nt) for p in beta]
      for p in alpha:
        grammar[new_nt].append((p[1][1:], new_nt))
  # Step 4
  for nt in grammar:
    productions = grammar[nt]
    groups = {}
    for p in productions:
      key = p[0]
      if key not in groups:
        groups[key] = []
      groups[key].append(p)
    new_productions = []
    for k in groups:
      if len(groups[k]) == 1:
        new_productions.append(groups[k][0])
      else:
        new_nt = nt + '_' + k
        grammar[new_nt] = []
        for p in groups[k]:
          grammar[new_nt].append(p[1:])
        new_productions.append((k, new_nt))
    grammar[nt] = new_productions
  # Step 5
  for nt in grammar:
    productions = grammar[nt]
    for i, p in enumerate(productions):
      rhs = p[1]
      if rhs in grammar:
        rhs_productions = grammar[rhs]
        new_rhs = ''
        for rp in rhs_productions:
          new_rhs += rp[0]
        new_production = (p[0], new_rhs)
        productions[i] = new_production
    productions.sort(key = lambda x: x[1])
  return grammar

# Example
grammar = {
  'S': [('A', 'b'), ('B', 'a')],
  'A': [('A', 'c'), ('B', 'b'), ('a',)],
  'B': [('B', 'a'), ('c',), ('@',)]
}
greibach_grammar = to_greibach(grammar)
print(greibach_grammar)