[英]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.