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一次
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一次
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次和