LL(1)文法:從文法的開始符,向下推導,推出句子。
對文法G的句子進行確定的自頂向下語法分析的充分必要條件是,G的任意兩個具有相同左部的
產生式A—>α|β 滿足下列條件:
(1)如果α、β均不能推導出ε,則 FIRST(α) ∩ FIRST(β) = ∅。
(2)α 和 β 至多有一個能推導出 ε。
(3)如果 β *═> ε,則 FIRST(α) ∩ FOLLOW(A) = ∅。
將滿足上述條件的文法稱為LL(1)文法。
一、消除左遞歸
由於自上而下的分析方法不允許文法含有左遞歸。
因此對於包含直接左遞歸和間接左遞歸的文法都要消除左遞歸。
直接消除左遞歸比較容易。
例如:
P->Pa | b
直接消除左遞歸
P->bP'
P'->aP' | ε
二、提左因子
如果不提左因子,當面臨兩個相同的前綴,不知道選擇哪條,必然會產生回溯。為了消除回溯,我們需要提左因子。
例如
三、實驗
已知算術表達式文法 G[E]:
E → T E'
E' → + T E'|ε
T → F T'
T' → * F T'|ε
F → ( E )|i
判斷該文法是否為 LL(1)文法,計算 FIRST 集合和 FOLLOW 集合
SELECT(E→T E')= FIRST(T)= {(, i}
SELECT(E'→+ T E')= {+}
SELECT(E'→ε)= FOLLOW(E')= {), #}
SELECT(T→F T')= FIRST(F)= {(, i}
SELECT(T' →* F T')= {*}
SELECT(T'→ε)= FOLLOW(T')= {+, ), #}
SELECT(F → ( E ))= {(}
SELECT(F → i)= {i}
具有相同左部產生式的 SELECT 集合交集為空
SELECT(E'→+ T E')∩SELECT(E'→ε)= {+}∩{), #}=Φ
SELECT(T' →* F T')∩SELECT(T'→ε) = {*}∩{+, ), #}=Φ
SELECT(F → ( E ))∩SELECT(F → i) = {(}∩{i}=Φ
所以,轉換后的文法是 LL(1)文法。
此外,我們構造LL(1)分析表
表1-1 LL(1)分析表
|
i |
+ |
* |
( |
) |
# |
E |
E->TE’ |
|
|
E->TE’ |
|
|
E’ |
|
E’->+TE’ |
|
|
E’->ε |
E’->ε |
T |
T->FT’ |
|
|
T->FT’ |
|
|
T’ |
|
T’->ε |
T’->*FT’ |
|
T’->ε |
T’->ε |
F |
F->i |
|
|
F->(E) |
|
|
程序如下:
1 #include<bits/stdc++.h> 2 #define ROW 6 3 #define COLUMN 9 4 using namespace std; 5 string table[ROW][COLUMN]={ 6 {"","(",")","*","+","-","/","i","#"}, 7 {"E","Te","","","","","","Te",""}, 8 {"e","","ε","","+Te","-Te","","","ε"}, 9 {"T","Ft","","","","","","Ft",""}, 10 {"t","","ε","*Ft","ε","ε","/Ft","","ε"}, 11 {"F","(E)","","","","","","i",""}}; 12 string Get_table(string x,string a){ 13 string ans=""; 14 for(int i=0;i<ROW;i++){ 15 for(int j=0;j<COLUMN;j++){ 16 if(x==table[i][0]&&a==table[0][j]){ 17 ans=table[i][j]; 18 return ans; 19 } 20 } 21 } 22 return ans; 23 } 24 bool check_LL1(string input){ 25 bool flag=true; 26 stack < string > s; 27 s.push("#"); 28 s.push("E"); 29 int i=0; 30 string a=input.substr(i,1); 31 string x; 32 while(flag){ 33 string RS; 34 x=s.top(); 35 if(x==a && a=="#"){ 36 break; 37 }else if(x==a && a!="#"){ 38 s.pop(); 39 i++; 40 a=input.substr(i,1); 41 }else if((RS=Get_table(x,a))!=""){ 42 if(RS!="ε"){ 43 s.pop(); 44 for(int j=RS.length()-1;j>=0;j--){ 45 string tmp=RS.substr(j,1); 46 s.push(tmp); 47 } 48 }else{ 49 s.pop(); 50 } 51 }else{ 52 flag=false; 53 break; 54 } 55 } 56 return flag; 57 } 58 int main(){ 59 string input; 60 while(cin>>input){ 61 input=input+"#"; 62 if(check_LL1(input)){ 63 cout<<"correct"<<endl; 64 }else{ 65 cout<<"error"<<endl; 66 } 67 } 68 return 0; 69 }
實驗截圖: