Parsing 上下文无关文法的所有可行前缀

Parsing 上下文无关文法的所有可行前缀,parsing,compiler-construction,Parsing,Compiler Construction,我遇到了一个来自著名的编译器设计龙书的问题。如何找到以下语法的所有可行前缀: S -> 0S1 | 01 语法实际上是正则表达式0n1n的语言。 我假设所有可行前缀的集合也可能是正则表达式 0+ 0+S 0+S1 0+1 S (加号的意思是零的数量是1..inf) 通过以下步骤减少管柱000111后: stack input 000111 0 00111 00 0111

我遇到了一个来自著名的编译器设计龙书的问题。如何找到以下语法的所有可行前缀:

S -> 0S1 | 01
语法实际上是正则表达式0n1n的语言。 我假设所有可行前缀的集合也可能是正则表达式

0+
0+S
0+S1
0+1
S
(加号的意思是零的数量是1..inf)

通过以下步骤减少管柱000111后:

stack             input
                 000111
0                00111
00               0111 
000              111
0001             11
00S              11
00S1             1
0S               1
0S1              $
S                $
我的解决方案是正确的还是遗漏了什么?

0n1n
不是一种常规语言;regexen没有像
n
这样的变量,并且它们不能对两个不同的子序列执行相同数量的重复。尽管如此,对于任何上下文无关语法,可行前缀集都是一种常规语言。(以某种形式证明这一事实的证据出现在Donald Knuth 1965年的开创性论文《语言从左到右的翻译》第二部分的开头,该论文展示了对LR(k)属性的测试和在线性时间内解析LR(k)语法的算法。)

好,回到实际问题。语法的一个可行前缀(根据定义)是句子形式的前缀,它可以在使用该语法的解析过程中出现在堆栈上。它被称为“可行的”(意思是“仍然活着”或“可以继续生长”),正是因为它必须是某个正确句子形式的前缀,其后缀不包含非终结符号。换言之,存在一系列可以附加到可行前缀上的结束语,以产生正确的句子形式;可行的前缀可以增长

Knuth展示了如何创建一个生成所有可行前缀的DFA,但是如果我们已经有了由LR(k)算法生成的LR(k)解析器,那么更容易看到这个DFA。该解析器是一个有限状态机,其字母表是语法的终端和非终端符号集。为了获得可行的前缀语法,我们使用完全相同的状态机,但我们删除了堆栈(使其成为一个状态机)和reduce操作,只留下shift和goto操作作为转换。可行前缀机器中的所有状态都是接受状态,因为可行前缀的任何前缀本身就是可行前缀

这个新自动机的一个关键特性是它不能用reduce操作扩展前缀(因为我们删除了所有reduce操作)。带有reduce操作的前缀是以句柄结尾的前缀--回想一下句柄是某些产品的右手边--因此可行前缀的另一个定义是它是一种右语句形式(即派生中的一个可能步骤),它不会延伸到最右边的句柄之外

您使用的语法只有两个结果,因此只有两个句柄,
01
0S1
。注意,
10
1S
不能是任何右句子形式的子序列,右句子形式也不能包含多个
S
。任何正确的句子形式必须是句子
0n1n
或句子形式
0nS1n
其中
n>0
。但是每个句柄都在句子形式的第一个
1
处结束,因此可行前缀必须在第一个
1
处或之前结束。这正好产生您列出的四种可能性,我们可以将其压缩为正则表达式
0*0(S1?)

去掉后缀后,第二个
n
从公式中删除,因此不再需要一致性,语言是规则的


注:
像这样的问题及其答案都要求使用MathJax来呈现。不幸的是,StackOverflow没有提供这个扩展,这显然被认为是编程不必要的。然而,StackExchange星座中有一个站点专门用于计算科学问题,另一个站点专门用于数学问题。形式语言理论是计算科学和数学的一部分。这两个站点都允许MathJax,这些站点上的问题不会被关闭,因为它们不是编程问题。我建议您在回答此类问题时考虑这些信息。

谢谢您的回答,Rici和备注