前言:
写算法的时候,也搜索了不少大佬的笔记,感觉有些复杂,不太容易看懂。但还是借鉴了不少思想,再结合自己的所学,成功运行。本次设计的存储结构简单易懂,且适合新手,目前实现了FirstVt集,LastVt以及算符优先分析表的构造,主要还是利用从各自的构造思想入手。
算符优先分析法是一种自底向上的语法分析方法。在算符文法中,任何一个规则右部都不存在两个非终结符相邻的情况。通过比较两个相继出现的终结符a,b的优先级,然后借助优先级关系,来确定句型的可归约串并进行归约。通过构造FIRSTVT集和LASTVT集来构造算符优先分析表,从表中可以看出各终结符的优先关系。
主要概念:
FirstVt集如何构造:
若P→a…或P→Qa…, 则a属于FIRSTVT(P)
若P→Q…, 则FIRSTVT(Q)加到FIRSTVT(P)
直至FIRSTVT(P)不再增大。
LastVt构造:
若P→...a或P→…aQ, 则a属于LASTVT(P);
若P→...Q, 则LASTVT(Q)含于LASTVT(P);
直至LASTVT(P)不再增大。
算符优先分析表构造:
1) ‘=’关系
-若出现了A →…ab…或A →…aBb, 则a=b;
2)‘<’关系
-求出每个非终结符B的FIRSTVT(B),
-若A→…aB…,则 任意b∈FIRSTVT(B),a<b;
3)‘>’关系
-求出每个非终结符B的LASTVT(B),
-若A→…Bb…,则 任意a∈LASTVT(B),a>b
存储结构设计 :
#include<iostream>
#include<vector>
using namespace std;
#include<string.h>
struct inf{
char ter;//首非终结符
bool e;//是否产生空字符
string nonter;
};
vector <inf> v;//产生式集合
char a[10];
string T="";//非终结符集合
string Vt="";//终结符集合
string firstvt[20];
string lastvt[20];
char table[50][50];//算符优先关系表
源代码:
(涉及到将文法转化为产生式。即将 E->aB|c 变为 E->aB E->c)
//选择20、填空20、判断10、程序阅读25、设计题25 数据可视化 nowpy应用于机器学习 文件操作 pandas
#include<iostream>
#include<vector>
using namespace std;
#include<string.h>
struct inf{
char ter;//首非终结符
bool e;//是否产生空字符
string nonter;
};
vector <inf> v;//产生式集合
char a[10];
string T="";//非终结符集合
string Vt="";//终结符集合
string firstvt[20];
string lastvt[20];
char table[50][50];//算符优先关系表
void add();
//将文法转为产生式
string produce(string str){
inf infi;
infi.ter = str[0];
infi.e=false;
int i = 3;
for(int k=i;k<str.length();k++){
if(str[k]=='|'){
infi.nonter.append(str.substr(i,k-i));
i=str.length();
if(str[i]!=' '&&str[i]!='@'){
inf ind;
ind.ter=str[0];
ind.e=false;
ind.nonter.append(str.substr(k+1,str.length()-1));
v.push_back(ind);
}
}
else if(str[k]=='@'){
infi.e=true;
i= k+2;
k++;
}
}
if(i < str.length()){ //处理形如 E-》TB
infi.nonter.append(str.substr(i));
}
for(int k=3;k<str.length();k++){
if((str[k]>='!'&&str[k]<='/'&&str[k]!='|')||(str[k]>='a'&&str[k]<='z')){
Vt+=str[k];
}
}
v.push_back(infi);
T=T+str[0];
return infi.nonter;
}
//求firstvt集
void add_firstvt(int p,char ch){//对每一行产生式求
for(int i=0;i<v.size();i++){
inf e= v[i];
if(ch==e.ter){
char str=e.nonter[0];
int lo = e.nonter.find(str);
char str2;
//A->a...,则a属于 firstvt(A)
if((str >= 'a'&&str <= 'z')||(str>='('&&str<='+')){
firstvt[p] += str;
}
//A->Qa... ,则a属于 firstvt(A)
if(lo+1<=e.nonter.length()-1){
str2=e.nonter[1];
if(str>='A'&&str<='Z'){
if((str2 >= 'a'&&str <= 'z')||(str2>='!'&&str2<='/'))
firstvt[p] += str2;
}
}
//A->B...,则firstvt(A)+=firstvt(B)
else if((str >= 'A'&&str <= 'Z')&&str!=e.ter&&str!=e.ter){
int j = T.find(str);
add_firstvt(j,str);
firstvt[p].append(firstvt[j].substr(0));
firstvt[j]="";
}
}
}
}
求last集
void add_lastvt(int p,char a){
for(int i=0;i<v.size();i++){
inf e= v[i];
if(a==e.ter){
char str=e.nonter[e.nonter.length()-1];
int lo = e.nonter.find(str);
char str2;
//A->...a,则a属于 lastvt(A)
if((str >= 'a'&&str <= 'z')||(str>='('&&str<='+')){
lastvt[p] += str;
}
//A->...aQ ,则a属于 lastvt(A)
if(lo!=0){
str2=e.nonter[e.nonter.length()-2];
if(str>='A'&&str<='Z'){
if((str2 >= 'a'&&str <= 'z')||(str2>='!'&&str2<='/'))
lastvt[p] += str2;
}
}
//A->...B,则lastvt(A)+=lastvt(B)
else if((str >= 'A'&&str <= 'Z')&&str!=e.ter&&str!=e.ter){
int j = T.find(str);
add_lastvt(j,str);
lastvt[p].append(lastvt[j].substr(0));
lastvt[j]="";
}
}
}
}
//将空转符去掉,添加新的产生式
void add(){
int vsize=v.size();
for(int i=0;i<vsize;i++){
if(v[i].e){
for(int j=0;j<vsize;j++){
int n=v[j].nonter.find(v[i].ter);
if(n>=0){ //找到
inf ind;
string str=v[j].nonter;
ind.e=false;
ind.ter=v[j].ter;
ind.nonter.append(str.substr(0,n));
v.push_back(ind);
continue;
}
}
}
}
}
void print(){
for(int i=0;i<v.size();i++){
inf infd=v[i];
for(int j=0;j<infd.nonter.size();j++){
cout<<infd.ter<<"->"<<infd.nonter<<"\t";
break;
}
}
cout<<endl;
for(int j=0;j<T.length();j++){
add_firstvt(j,T[j]);
}
for(int j2=0;j2<T.length();j2++){
add_lastvt(j2,T[j2]);
}
}
void printTable(){
cout<<"\t";
table[5][5]='=';
for(int i=0;i<Vt.length();i++){
cout<<Vt[i]<<"\t";
}
cout<<endl;
for(int i=0;i<Vt.length();i++){
cout<<Vt[i];
for(int j=0;j<Vt.length();j++){
cout<<"\t"<<table[i][j];
}
cout<<endl;
}
}
int FindSub(char c){
for (int i = 0; i < Vt.length(); i++) {
if (Vt[i] == c) {
return i;
}
}
return -1;//#的下标
}
bool IsVt(char c) {//判断该字符是否为终结符
for (int i = 0; i < Vt.length(); i++) {
if (c == Vt[i]) {
return true;
}
}
return false;
}
void CreateTable() {//构建算符优先分析表
inf id;
id.ter='E';
id.e=false;
id.nonter="#E#";
v.push_back(id);
for (int i = 0; i < v.size(); i++) {//遍历每条产生式
inf ind = v[i];
for (int j = 0; j < ind.nonter.length(); j++) {//遍历每条产生式中符号
int len = ind.nonter.length();
if (IsVt(ind.nonter[0])) {//Xi和Xi+1都是终结符P->...ab...
int x,y;
if(len>=2){
if(IsVt(ind.nonter[1])){
x = FindSub(ind.nonter[0]);
y = FindSub(ind.nonter[1]);
cout<<x<<y;
table[x][y] = '=';
}
else if(len>=3&&ind.nonter[1]>='A'&&ind.nonter[1]<='Z'&&IsVt(ind.nonter[2])){ //aQb
x = FindSub(ind.nonter[0]);
y = FindSub(ind.nonter[2]);
table[x][y] = '=';
}
}
}//'='结束
//若A→…aB…,则 任意b∈FIRSTVT(B),a<b;
if(len>=2){
if(IsVt(ind.nonter[j])){
int x=FindSub(ind.nonter[j]);
if(ind.nonter[j+1]>='A'&&ind.nonter[j+1]<='Z'){
int lod = T.find(ind.nonter[j+1]);
for (int m = 0; m < firstvt[lod].length(); m++) {
int y = FindSub(firstvt[lod][m]);
table[x][y] = '<';
}
}
}
}//'<'结束
// 若A→…Bb…,则 任意a∈LASTVT(B),a>b
if(ind.nonter[j]>='A'&&ind.nonter[j]<='Z'){
if(j+1<=ind.nonter.length()-1){
if(IsVt(ind.nonter[j+1])){
int x=FindSub(ind.nonter[j+1]);
int lod = T.find(ind.nonter[j]);
for (int m = 0; m < lastvt[lod].length(); m++) {
int y = FindSub(lastvt[lod][m]);
table[y][x] = '>';//竖着看
}
}
}
}
}
}
}
int main(){
string BefSource[3]={{"E->E+T|T"},{"T->T*F|F"},{"F->(E)|i"}};
for(int i=0;i<3;i++) {
cout<<BefSource[i]<<endl;
BefSource[i]=produce(BefSource[i]);
}
cout<<"--------"<<endl;
add();
print();
cout<<"--------"<<endl;
cout<<"FirstVT集:"<<endl;
for(int len = 0;len < T.length();len++){
cout<<T[len]<<": "<<firstvt[len]<<" "<<endl;
}
cout<<"--------"<<endl;
string foll[20];
cout<<"LastVT集:"<<endl;
for(int len = 0;len < T.length();len++){
for(int j=0;j<lastvt[len].length();j++){
if(foll[len].find(lastvt[len][j])==-1)
foll[len]+=lastvt[len][j];
}
cout<<T[len]<<": "<<foll[len]<<" "<<endl;
}
Vt+='#';
cout<<"算符优先关系表:"<<endl;
CreateTable();
printTable();
}