编译原理-算符优先

来源:互联网 发布:工业设计所需软件 编辑:程序博客网 时间:2024/05/18 13:47

一、实验目的

根据文法求出FirstVT和LastVT,构造算法优先表,根据输入二元组判断正确与否

二、实验内容

2.1任务一:构造FIRSTVT,LASTVT

FIRSTVT计算过程:
(1)若有产生式P->a…或者P->Qa…,则a∈FIRSTVT(P);
(2)若a∈FIRSTVT(Q),且有产生式P->Q…,则a∈FIRSTVT(P);
LASTVT计算过程:
(1)若有产生式P->…a或者P->…aQ,则a∈LASTVT(P);
(2)若a∈LASTVT(Q),且有产生式P->…Q,则a∈LASTVT(P);

2.2任务二:构造算符优先表

(1)对形如 P→…ab…和形如P→…aQb…,有a=b;
(2)对形如 P→…aR…,而b∈FIRSTVT(R),有a

2.3任务三:根据输入判断结果

(1)读入当前输入符号
(2)若输入符号为数字,则输入符号进OPND,输入指针后移,转第(1)步
(3)若当前输入符号为终结符,则比较当前字符和符号栈栈顶字符的优先级
(4)若输入符号和栈顶的优先级相同,则输入指针后移,符号栈出栈
(5)若输入符号优先级小于栈顶的优先级,则输入符号入符号栈,输入指针后移
(6)若输入符号优先级大于栈顶的优先级,则从数据栈中弹出两个数,符号栈中弹出符号进行计算,结果压入数据栈。继续判断符号栈栈顶和输入符号的优先级
(7)若输入符号为“#”且符号栈只剩一个“#”时,表示判断成功。

三、实验过程

3.1 开发环境

使用Visual Studio 2015开发win32控制台程序

3.2 数据结构设计

3.2.1 使用的宏定义

#define MAXSIZE 10
#define NUM_VT 7
#define NUM_VN 5

3.2.2 定义的结构体

//栈操作
typedef struct Stack
{
char data[MAXSIZE];
int top;
};

3.3 测试数据设计

3.3.1 文法文件“nick.txt”

S->E
E->E+T
E->T
T->T*F
T->F
F->P^F
F->P
P->(E)
P->i

3.3.2 输入文件“Input.txt”

(i,1)
(+,)
(i,2)
(*,)
(i,3)
(#,)

/**功能:算符优先*作者:王文堃*创建时间:2016/5/15*/#include <iostream>#include <malloc.h>#include <stack>using namespace std;/**任务一:构造FIRSTVT,LASTVT*任务开始时间:2016/5/15*任务结束时间:2016/5/16*//**任务二:构造算符优先表*任务开始时间:2016/5/17*任务完成时间:2016/5/17*//**任务三:根据输入判断结果*任务开始时间:2016/5/17*任务完成时间:2016/5/17*/#define MAXSIZE 10#define NUM_VT 7#define NUM_VN 5char WenFa[MAXSIZE][MAXSIZE]; //存放从文件中读取的文法int g_num_wenfa = 0; //存放文法的个数,初值为0char vt[NUM_VT] = {'+','*','^','i','(',')','#'}; //所有终结符char vn[NUM_VN] = {'E','T','F','P','S'}; //存放所有非终结符int firstvt[NUM_VN][NUM_VT]; //存放每一个非终结符的firstvtint lastvt[NUM_VN][NUM_VT]; //存放每一个非终结符的lastvtint labelofch[MAXSIZE]; //存放已ch打头的所有文法的标号char OPT[NUM_VT][NUM_VT];  //算符优先表char Input[MAXSIZE][MAXSIZE]; //保存输入int g_num_input = 0; //存放输入的个数stack <char> OPTR; //符号栈stack <char> OPND; //数据栈/*-----------------------------------------计算FIRSTVT----------------------------------------*///读取文法bool readfromfile(char* str){    FILE* fp = fopen(str, "r");    if (fp) //succeed    {        while (EOF != fscanf(fp, "%s", WenFa[g_num_wenfa]))        {            g_num_wenfa++;        }        fclose(fp);        return true;    }    else    {        printf("error to open the file\n");        return false;    }}//判断文法中字符是否为终结符int isVt(char ch){    for (int i = 0; i < NUM_VT; i++)    {        if (ch == vt[i])        {            return true;        }    }    return false;}//判断文法中字符是否为非终结符int isVn(char ch){    for (int i = 0; i < NUM_VN; i++)    {        if (ch == vn[i])        {            return true;        }    }    return false;}//找到以ch开头的文法的下标int findit(char ch){    int num = 0;    for (int i = 0; i < g_num_wenfa; i++)    {        if (WenFa[i][0] == ch)            labelofch[num++] = i;    }    return num; //返回以ch开头文法的个数}//将非终结符转换成下标int Vn2num(char ch){    switch (ch)    {    case 'E':        return 0;        break;    case 'T':        return 1;        break;    case 'F':        return 2;        break;    case 'P':        return 3;        break;    case 'S':        return 4;        break;    default:        return -1;    }}//将终结符转换成下标int Vt2num(char ch){    switch (ch)    {    case '+':        return 0;        break;    case '*':        return 1;        break;    case '^':        return 2;        break;    case 'i':        return 3;        break;    case '(':        return 4;        break;    case ')':        return 5;        break;    case '#':        return 6;        break;    default:        return -1;    }}//求FIRSTVT(ch)void get_firstvt(char ch){    if (isVn(ch)) //对终非结符ch    {        int firstnum = Vn2num(ch); //ch所对应的编号        int num = findit(ch); //找到以该非终结符开头文法的下标        for (int i = 0; i < num; i++)        {            char rightfirst = WenFa[labelofch[i]][3]; //取出文法推到的第一个字符            if (isVt(rightfirst)) //该文法推出的第一个字符是终结符            {                firstvt[firstnum][Vt2num(rightfirst)] = 1;            }            else //该文法推出的第一个字符是非终结符            {                char rightsc = WenFa[labelofch[i]][4];                if (isVt(rightsc)) //判断该非终结符之后的符号是不是终结符                {                    firstvt[firstnum][Vt2num(rightsc)] = 1;                }                if (ch != rightfirst)                {                    get_firstvt(rightfirst); //计算这个非终结符的firstvt集                    int newvn = Vn2num(rightfirst);                    for (int j = 0; j < NUM_VT; j++)                    {                        if (firstvt[newvn][j] == 1)                        {                            firstvt[firstnum][j] = 1;                        }                    }                }            }        }    }}//计算所有firstvtvoid do_firstvt(){    for (int i = 0; i < NUM_VN; i++)    {        get_firstvt(vn[i]);    }}//输出firstvt表void output_firstvt(){    int i = 0;    printf("---------------firstvt----------------\n");    printf(" ");    for (i = 0; i < NUM_VT; i++)    {        printf("%5c", vt[i]);    }    printf("\n");    for (i = 0; i < NUM_VN; i++)    {        printf("%c", vn[i]);        for (int j = 0; j < NUM_VT; j++)        {            printf("%5d", firstvt[i][j]);        }        printf("\n");    }    printf("--------------------------------------\n");    printf("\n");}/*-----------------------------------------计算LASTVT----------------------------------------*///找到下标为num的文法的最后一个字符的下标int get_last(int num){    for (int i = 0; i < MAXSIZE; i++)    {        if (WenFa[num][i] == '\0')        {            return (i-1);         }    }}//求LASTVT(ch)void get_lastvt(char ch){    if (isVn(ch)) //对终非结符ch    {        int lastnum = Vn2num(ch); //ch所对应的编号        int num = findit(ch); //找到以该非终结符开头文法的下标        for (int i = 0; i < num; i++)        {            int ilast = get_last(labelofch[i]);            char rightlast = WenFa[labelofch[i]][ilast]; //获得文法的最后一个字符            if (isVt(rightlast)) //该文法推出的最后一个字符是终结符            {                lastvt[lastnum][Vt2num(rightlast)] = 1;            }            else //该文法推出的最后一个字符是非终结符            {                char rightlastsc = WenFa[labelofch[i]][ilast -1]; //文法倒数第二个字符                if (isVt(rightlastsc)) //判断倒数第二个字符是不是终结符                {                    lastvt[lastnum][Vt2num(rightlastsc)] = 1;                }                if (ch != rightlast)                {                    get_lastvt(rightlast); //计算这个非终结符的lastvt集                    int newvn = Vn2num(rightlast);                    for (int j = 0; j < NUM_VT; j++)                    {                        if (lastvt[newvn][j] == 1)                        {                            lastvt[lastnum][j] = 1;                        }                    }                }            }        }    }}//计算所有lastvtvoid do_lastvt(){    for (int i = 0; i < NUM_VN; i++)    {        get_lastvt(vn[i]);    }}//输出lastvt表void output_lastvt(){    int i = 0;    printf("----------------lastvt----------------\n");    printf(" ");    for (i = 0; i < NUM_VT; i++)    {        printf("%5c", vt[i]);    }    printf("\n");    for (i = 0; i < NUM_VN; i++)    {        printf("%c", vn[i]);        for (int j = 0; j < NUM_VT; j++)        {            printf("%5d", lastvt[i][j]);        }        printf("\n");    }    printf("--------------------------------------\n");    printf("\n");}/*----------------------------------------构造算符优先表---------------------------------------*///处理小于的情况,a<FIRSTVT(R)void do_less(char vtch1, char vnch2){    int x = Vt2num(vtch1); //a    int i = Vn2num(vnch2); //firstvt表中的行    for (int j = 0; j < NUM_VT; j++) //遍历firstvt表    {        if (firstvt[i][j] == 1)            OPT[x][j] = '<';    }}//处理大于的情况,LASTVT(R)>avoid do_more(char vnch1, char vtch2){    int y = Vt2num(vtch2);    int i = Vn2num(vnch1);    for (int j = 0; j < NUM_VT; j++) //遍历LASTVT表    {        if (lastvt[i][j] == 1)        {            OPT[j][y] = '>';        }    }}//处理#号void dosharp(){    //添加“#=#”    int temp = Vt2num('#');    OPT[temp][temp] = '=';    //添加'#'<FIRSTVT(S)、LASTVT(S)>'#'    for (int i = 0; i < NUM_VT; i++)    {        int x = Vn2num('S');        int j = Vt2num('#');        if (firstvt[x][i] == 1)        {            OPT[j][i] = '<';        }        if (lastvt[x][i] == 1)        {            OPT[i][j] = '>';        }    }}//构造算法优先表void OperatorPrecedence(){    int i = 0; //循环变量    for (i = 0; i < g_num_wenfa; i++) //对所有的文法    {        int j = 3; //内部循环变量,从推出来的第一个字符开始        while (WenFa[i][j] != '\0') //该文法没有完        {            char ch = WenFa[i][j];            if (isVt(ch)) //判断当前字符是不是终结符            {                //判断下一个字符是不是终结符                if (isVt(WenFa[i][j + 1]))                {                    //若是,则这两个终结符的优先级相等                    OPT[Vt2num(ch)][Vt2num(WenFa[i][j + 1])] = '=';                }                else                {                    //做小于                    do_less(ch, WenFa[i][j + 1]);                    //继续判断下一个字符是不是终结符                    if (isVt(WenFa[i][j + 2]))                    {                        //若是,则这两个终结符的优先级依然相等                        OPT[Vt2num(ch)][Vt2num(WenFa[i][j + 2])] = '=';                    }                }            }            else //当前是非终结符            {                if (isVt(WenFa[i][j + 1])) //判断下一个字符                {                    //大于                    do_more(ch, WenFa[i][j + 1]);                }            }            j++;        }    }    dosharp(); //处理#}//输出算符优先表void output_OPT(){    int i = 0;    printf("------------------OPT-----------------\n");    printf(" ");    for (i = 0; i < NUM_VT; i++)    {        printf("%5c", vt[i]);    }    printf("\n");    for (i = 0; i < NUM_VT; i++)    {        printf("%c", vt[i]);        for (int j = 0; j < NUM_VT; j++)        {            printf("%5c", OPT[i][j]);        }        printf("\n");    }    printf("--------------------------------------\n");    printf("\n");}/*---------------------------------------处理输入判断结果---------------------------------------*///从文件中读取输入bool inputformfile(char* str){    FILE* fp = fopen(str, "r");    if (fp) //succeed    {        while (EOF != fscanf(fp, "%s", Input[g_num_input]))        {            g_num_input++;        }        fclose(fp);        return true;    }    else    {        printf("error to open the file\n");        return false;    }}//判断输入字符的类型int judge(char ch){    switch (ch)    {    case 'i':        return 0; //表示数字        break;    case '+':        return 1; //表示'+'号        break;    case '*':        return 2; //表示'*'号        break;    default:        return -1;    }}//将int行数字传化成char型int char2int(char ch){    if (ch >= 48 && ch <= 57) //数字    {        return ch - 48;    }}//处理输入bool doinput(){    int iInput = 0; //指向输入下标    //#入符号栈    OPTR.push('#');    while (iInput != (g_num_input-1)  || OPTR.size() != 0) //将输入遍历完    {        char* str = Input[iInput]; //取出第一个输入        int result = judge(str[1]);        if (result == 0) //数字        {            OPND.push(str[3]);        }        else //是符号        {            //判断符号栈顶的符号和当前符号的优先级            int topofstack = Vt2num(OPTR.top());            int topofinput = Vt2num(str[1]);            if (OPT[topofstack][topofinput] == '<') //栈顶小于输入就入栈            {                OPTR.push(str[1]);            }            else if (OPT[topofstack][topofinput] == '>')//否则运算            {                int i = char2int(OPND.top());                OPND.pop();                int j = char2int(OPND.top());                OPND.pop();                int vtnum = Vt2num(OPTR.top());                if (vtnum == 0) //+                {                    OPND.push(i + j);                    OPTR.pop();                }                else if (vtnum == 1) //*                {                    OPND.push(i*j);                    OPTR.pop();                }            }            else //如果相等就出栈            {                OPTR.pop();            }        }        if (iInput != (g_num_input-1))        {            iInput++;        }    }    //判断    if (OPTR.size() == 0)    {        return true;    }    else    {        return false;    }}int main(){    if (readfromfile("nick.txt"))    {        do_firstvt();  //构造firstvt        output_firstvt(); //输出firstvt        do_lastvt();  //构造lastvt        output_lastvt(); //输出lastvt        OperatorPrecedence(); //构造算符优先表        output_OPT(); //输出算符优先表        //---        inputformfile("input.txt");        bool result = doinput();        if (result != 0)        {            printf("最终结果正确\n");        }        else        {            printf("最终结果错误\n");        }    }    getchar();    return 0;}

最终的运算结果是:
这里写图片描述

1 0
原创粉丝点击