这不是一个与学校有关的问题,但它出现在龙书(作者:原则、技术和工具):
语法:
S::=阿萨|AA
生成所有偶数长度的字符串,除了空字符串。
a)为这个文法构造一个具有回溯的递归下降解析器,它在aa之前尝试替代阿萨。证明S的过程在2、4或8 a时成功,但在6 a时失败。B)您的解析器识别哪种语言?
我被难倒了看起来如果4个a被识别为S,并且在一个S之间的两个a被识别,那么6个a应该被识别。我试着用C实现解析器,但这个解析器也能识别所有偶数的a。不是不能识别6个A。这个练习的目的是什么?
/* A C implementation of Exercise 4.13 in the Dragon Book */
/* The grammar:
S ::= aSa | aa
*/
/* Construct a recursive-descent parser with backtracking for this grammar
that tries the alternative aSa before aa. Show that the procedure for S
succeeds on 2, 4, or 8 a's, but fails on 6 a's.
*/
#include <string.h>
#include <stdio.h>
int S(const char *str, int start, int end);
int aSa(const char *str, int start, int end);
int aa(const char *str, int start, int end);
/* returns 1 if a match, 0 otherwise */
int S(const char *str, int start, int end)
{
if(aSa(str, start, end))
return 1;
else
if(aa(str, start, end))
return 1;
return 0;
}
/* returns 1 if a match, 0 otherwise */
int aSa(const char *str, int start, int end)
{
int len = end - start;
if (len < 3)
return 0;
if(str[0] != 'a')
return 0;
if (!S(str, start+1, end-1))
return 0;
if(str[len-1] != 'a')
return 0;
return 1;
}
/* returns 1 if a match, 0 otherwise */
int aa(const char *str, int start, int end)
{
int len = end - start;
if(len != 2)
return 0;
if(str[0] == str[1] && str[0] == 'a')
return 1;
return 0;
}
int main()
{
char str[20];
printf("Enter a string: \n");
scanf("%s", str);
int match = S(str, 0, strlen(str));
if(match)
printf("The string %s matches\n", str);
else
printf("The string %s does not match\n", str);
return 0;
}
4条答案
按热度按时间d5vmydt91#
问题不在于这是一个回溯或递归下降解析器;问题在于所描述的实现没有适当地考虑递归下降解析的外部上下文。这类似于强LL(SLL)解析器和LL解析器之间的区别。
出现奇怪行为的最短输入是
aaaaaa
。1.我们从规则
S
开始,匹配第一个a
。S
。a
。S
。我将省略具体的步骤,但关键是S
的 this 调用匹配aaaa
,这是输入末尾的第3个a
。(见以下注解。)a
,但由于已经到达输入的末尾,我们返回并匹配 * 仅 * 第二个到第三个aa
。a
。关于匹配
aaaa
的S
的内部调用的附加说明:如果我们 * 知道 * 在第3步的输入末尾保留一个a
,那么对S
的内部调用可能会匹配aa
而不是aaaa
,从而成功解析完整的输入aaaaaa
。ANTLR 4在递归下降解析器中提供了这种“全上下文”解析能力,并且是第一个能够正确匹配S
而不是aaaa
的递归下降LL解析器。SLL解析器为该语法匹配a2 k。一个合适的LL解析器(比如ANTLR 4)会为这个语法匹配a2 k。
qncylg1j2#
即使使用回溯,这需要能够倒回输入流,递归下降解析器也不允许向前查看输入的结尾,也不允许从流的两端删除符号。
从左到右的解析器必须能够处理只有一个方法的输入流:
回溯版本需要一个带有两个以上方法的流:
yyhrrdl83#
我不可能为了好玩而用c来写这个,但是这里有一个用python写的解析器,尽我所能的简单(我希望它像伪代码一样清晰,即使你不懂这种语言):
结果为
length: (parsed, remaining)
:我想这能帮你理解简短的回答是递归下降是一个非常具体的、有限的东西。这不是一个完整的搜索。
(it这是个好问题这一点很重要好书。)
mv1qrgav4#
[aa]
的分析过程
[a1]
的分析过程
[aaaa]
的分析过程
[aaaaaaaa]
的分析程序
递归下降分析器仅在发生错误时才进行回溯。它忽略了成功是“暂时”的情况。