PL0编译语义分析 递归

来源:互联网 发布:远洋数据推销什么 编辑:程序博客网 时间:2024/06/11 02:52

云南大学编译技术实验报告

一、实验目的
1. 进一步理解递归下降分析原理和实现方法;
2. 理解语法、语义分析程序为中心的单遍编译程序组织方法;
3. 理解语义分析的基本机制;
4. 掌握语义子程序的构造方法;
5. 理解编译程序的基本逻辑过程(词法分析、语法分析、语义分析及目标代码的生成;
6. 理解编译过程中的符号表的基本管理方法;

二、实验内容
文法G[E]如下:
E→E+T | E-T |T
T→T*F | T/F | F
F→( E )
F→ id
注 id 为字母打头后面是数字或者字母的串;
在starter files基础上
1. 实现增加乘法 * 和除法 / 运算,并且,/优先级别高于+;其次,和/满足左结合规则;
2. 对包含乘除法运算的表达式生成对应的四元式;
3. 禁止同名重复声明,所以登记符号之前要检查有没有同名变量声明过;
4. 增加类型检查;

三、实验的分析与设计
1.经过修改后的翻译模式:
start-> DS.
D->B; D
D->ε
B->int L { L.type := int }|real L { L.type := real }
L->id { A.Type := L.type enter(v.entry,L.type)} A
A-> ,idA { A1.Type := A.type enter(v.entry,A.type)}
A->ε
S→ V := E { gen( “:=”, E.place,0,V.place) } H
H→;S | ε
E->T { R.i:=T.place} R {E.place:=R.s}
R->+T { R1.i:= newtemp; gen( “*”, R.i, T.place , R1.i) } R {R.s:= R1.s; }
R-> ε {Rs=R.i}

T→F {p.i:=F.place} P {T.place:=P.s}
P->F {p1.i:=newtemp;gen(““,P.i,T.place,P.i)} P {P.s:=P1.s;}
P->/F {p1.i:=newtemp;gen(“/”,P.i,T.place,P.i)} P {P.s:=P1.s;}
P-> ε {Ps=P.i}

F->( E ) { F.place := E.place}
F->id {F.place:=position (id)}
V->id {V.place:=position(id)}

type、i属性为继承属性,place、s属性为综合属性。

  1. 实现增加乘法 * 和除法 / 运算,并且,/优先级别高于+;其次,和/满足左结合规则;
  2. 对包含乘除法运算的表达式生成对应的四元式;
    E->T { R.i:=T.place} R {E.place:=R.s}
    R->+T { R1.i:= newtemp; gen( “*”, R.i, T.place , R1.i) } R {R.s:= R1.s; }
    R-> ε {Rs=R.i}

T→F {p.i:=F.place} P {T.place:=P.s}
P->F {p1.i:=newtemp;gen(““,P.i,T.place,P.i)} P {P.s:=P1.s;}
P->/F {p1.i:=newtemp;gen(“/”,P.i,T.place,P.i)} P {P.s:=P1.s;}
P-> ε {Ps=P.i}
3. 禁止同名重复声明,所以登记符号之前要检查有没有同名变量声明过;
登记符号之前要检查有没有同名变量声明过。
在enter( )这个存放声明变量的函数中,增加相应检验变量名重复的函数:

  1. 增加类型检查;
    检验’:=’前后字符类型是否匹配

检验’+’前后类型是否匹配

检验’*’前后的类型是否匹配

检验’/’前后的类型是否匹配

四、实验的实现

五、运行的结果以及存在问题及其原因

#include <stdio.h>#include<dos.h>#include<stdlib.h>#include<string.h>//#include <iostream.h>#include<ctype.h>#include <windows.h>#define txmax 100    /* 符号表最大容量 */#define al 10        /* 符号的最大长度 */#define tvmax 500    /* 最多能够申请的临时变量取值范围[100, tvmax] */#define norw 2       /* 关键字个数 */#define cxmax 500   /* 最多的虚拟机代码数 */int tx;              //名字表指针, 取值范围[0, txmax-1]int tv ;             //临时变量计数/* 符号 */enum symbol {    nul,         eeof,  ident,         plus,      times,    lparen,divide,    rparen,    comma,     semicolon,  becomes,  period, realsym,    intsym,};enum symbol sym;    /* 当前的符号 */char ch;            /* 获取字符的缓冲区,getch 使用 */char id[al+1];      /* 当前ident, 多出的一个字节用于存放0 */char a[al+1];       /* 临时符号, 多出的一个字节用于存放0 *//* 符号表结构 */struct tablestruct{   char name[al];      /* 名字 */    enum symbol type;   // 类型};struct tablestruct table[txmax]; /* 符号表 */char word[norw][al];        /* 保留字 */enum symbol wsym[norw];     /* 保留字对应的符号值 */enum symbol ssym[256];      /* 单字符的符号值,散列表 */int cx;             /* 四元式代码指针, 取值范围[0, cxmax-1]*/struct instruction{    char f[al+1]; /* 操作码 */    char l[al+1];     /* 左操作数 */    char r[al+1];     /* 右操作数*/    char t[al+1];     /* 结果 */};struct instruction code[cxmax]; /* 存放虚拟机代码的数组 */FILE* fin;FILE* fout;int getsym();void enter(enum symbol type);void init();int position(char* idt);int gen(enum symbol op, int arg1, int arg2,int result );     //中间代码分析void writecode(char *op, char *arg1, char *arg2,char *result );    //写缓存void  start();void  D();void  B();void L(enum symbol type);void A(enum symbol type);void S();void H();int E();int R(int Ri);int T();int P(int Pi);int F();int V();
#include "语义分析.h"int  main(){    char filename[20];    printf("请输入分析的文件名:");    gets(filename);    if((fin=fopen(filename,"r"))==NULL)    {        printf("不能打开文件.\n");        exit(0);    }    init();                  //初始化    getsym();                //读第一个单词,将单词类别放入sym中,单词值放入id中    start();                //开始按start->DS.  分析    if (sym==eeof)    {        printf("语法正确\n\n将中间代码保存到文件请输入文件名,否则回车");        gets(filename);        if(strlen(filename)<=0) return 0;        if((fout=fopen(filename,"w"))==NULL)        {            printf("不能打开文件.\n");            exit(0);        }        for (int cx1=0; cx1<cx; cx1++)            fprintf(fout,"(%s,%s,%s,%s)\n",code[cx1].f,code[cx1].l,code[cx1].r,code[cx1].t);        return 0;    }    else    {        printf("语法错1:  . 后不能再有句子");        exit(0);    }    fclose(fin);    fclose(fout);    return 0;}//初始化函数void init(){    int i;    /* 设置单字符符号 */    for (i=0; i<=255; i++)    {        ssym[i] = nul;            //不正确的单字符符号为nul,先预置初值nul    }    ssym['+'] = plus;    ssym['*'] = times;    ssym['('] = lparen;    ssym[')'] = rparen;    ssym['.'] = period;    ssym[','] = comma;    ssym[';'] = semicolon;    ssym['/']=divide;    /* 设置保留字名字 */    strcpy(&(word[0][0]), "real");    strcpy(&(word[1][0]), "int");    /* 设置保留字符号 */    wsym[0] = realsym;    wsym[1] = intsym;    tv=100;           //临时变量指针初值,让Tx和tv的取值没有交集,区别到底是临时变变量和声明的变量    tx=0;           //表指针初值    cx=0;     //指令计数器}/** 词法分析,获取一个符号*/int getsym(){    int i,k;    ch=fgetc(fin);    if (ch==EOF)    {        sym=eeof;    //文件结束        return 0;    }    while (ch==' ' || ch==10 || ch==13 || ch==9)  /* 忽略空格、换行、回车和TAB */        ch=fgetc(fin);    if (ch>='a' && ch<='z')    {        /* 名字或保留字以a..z开头 ,*/        k = 0;        do        {            if(k<al)                  /* 符号的最大长度为al ,超长就截尾处理*/            {                a[k] = ch;                k++;            }            ch=fgetc(fin);        }        while ((ch>='a' && ch<='z' )|| (ch>='0' && ch<='9'));        a[k] = 0;        strcpy(id, a);//a的地址赋予id        fseek(fin,-1,1);//文件指针偏移,向后读一个        for (i=0; i<norw; i++)      /* 搜索当前符号是否为保留字 */            if (strcmp(id,word[i]) == 0)//如果是                break;        if (i <norw)//已经经过定义,不可作为变量和过程名        {            sym = wsym[i];        }        else        {            sym = ident;          /* 搜索失败则,类型是标识符 */        }    }    else if(ch == ':') /* 检测赋值符号 */    {        ch=fgetc(fin);        if (ch == '=')        {            sym = becomes;        }        else        {            sym = nul;  /* 不能识别的符号 */        }    }    else sym = ssym[ch];     /* 当符号不满足上述条件时,全部按照单字符符号处理 */    return 0;}/** 在符号表中加入一项*/void enter(enum symbol type)//将声明过的变量保存在结构体table[tx]中{    tx=tx+1;    if (tx > txmax)    {        printf(" 符号表越界 ");           /* 符号表越界 */        return;    }    for(int i=1; i<txmax; i++)    {        if(strcmp(id,table[i].name)==0)        {            printf("错误1:变量名重复定义\n");            exit(0);        }    }    strcpy(table[tx].name, id); /* 全局变量id中已存有当前名字的名字,Tx为插入当前符号之前表尾指针 */    table[tx].type = type;}/** 查找名字的位置.* 找到则返回在名字表中的位置,否则返回0.** idt:    要查找的名字* tx:     当前名字表尾指针,全局变量*//*判断是否已经存在*/int position(char* idt){    int i;    strcpy(table[0].name, idt);    i = tx;    while (strcmp(table[i].name, idt) != 0)    {        i--;    }    return i;}/* 中间代码,生成四元式,目标代码*/int gen(enum symbol op, int arg1, int arg2,int result )//通过传来的参数产生四元式{    char temp1[al+1],temp2[al+1],temp3[al+1];    if(arg1>=100)                            //模拟申请临时变量    {        wsprintf(temp1,"T%d",arg1);//temp1是一个缓冲区,将arg1内容输出到temp1中    }    else    {        strcpy(temp1, table[arg1].name);//把table[arg1].name的内容copy到temp1中    }    if(arg2>=100)    {        wsprintf(temp2,"T%d",arg2);    }    else    {        strcpy(temp2, table[arg2].name);    }    if(result>=100)    {        wsprintf(temp3,"T%d",result);    }    else    {        strcpy(temp3,table[result].name);    }    if (op==becomes)//赋值符    {        if(table[arg1].type!=table[result].type) //检验':='前后字符类型是否匹配        {            printf("(:=,%s,%s,%s)\n",temp1,temp2,temp3);//输出四元式            writecode(":=",temp1,temp2,temp3);//写入缓存            printf("语法错:%s和%s的类型不一致\n",temp1,temp3);//':='前后字符类型不匹配,报错        }        else //:=前后字符类型匹配        {            printf("(:=,%s,%s,%s)\n",temp1,temp2,temp3);            writecode(":=",temp1,temp2,temp3);//写入缓存        }    }    else if (op==plus)                          //+运算    {        if(table[arg1].type==table[arg2].type)//检验'+'前后类型是否匹配        {            table[result].type=table[arg1].type;            writecode("+",temp1,temp2,temp3);            printf("(+,%s,%s,%s)\n",temp1,temp2,temp3);        }        else        {            printf("(+,%s,%s,%s)\n",temp1,temp2,temp3);            writecode("+",temp1,temp2,temp3);            printf("语法错:%s和%s的类型不一致\n",temp1,temp2);        }    }    /*乘法*/    else if(op==times)    {        if(table[arg1].type==table[arg2].type)//检验'*'前后的类型是否匹配        {            table[result].type=table[arg1].type;            printf("(*,%s,%s,%s)\n",temp1,temp2,temp3);            writecode("*",temp1,temp2,temp3);        }        else        {            printf("(*,%s,%s,%s)\n",temp1,temp2,temp3);            writecode("*",temp1,temp2,temp3);            printf("语法错:%s和%s的类型不一致\n",temp1,temp2);        }    }    /*除法*/    else if(op==divide)    {        if(table[arg1].type==table[arg2].type)//检验'/'前后的类型是否匹配        {            table[result].type=table[arg1].type;            printf("(/,%s,%s,%s)\n",temp1,temp2,temp3);            writecode("/",temp1,temp2,temp3);        }        else        {            printf("(/,%s,%s,%s)\n",temp1,temp2,temp3);            writecode("/",temp1,temp2,temp3);            printf("语法错:%s和%s的类型不一致\n",temp1,temp2);        }    }    return 0;}//处理代码段,打印void writecode(char op[al+1], char arg1[al+1], char arg2[al+1],char result[al+1] ){    if (cx >= cxmax)    {        printf("Program too long"); /* 程序过长 */        return ;    }    strcpy(code[cx].f, op);    strcpy(code[cx].l,arg1);    strcpy(code[cx].r,arg2);    strcpy(code[cx].t,result);    cx++;    return ;}/*分析产生式     X->DS.   */void  start(){    if (sym==intsym||sym==realsym)//如果变量是int或者real型    {        D();        S();        if (sym==period)        {            getsym();//调用词法分析            return;        }        else        {            printf("语法错2: 缺少程序结束.");            exit(0);        }    }    else    {        printf("语法错3: 程序只能用int,和real开始,而且区分大小写");        exit(0);    }}/*递归下降分析D->  B; DD->ε*/void  D(){    if (sym==intsym ||sym==realsym)    {        B();        if (ch=';')        {            getsym();            D();        }        else        {            printf("语法错4");            exit(0);        }    }    else if(sym==ident)  return;    else    {        printf("语法错5");        exit(0);    }}/*B->   int L    { L.type := int }|real L    { L.type := real }*/void  B(){    if (sym==intsym )//继承L的类型    {        getsym();        L(intsym);    }    else if (sym==realsym)    {        getsym();        L(realsym);    }    else    {        printf("语法错6:变量不是real或int型\n");        exit(0);    }}/*L->   id   { A.Type := L.type  enter(v.entry,L.type)}   A       V.entry通过全局变量tx隐性传递有参,有几个继承属性就有几个参数*/void L(enum symbol type)//L的id赋予A{    int Vplace;    if (sym==ident)    {        Vplace=position(id);        if(Vplace>0)        {            printf("语法错7:变量重复声明\n");            exit(0);        }        enter(type);        getsym();        A(type);    }    else    {        printf("语法错8:缺少变量");        exit(0);    }}/*A-> ,id  A   { A1.Type := A.type  enter(v.entry,A.type)}A->ε*/void A(enum symbol type){    int Vplace;    if (sym==comma)          //当前单词为,    {        getsym();        if (sym==ident)        {            Vplace=position(id);            if(Vplace>0)            {                printf("语法错7:变量重复声明\n");                exit(0);            }            enter(type);            getsym();            A(type);        }        else        {            printf("语法错9");            exit(0);        }    }    else if (sym== semicolon)   return ;//当前单词为;即A的follow集元素相当于进行A->ε    else    {        printf("语法错10");        exit(0);    }}/*S→ V := E { gen( ":=", E.place,0,V.place) } H*/void S(){    int vplace,Eplace;    if (sym==ident)    {        vplace=V();        //getsym();        if (sym==becomes)     //当前单词为:=        {            getsym();            Eplace=E();            gen(becomes,Eplace,-1,vplace);            H();        }        else        {            printf("语法错11");            exit(0);        }    }    else    {        printf("语法错12");        exit(0);    }}/*H→;S | ε*/void H()//执行下一条运算{    if (sym==semicolon)          //当前单词为indent类型    {        getsym();        S();    }    else if (sym==period)   return ;    else    {        printf("语法错13");        exit(0);    }}/*E->T      { R.i:=T.place}      R     {E.place:=R.s}综合属性,有返回值*/int E()//分析赋值号后面的运算{    int ri,tplace,Rs;    if (sym==ident || sym== lparen)//当前为标识符或左括号    {        tplace=T();        ri=tplace;        Rs=R(ri);    }    else    {        printf("语法错14");        exit(0);    }    return Rs;}/*R->+T     { R1.i:= newtemp; gen( "*", R.i, T.place , R1.i) }     R   {R.s:= R1.s; }R-> ε    {R.s=R.i}R既有参数又有返回值*/int R(int Ri)//检验+运算{    int Rs,tplace;    if (sym==plus)    {        getsym();        tplace=T();        tv=tv+1;            //生成临时变量        gen(plus,Ri,tplace,tv);        Rs=R(tv);    }    else if (sym== semicolon || sym==rparen|| sym==period)    {        Rs=Ri;    }    else    {        printf("语法错15");        exit(0);    }    return Rs;}/*实现乘除的左结合及优先级F->( E )  { F.place := E.place}F->id     {F.place:=position (id)}*/int F()//实现*、/运算的优先级高于+运算{    int Fplace;    if(sym==ident)    {        Fplace=position(id);//获取当前位置        if(Fplace==0)        {            printf("变量没有声明\n");            exit(0);        }        getsym();    }    else if(sym==lparen)    {        getsym();        Fplace=E();        if(sym==rparen)getsym();        else        {            printf("语法错16,缺)");            exit(0);        }    }    else    {        printf("语法错17,,缺(");        exit(0);    }    return Fplace;}/*P->*F  {p1.i:=newtemp;gen("*",P.i,T.place,P.i)}  P  {P.s:=P1.s;}P->/F  {p1.i:=newtemp;gen("/",P.i,T.place,P.i)}  P  {P.s:=P1.s;}P-> ε    {Ps=P.i}*/int P(int Pi)//检验*、/运算{    int ps,Fplace;    if(sym==times)    {        getsym();        Fplace=F();        tv=tv+1;//生成临时变量        gen(times,Pi,Fplace,tv);        ps=P(tv);    }    else if(sym==divide)    {        getsym();        Fplace=F();        tv=tv+1;        gen(divide,Pi,Fplace,tv);        ps=P(tv);    }    else if(sym==plus||sym==semicolon||sym==rparen||sym==period)        //求出P的follow集,进行语法检查,如判断左括号是否匹配    {        ps=Pi;    }    else    {        printf("语法错18:缺少变量或(");        exit(0);    }    return ps;}/*将T的位置指向新增加乘除T→F  {p.i:=F.place}   P   {T.place:=P.s}*/int T(){    int Pi,Fplace,Ps;    if(sym==ident||sym==lparen)    {        Fplace=F();        Pi=Fplace;        Ps=P(Pi);    }    else    {        printf("语法错19");        exit(0);    }    return Ps;}/*V->id     {V.place:=position(id)}*/int V(){    int Vplace;    if (sym==ident)    {        Vplace=position (id);        if (Vplace==0)        {            printf("变量没有声明");            exit(0);        }        getsym();    }    else    {        printf("语法错20");        exit(0);    }    return Vplace;}
原创粉丝点击