[英]How to prevent stack overflow when dealing with long recursive productions in C?
给定一种语法,如何在C中计算FIRST和FOLLOW集时如何避免堆栈溢出问题。当我不得不通过长时间的生产递归时,该问题就出现在我的代码中。
例:
S->ABCD
A->aBc | epsilon
B->Bc
C->a | epsilon
D->B
那只是语法上的麻烦。 递归是这样的:
S->A
C->A
A->B
B->D
D->aBc | epsilon
FIRST(S)=FIRST(A)=FIRST(B)=FIRST(D)={a,epsilon}.
提供一个C(不是C ++)代码来计算并打印上面的语法的FIRST和FOLLOW集,请记住,您可能会遇到一个较长的语法,该语法具有特定非终结点的多个隐式的first / follow集。
例如:
FIRST(A)=FIRST(B)=FIRST(B)=FIRST(C)=FIRST(D)=FIRST(E)=FIRST(F)=FIRST(G)=FIRST(H)=FIRST(I)=FIRST(J)=FIRST(K)={k,l,epsilon}.
也就是说:要获得
FIRST(A)
您必须计算FIRST(B)
,依此类推,直到到达FIRST(K)
,其FIRST(K)
端子为'k'
,'l'
和epsilon
。 隐含的时间越长,由于多次递归而导致堆栈溢出的可能性就越大。
如何用C语言避免这种情况,但仍能获得正确的输出?
用C(不是C ++)代码解释。
char*first(int i)
{
int j,k=0,x;
char temp[500], *str;
for(j=0;grammar[i][j]!=NULL;j++)
{
if(islower(grammar[i][j][0]) || grammar[i][j][0]=='#' || grammar[i][j][0]==' ')
{
temp[k]=grammar[i][j][0];
temp[k+1]='\0';
}
else
{
if(grammar[i][j][0]==terminals[i])
{
temp[k]=' ';
temp[k+1]='\0';
}
else
{
x=hashValue(grammar[i][j][0]);
str=first(x);
strncat(temp,str,strlen(str));
}
}
k++;
}
return temp;
}
我的代码进入堆栈溢出。 我该如何避免呢?
您的程序溢出堆栈不是因为语法“太复杂”,而是因为它是左递归的。 由于您的程序不会检查是否已经通过非终端递归,因此一旦尝试计算first('B')
,它将进入无限递归,最终将填充调用堆栈。 (在示例语法中, B
不仅是左递归的,而且也没有用,因为它没有非递归的产生,这意味着它永远不会派生仅包含终端的句子。)
不过,这不是唯一的问题。 该程序还存在至少两个其他缺陷:
在将终端添加到非终端的FIRST集中之前,它不会检查给定的终端是否已添加到该FIRST集合中。 因此,在第一组中将有重复的端子。
该程序仅检查右侧的第一个符号。 但是,如果非终结符可以产生ε(换句话说,非终结符可以为null ),则还需要使用以下符号来计算FIRST集。
例如,
A → BC d B → b | ε C → c | ε
此处, 第一 ( A )为{b, c, d}
。 (并且类似地, FOLLOW ( B )是{c, d}
。)
递归对FIRST和FOLLOW集的计算没有太大帮助。 描述最简单的算法就是该算法,类似于《 龙书》中介绍的算法,该算法可以满足任何实用的语法要求:
对于每个非终端,计算它是否可为空。
使用上面的,对于每一个非末端N到该组的每个生产对于N 主导符号初始化FIRST(N)。 如果符号是右侧的第一个符号或左侧的每个符号都可以为空,则它是生产中的前导符号。 (这些集合将包含终端和非终端;现在不必担心。)
执行以下操作,直到循环期间未更改任何FIRST设置:
从所有第一组中移除所有非端子。
上面假设您有一个用于计算可空性的算法。 您也可以在《龙书》中找到该算法。 这有点相似。 另外,您应该消除无用的产品; 检测它们的算法与可空性算法非常相似。
有一种算法通常更快,但实际上并不复杂。 完成上述算法的第1步后,您就计算了Leads-with ( N , V )关系,当且仅当非端N的某些生产以端V或非端V开头时,这才成立跳过可为空的非终结符。 FIRST( N )然后是引线的传递性闭包-其范围仅限于终端。 可以使用Floyd-Warshall算法或使用Tarjan算法的一种变体(用于计算图的强连通分量)有效地计算(无递归)。 (例如,请参见Esko Nuutila的可传递性关闭页面。 )
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.