实验内容
针对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; }