编译原理中FIRSTVT和LASTVT的求解

485 阅读3分钟

首先来了解一波理论知识 (来自编译原理书籍)

image.png 我中我们将建立-一个布尔数组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拆空为止。

再来看看利用栈实现的伪代码

image.png 最后,上代码!

#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的运行结果:

image.png

如有错误,请指正哦