Parsing 如何消除下列语法中的歧义?

Parsing 如何消除下列语法中的歧义?,parsing,grammar,Parsing,Grammar,如何消除下列语法中的歧义 E -> E * F | F + E | F F -> F - F | id 首先,我们需要找到模棱两可之处 考虑不带F的E的规则;将F转换成F,并将其视为终端符号。然后是语法 E -> E * f E -> f + E E -> f 这是模棱两可的。考虑f+f*f: E E | | +-------+--+

如何消除下列语法中的歧义

E -> E * F | F + E | F

F -> F - F | id

首先,我们需要找到模棱两可之处

考虑不带F的E的规则;将F转换成F,并将其视为终端符号。然后是语法

E -> E * f
E -> f + E
E -> f
这是模棱两可的。考虑f+f*f:

    E                      E
    |                      |
    +-------+--+           +-+-+
    |       |  |           | | |
    E       *  f           f + E
  +-+-+                        |
  | | |                        +-+-+
  f + E                        E * f
      |                        |
      f                        f
我们可以通过强制*或+优先来解决这种模糊性。通常,*按操作顺序优先,但这完全是任意的

E -> f + E | A
A -> A * f | f
现在,字符串f+f*f只有一个解析:

    E
    |
    +-+-+
    | | |
    f + E
        |
        A
        |
        +-+-+
        A * f
        |
        f
E
|
A
|
F
|
+----+----+----+
     |    |    |
     id   -    F
               |
            +--+-+
            |  | |
            id - F
                 |
                 id

现在,考虑我们用F代替F:

的原始语法。
E -> F + E | A
A -> A * F | F
F -> F - F | id
这是不明确的吗?它是。考虑字符串ID-ID-I.P/P>
E                    E
|                    |
A                    A
|                    |
F                    F
|                    |
+-----+----+----+    +----+----+----+
      |    |    |         |    |    |
      F    -    F         F    -    F
      |         |         |         |
    +-+-+       id        id      +-+-+
    F - F                         F - F
    |   |                         |   |
    id  id                        id  id
这里的歧义是-可以是左关联或右关联。我们可以选择与+相同的约定:

E -> F + E | A
A -> A * F | F
F -> id - F | id
现在,我们只有一个解析:

    E
    |
    +-+-+
    | | |
    f + E
        |
        A
        |
        +-+-+
        A * f
        |
        f
E
|
A
|
F
|
+----+----+----+
     |    |    |
     id   -    F
               |
            +--+-+
            |  | |
            id - F
                 |
                 id
现在,这个语法有歧义吗?事实并非如此

  • s将包含#(+)+s,我们总是需要使用production E->F+E精确地#(+)次,然后使用production E->A一次
  • s将包含#(*)*s,我们总是需要精确地使用生产A->A*F#(*)次,然后使用生产E->F一次
  • s将包含#(-)-s,并且我们总是需要精确地使用生产F->id-F次,生产F->id一次
s正好有#(+)+s、#(*)*s和#(-)-s,这是理所当然的(如果s中没有数字,则数字可以为零)。E->A、A->F和F->id必须精确使用一次,如下所示:

F -> id - F | id
如果从不使用E->A,则派生的任何字符串中仍将包含非终结符E,因此在该语言中不会是字符串(如果不使用E->A至少一次,则不会生成任何内容)。此外,在使用E->A之前可以生成的每个字符串中最多有一个E(您从一个E开始,只有其他生产保留一个E),因此不可能多次使用E->A。因此,E->A对所有派生字符串只使用一次。该演示对A->F和F->id的工作方式相同

E->F+E、A->A*F和F->id-F分别被精确地使用#(++)、#(*)和#(-)次,这一点很明显,因为这些是唯一引入各自符号的产品,并且每个产品都引入了一个实例

如果我们考虑所得语法的子文法,我们可以证明它们不含糊如下:

F -> id - F | id
这是
(id-)*id
的明确语法。
(id-)^kid
的唯一派生是使用
F->id-F
k次,然后只使用
F->id

A -> A * F | F
我们已经看到F对于它所识别的语言来说是明确的。根据相同的论点,这是语言
F(*F)*
的明确语法。推导
F(*F)^k
需要使用
A->A*F
精确的k次,然后使用
A->F
。因为从
F
生成的语言是明确的,并且因为
A
的语言使用*(不是由F生成的符号)明确地分隔了F的实例,所以语法

A -> A * F | F
F -> id - F | id

这也是毫不含糊的。要完成参数,请将相同的逻辑应用于从起始符号E生成(F+)*A的语法。

首先,我们需要找到歧义

考虑不带F的E的规则;将F转换成F,并将其视为终端符号。然后是语法

E -> E * f
E -> f + E
E -> f
这是模棱两可的。考虑f+f*f:

    E                      E
    |                      |
    +-------+--+           +-+-+
    |       |  |           | | |
    E       *  f           f + E
  +-+-+                        |
  | | |                        +-+-+
  f + E                        E * f
      |                        |
      f                        f
我们可以通过强制*或+优先来解决这种模糊性。通常,*按操作顺序优先,但这完全是任意的

E -> f + E | A
A -> A * f | f
现在,字符串f+f*f只有一个解析:

    E
    |
    +-+-+
    | | |
    f + E
        |
        A
        |
        +-+-+
        A * f
        |
        f
E
|
A
|
F
|
+----+----+----+
     |    |    |
     id   -    F
               |
            +--+-+
            |  | |
            id - F
                 |
                 id

现在,考虑我们用F代替F:

的原始语法。
E -> F + E | A
A -> A * F | F
F -> F - F | id
这是不明确的吗?它是。考虑字符串ID-ID-I.P/P>
E                    E
|                    |
A                    A
|                    |
F                    F
|                    |
+-----+----+----+    +----+----+----+
      |    |    |         |    |    |
      F    -    F         F    -    F
      |         |         |         |
    +-+-+       id        id      +-+-+
    F - F                         F - F
    |   |                         |   |
    id  id                        id  id
这里的歧义是-可以是左关联或右关联。我们可以选择与+相同的约定:

E -> F + E | A
A -> A * F | F
F -> id - F | id
现在,我们只有一个解析:

    E
    |
    +-+-+
    | | |
    f + E
        |
        A
        |
        +-+-+
        A * f
        |
        f
E
|
A
|
F
|
+----+----+----+
     |    |    |
     id   -    F
               |
            +--+-+
            |  | |
            id - F
                 |
                 id
现在,这个语法有歧义吗?事实并非如此

  • s将包含#(+)+s,我们总是需要使用production E->F+E精确地#(+)次,然后使用production E->A一次
  • s将包含#(*)*s,我们总是需要精确地使用生产A->A*F#(*)次,然后使用生产E->F一次
  • s将包含#(-)-s,并且我们总是需要精确地使用生产F->id-F次,生产F->id一次
s正好有#(+)+s、#(*)*s和#(-)-s,这是理所当然的(如果s中没有数字,则数字可以为零)。E->A、A->F和F->id必须精确使用一次,如下所示:

F -> id - F | id
如果从不使用E->A,则派生的任何字符串中仍将包含非终结符E,因此在该语言中不会是字符串(如果不使用E->A至少一次,则不会生成任何内容)。此外,在使用E->A之前可以生成的每个字符串中最多有一个E(您从一个E开始,只有其他生产保留一个E),因此不可能多次使用E->A。因此,E->A对所有派生字符串只使用一次。该演示对A->F和F->id的工作方式相同

E->F+E、A->A*F和F->id-F分别被精确地使用#(++)、#(*)和#(-)次,这一点很明显,因为这些是唯一引入各自符号的产品,并且每个产品都引入了一个实例

如果我们考虑所得语法的子文法,我们可以证明它们不含糊如下:

F -> id - F | id
这是
(id-)*id
的明确语法。
(id-)^kid
的唯一派生是使用
F->id-F
k次,然后只使用
F->id

A -> A * F | F
我们已经看到F对于它所识别的语言来说是明确的。根据相同的论点,这是语言
F(*F)*
的明确语法。
F(*F)^k
的推导需要使用
A->A*F
精确的k次和