首先来了解一波理论知识 (来自编译原理书籍)
我中我们将建立-一个布尔数组F[P,a],使得F[P,a]为真的条件是,当且仅当a∈FIRSTVT(P)。
开始时,按上述的规则(1)对每个数组元素F[P,a]赋初值。我们用一个栈STACK,把所有初值为真的数组元素F[P,a]的符号对(P,a)全都放在STACK之中。
然后,对栈STACK施行如下运算:
如果栈STACK不空,就将顶项逐出,记此项为(Q,a)。对于每个形如 P->Q... 的产生式,若F[P.a]为假,则变其值为重且将(P,a)推进STACK栈。
上述过程必须一直重复,直至栈STACK拆空为止。
再来看看利用栈实现的伪代码
最后,上代码!
#include <bits/stdc++.h>
using namespace std;
const int Max = 40;
int num; //文法规则数
char str[Max][Max];//文法规则
bool F[Max][Max] = {0};//FIRSTVT的布尔数组
bool L[Max][Max] = {0};//LASTVT的布尔数组
char terminal[Max];//终结符数组
int k = 0;//记录终结符的数量
char notTerminal[Max];//非终结符数组
typedef struct real_f //布尔数组里面的元素
{
/* data */
char NT; //对应的非终结符
char T; //对应的终结符
}real_f;
stack<real_f *> stack1;//栈
//判断字符是否是终结符
bool isTer(char ch){
for(int i = 0;terminal[i] != '\0';i ++){
if(terminal[i] == ch){
return true; //是终结符就返回true
}
}
return false;
}
//计算终结符在终结符数组中的位置,方便入栈及后面表的列出
int findTer(char ch){
for(int i = 0;terminal[i] != '\0';i ++){
if(terminal[i] == ch){
return i;//返回这个终结符的位置
}
}
return -1;//如果未找到就返回-1,一般是能够找到的
}
//入栈操作
void inStack(int ntsite,int tsite,char flag){
if(flag == 'f'){
if(!F[ntsite][tsite]){
F[ntsite][tsite] = 1;//置1
real_f *node = (real_f*)malloc(sizeof(real_f));
node->NT = notTerminal[ntsite];
node->T = terminal[tsite];
stack1.push(node);//压入栈中
}
}
else if(flag == 'l'){
if(!L[ntsite][tsite]){
L[ntsite][tsite] = 1;
real_f *node = (real_f*)malloc(sizeof(real_f));
node->NT = notTerminal[ntsite];
node->T = terminal[tsite];
stack1.push(node);
}
}
}
//计算FIRSTVT
void calFITSRVT(){
//按照规则(1)对每个布尔数组元素赋初值为1,并入栈
for(int i = 0;i < num;i ++){
for(int j = 0; str[i][j] != '\0';j ++){
if(j == 2 || str[i][j] == '|'){
if(isTer(str[i][j + 1])){ //产生式为P->a...
inStack(i,findTer(str[i][j + 1]),'f');
}
else if(isTer(str[i][j + 2])){ //产生式为P->Qa...
inStack(i,findTer(str[i][j + 2]),'f');
}
}
}
}
//随后开始对栈进行操作
while (!stack1.empty())
{
real_f *topnode = stack1.top();
//cout<<topnode->NT<<" "<<topnode->T<<endl;
stack1.pop();
for(int i = 0;i < num;i ++){
for(int j = 0;str[i][j] != '\0';j ++){
//cout<<"正在遍历的文法为:"<<str[i]<<endl;
if(j == 2 || str[i][j] == '|'){
if(topnode->NT == str[i][j + 1]){ //产生式为P->Q...
//cout<<"匹配的P->Q...形式的文法为:"<<str[i]<<endl;
inStack(i,findTer(topnode->T),'f');
}
}
}
}
}
cout<<"FIRSTVT布尔数组元素的值为:"<<endl;
cout<<" ";
for(int i = 0;i < k;i ++){
cout<<" "<<terminal[i];
}
cout<<endl;
for(int i = 0;i < num;i ++){
cout<<notTerminal[i]<<" ";
for(int j = 0;j < k;j ++){
cout<<F[i][j]<<" ";
}
cout<<endl;
}
cout<<"每个非终结符的FIRSTVT集为:"<<endl;
int last = k - 1;
for(int i = 0;i < num;i ++){
last = k - 1;
cout<<"FIRSTVT("<<str[i][0]<<")={";
//找到最后一个对应的终结符
while (F[i][last] == 0)
{
last --;
}
for(int j = 0;j < k;j ++){
if(F[i][j] == 1){
if(j == last){
cout<<terminal[j]<<"}";
break;
}
cout<<terminal[j]<<"、";
}
}
cout<<endl;
}
}
//计算LASTVT
void calLASTVT(){
//按照规则(1)对每个布尔数组元素赋初值为1,并入栈
for(int i = 0;i < num;i ++){
//首先得知道这个文法的长度,然后从后面开始寻找
int len = strlen(str[i]);
for(int j = len;str[i][j] != '>';j --){
if(j == len || str[i][j] == '|'){
if(isTer(str[i][j - 1])){//产生式为P->...a
inStack(i,findTer(str[i][j - 1]),'l');
}
else if(isTer(str[i][j - 2])){//产生式为P->...aQ
inStack(i,findTer(str[i][j - 2]),'l');
}
}
}
}
//随后开始对栈进行操作
while (!stack1.empty())
{
real_f *topnode = stack1.top();
//cout<<topnode->NT<<" "<<topnode->T<<endl;
stack1.pop();
for(int i = 0;i < num;i ++){
int len = strlen(str[i]);
for(int j = len;str[i][j] != '>';j --){
if(j == len || str[i][j] == '|'){
if(topnode->NT == str[i][j - 1]){
inStack(i,findTer(topnode->T),'l');
}
}
}
}
}
cout<<"LASTVT布尔数组元素的值为:"<<endl;
cout<<" ";
for(int i = 0;i < k;i ++){
cout<<" "<<terminal[i];
}
cout<<endl;
for(int i = 0;i < num;i ++){
cout<<notTerminal[i]<<" ";
for(int j = 0;j < k;j ++){
cout<<L[i][j]<<" ";
}
cout<<endl;
}
cout<<"每个非终结符的LASTVT集为:"<<endl;
int last = k - 1;
for(int i = 0;i < num;i ++){
last = k - 1;
cout<<"LASTVT("<<str[i][0]<<")={";
//找到最后一个对应的终结符
while (!L[i][last])
{
last --;
}
for(int j = 0;j < k;j ++){
if(L[i][j] == 1){
if(j == last){
cout<<terminal[j]<<"}";
break;
}
cout<<terminal[j]<<"、";
}
}
cout<<endl;
}
}
int main(){
cout<<"请输入文法规则的数量:";
cin>>num;
cout<<"请输入文法规则:"<<endl;
for(int i = 0;i < num;i ++){
cin>>str[i];
notTerminal[i] = str[i][0];//第一个符号肯定是非终结符,提取出来
}
//提取终结符
for(int i = 0;i < num;i ++){
for(int j = 0;str[i][j] != '\0';j ++){
if((str[i][j] < 'A' || str[i][j] > 'Z') && str[i][j] != '-' && str[i][j] != '>' && str[i][j] != '|'){
terminal[k ++] = str[i][j];
}
}
}
cout<<"此文法规则中的终结符有:";
for(int i = 0;i < k;i ++){
cout<<terminal[i]<<" ";
}
cout<<endl;
cout<<"此文法规则中的非终结符有:";
for(int i = 0;i < num;i ++){
cout<<notTerminal[i]<<" ";
}
cout<<endl;
calFITSRVT();
calLASTVT();
return 0;
}
/*
示例1:
S->a|^|(T)
T->T,S|S
示例2:
S->aAcBe
A->Ab|b
B->d
*/
示例1的运行结果:
如有错误,请指正哦