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

时间:2017-10-03 12:20:34

标签: parsing grammar

如何消除后续语法中的含糊之处?

if(this.state.messages['hydra:member'] !== undefined) {
    let messages = JSON.parse(JSON.stringify(this.state.messages['hydra:member']));
   //use messages here
}

1 个答案:

答案 0 :(得分:2)

首先,我们需要找到歧义。

考虑没有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

现在,考虑使用F而不是f:

的原始语法
E -> F + E | A
A -> A * F | F
F -> F - F | id
这是不明确的?它是。考虑字符串id - id - id。

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
|
A
|
F
|
+----+----+----+
     |    |    |
     id   -    F
               |
            +--+-+
            |  | |
            id - F
                 |
                 id

现在,这个语法是不明确的?事实并非如此。

  • s中会有#(+)+ s,我们总是需要使用生产E - > F + E正好#(+)次然后生产E - >一次。
  • 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必须正好使用一次,如下所示:

如果E - >; A永远不会被使用,任何派生的字符串仍然会有E,一个非终结符号,因此不会是该语言中的字符串(如果没有使用E - > A至少一次就不生成任何内容)。此外,在使用E之前可以生成的每个字符串 - > A中最多只有一个E(你从一个E开始,唯一的另一个产品保留一个E)所以永远不可能使用E - >不止一次。所以E - > A仅对所有派生字符串使用一次。对于A - >演示以相同的方式工作。 F和F - >标识。

那个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.