實驗內容
針對CP語言中簡單算術表達式文法G[E]:
E→TE’
E’→ATE’|ε
T→FT’
T’→MFT’|ε
F→(E) | i
A→+ | -
M→* | /
求解相應的FIRST、FOLLOW集,構造預測分析表,並編寫LL(1)語法分析程序,並給出測試句子的分析過程。
實驗要求
(1)輸入:是詞法分析輸出的二元組序列,即任意簡單算術表達式經過專題1程序輸出后得到的結果。
(2)處理:基於分析表進行 LL(1)語法分析,判斷其是否符合文法。
(3)輸出:串是否合法。
設計思路
先根據題意求解FIRST集、FOLLOW集和SELECT集,構造預測分析表(構造過程見下圖),並用string類型的二維數組存儲。
將上上篇詞法分析器的二元組輸出作為輸入讀入到二維字符數組中,再將每個二元組中的單詞提取出來存入string數組中(若這里的單詞為標識符,則將其替換為“i”),數組尾部加入輸入結束符“$”。構造一個空棧,將“$”和“E”壓入棧中,用變量p指向輸入的單詞,當棧頂元素不為“$”時,取出棧頂元素X,重復進行如下操作:
(1)若X和p指向的單詞相同,彈出X,p指向下一個單詞。
(2)否則,若預測分析表中X和p指向單詞對應的位置非空,則彈出X,將相應的產生式右部倒序壓入棧中。
(3)否則,記錄錯誤,並嘗試跳過當前字符繼續向下分析。
執行完后,若沒有錯誤的標記,則輸入串合法,否則不合法。
程序結構
(1)主要數據結構:
二維字符數組:用於接受輸入的二元組。
一維string數組:用於存儲提取出的單詞。
二維string數組:用於存儲預測分析表。
棧:用於中間過程分析。
(2)函數定義:
string M(string X,string a):返回分析表中X和a對應的產生式。
void travel_st(stack<string> str):遍歷當前棧中的元素。
int main():主程序。
(3)算法流程:
實驗代碼
#include<bits/stdc++.h> using namespace std; char ch[100][20]; string a[100]; int p=0; string travel=""; int flag=0; string fenxibiao[8][9]={" ","i","+","-","*","/","(",")","$", "E","E->TE'"," "," "," "," ","E->TE'"," "," ", "E'"," ","E'->ATE'","E'->ATE'"," "," "," ","E'->#","E'->#", "T","T->FT'"," "," "," "," ","T->FT'"," "," ", "T'"," ","T'->#","T'->#","T'->MFT'","T'->MFT'"," ","T'->#","T'->#", "F","F->i"," "," "," "," ","F->(E)"," "," ", "A"," ","A->+","A->-"," "," "," "," "," ", "M"," "," "," ","M->*","M->/"," "," "," "}; string M(string X,string a) { int i,j; for(i=0;i<8;i++) { if(X==fenxibiao[i][0]) break; } for(j=0;j<9;j++) { if(a==fenxibiao[0][j]) break; } if(i>=8||j>=9) return " "; return fenxibiao[i][j]; } void travel_st(stack<string> str)//遍歷棧 { travel=""; while(!str.empty()) { travel+=str.top(); str.pop(); } } int main() { FILE *fp; fp=fopen("result2.txt","r"); if(fp==NULL) { cout<<"Open Error"; exit(1); } int len=0; while(fscanf(fp,"%s",ch[len])!=EOF) len++; fclose(fp); for(int i=0;i<len;i++)//輸入轉換 { string temp=""; int j=1; for(;ch[i][j]!=',';j++) { temp+=ch[i][j]; } a[i]=temp; string code=""; for(j++;ch[i][j]!='>';j++) { code+=ch[i][j]; } if(code=="28") a[i]="i"; } a[len]="$"; stack<string> st; st.push("$");st.push("E"); string zhan="",shuru="",shuchu=""; cout<<setiosflags(ios::right) //設置右對齊輸出,空格在前 <<setw(20)<<"棧"<<setw(20)<<"輸入"<<setw(20)<<"輸出"<<endl; for(int i=p;i<=len;i++) { shuru+=a[i]; } cout<<setiosflags(ios::right) //設置右對齊輸出,空格在前 <<setw(20)<<"E$"<<setw(20)<<shuru<<setw(20)<<" "<<endl; string X=st.top(); while(X!="$") { zhan="",shuru="",shuchu=""; if(X==a[p])//將X彈出 { st.pop(); p++; } else if(M(X,a[p])!=" ") { st.pop(); string temp=M(X,a[p]); int l=temp.length(); if(temp[l-1]!='#') { for(int i=l-1;temp[i]!='>';i--) { string temp1=""; if(temp[i]=='\'') { temp1+=temp[i-1]; temp1+=temp[i]; i--; } else { temp1+=temp[i]; } st.push(temp1); } } shuchu=temp; } else { shuchu="錯誤,跳過"; if(a[p].length()>1) { string::iterator it=a[p].begin(); a[p].erase(it); } else p++; flag=1; } travel_st(st); zhan=travel; shuru=""; for(int i=p;i<=len;i++) { shuru+=a[i]; } cout<<setiosflags(ios::right) <<setw(20)<<zhan<<setw(20)<<shuru<<setw(20)<<shuchu<<endl; X=st.top(); } if(flag==0) cout<<"句子合法"<<endl; else cout<<"句子不合法"<<endl; return 0; }