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属性为综合属性。
- 实现增加乘法 * 和除法 / 运算,并且,/优先级别高于+;其次,和/满足左结合规则;
- 对包含乘除法运算的表达式生成对应的四元式;
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( )这个存放声明变量的函数中,增加相应检验变量名重复的函数:
- 增加类型检查;
检验’:=’前后字符类型是否匹配
检验’+’前后类型是否匹配
检验’*’前后的类型是否匹配
检验’/’前后的类型是否匹配
四、实验的实现
五、运行的结果以及存在问题及其原因
#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;}
- PL0编译语义分析 递归
- 编译原理:PL0词法分析
- 编译原理语义分析
- 编译语义分析实验
- 编译原理---语义分析
- PL0源码分析之占位
- 编译原理实验二:语义分析
- 编译原理之语法,语义,词法分析
- 语义分析-哈工大编译原理第三次实验
- PL0编译器分析与语法扩展
- Java实现C语言语义分析(递归下降)
- 编译原理之词法分析、语法分析、语义分析
- 编译原理之词法分析、语法分析、语义分析
- 编译原理之词法分析、语法分析、语义分析
- PL0 表达式的计算(递归子程序法)
- 语义分析
- 语义分析
- 编译原理pl/0 c语言版 pl0.h文件
- Be Like Water--程序设计的平衡和取舍
- Linux关闭防火墙(Centos6.5)
- Spring Data Jpa 配合MongoDB实现持久层对象属性动态增加
- 【Python】Python3 List count()方法
- 好吧,左小波出山了!
- PL0编译语义分析 递归
- java将一个List赋值给另一个List相关问题
- Two Paths HDU
- NOIP 提高组 2003
- DataGridView连接数据源
- 调用ArcToolBox里的Tool的三种方法
- 【STL】STL之顺序容器和关联容器总结
- 关于数组(一)
- Java Web 架构系列 知识(一) 数据库连接池