语法分析

  • 格式:docx
  • 大小:236.52 KB
  • 文档页数:26

编译原理实验二·语法分析

一、 实验目的

通过动手实践,使学生对构造编译系统的基本理论、编译程序的基本结构有更为深入的理解和掌握;使学生掌握编译程序设计的基本方法和步骤;能够设计实现编译系统的重要环节。同时增强编写和调试程序的能力。

二、 实验内容及要求

对某特定语言A ,构造其语法规则。该语言的语法单位如下:

实现识别该语言的语法分析器, 可以选用:细化的递归下降程序,或者预测分析程序等。

按语法单位出现的顺序,返回识别出的语法单位序列

出现的语法错误,可以指出错误位置,及错误原因。

出现的标识符存放在标识符表,整型常数存放在常数表

三、 实验过程

1、 文法描述

语言A的文法的描述如下:

程序P的文法:

P  program ID;

语句S文法:

S  SA | SD | SW | SC | SIF

赋值语句的文法:

SA  ID := E | ID := NUM 定义语句的文法:

SD  var int ID D’

D’  ,ID D’|ε

循环语句的文法:

SW  while B do S

判断语句的文法:

SIF  if B then S | if B then S else S

复合语句的文法:

SC  begin S C’

C’  ;S C’| ;end

布尔表达式B的文法:

B  TB′

B′ and TB′|ε

T  FT′

T′ or FT′|ε

F  not F |(B)| E rop E | E

rop  > | < | >= | <= | <> | =

算术表达式E的文法(此中的T、T’和F与上面不同):

E  TE'

E' + TE' | ε

T  FT'

T'  * FT' | ε

F  (E) | I

注:ID与NUM的文法与语法分析器中的定义相同。

2、 单词种别定义

A语言中的单词符号及其对应的种别编码如下表所示:

单词符号 种别编码 单词符号 种别编码

program 1 + 16

begin 2 * 17

end 3 ( 18

var 4 ) 19

int 5 , 20

and 6 . 21

or 7 := 22

not 8 ; 23

if 9 > 24

then 10 < 25 else 11 = 26

while 12 >= 27

do 13 <= 28

标识符 14 <> 29

整型常量 15 - 30

3、 运行环境

本次实验采用win-tc进行代码的编写和编译及运行

程序的运行环境为windows

4、 关键算法描述

本程序采用细化的递归下降程序进行描述,所用到的主要函数有:

main() //主函数,程序的入口

P() //程序P文法判定函数

S(int i) //语句S文法实现程序,i表示递归层数,下同

SA(int i) //赋值语句文法实现程序

SD(int i) //定义语句文法实现程序

SW(int i) //循环语句文法实现语句

SIF(int i) //判断语句文法实现语句

SC(int i) //复合语句文法实现判断语句

E() //算数表达式

B() //布尔表达式

errProc(int type) //出错处理语句,参数type表示错误类型,此函数与词法分析中的出错函数相同,是在原函数的基础上添加新的错误类型

struct binary *lexicalAnalyze() //词法分析主函数,本程序通过此函数实现了与词法分析程序的连接

语句S的程序流程图如下所示:

开始

判断当前单词符号

当前为if

关键字 调用SIF()函数 是

当前为begin

关键字 调用SC()函数 是 否

当前为while

关键字 调用SW()函数 是

主函数main()程序流程图如下所示:

当前为var

关键字 调用SD()函数 是

当前为分号 调用SD()函数 是

结束

开始

程序的初始化操作:将文件的内容读入内存;保留字、标识符、常数和错误表初始化;ch指针初始化

调用程序P(),返回result

Result为1 是 到达数据末尾

出错处理 调用函数S() 否 是

结束

其他的文法分析函数SA()、SD()、SW()、SIF()、SC()、E()、B()和P()按照文法的产生式就可以得到具体的代码了。

在lexicalAnalyze()函数的调用过程中,用到了词法分析的函数,通过这个函数作为接口将词法与语法分析很好地结合在了一起。

5、 测试报告

语法分析功能检测:

测试用的A语言代码如下:

代码执行后在控制台中输出如下:

报错功能检测:

将原A语言加入如下图的语法错误:

(图中画圈处为加入的语法错误)

代码执行结果如下所示:

(矩形方框为表示错误检测的表现)

经检验,本程序的语法分析功能和报错功能均可以正确执行。

四、 实验总结

1、 实验体会

通过本次实验,我进一步巩固了学习的编译原理的知识,同时更加熟练地掌握了各种矩形的文法,对词法分析器的工作原理有了进一步的认识,自上而下的分析程序的思想进一步巩固,增强了编程技巧。

刚完成的时候,程序可以完成语法分析,但由于使用了递归调用,所以先出现的语法句型反而在后面显示,后来增加了以一种数据结构,将分析过程中出现的矩形记录在链表中,最后进行分析与显示。通过这个过程,我认识到,在编程的过程中,要充分利用各种数据结构帮助解决问题,可以大大增加编程效率。

2、 存在不足及改进思路

1、 当遇到错误的时候,直接寻找下一个的分号的位置,可能会错过一些关键字,从而对结构进行误判。

改进思路:当遇到错误的时候,可以寻找下一个关键字或分号。

2、 若语句缺少while或if关键字,将对整个结构都不能正确分析

改进思路:增加S()函数的判断条件,将if 或while 的缺失作为一种错误类型。

附:程序源代码(C语言)

注:仅语法分析的部分

主函数:

main(int argc,char ** argv)

{

int nLen;

char *pchBuf;

struct showitem *tempitem;

int tempi,curi;

FILE *pf = fopen(argv[1],"r");

FILE *pf1 = fopen(argv[2],"w");

itable = (struct identifier*)malloc(sizeof(struct identifier));

ctable = (struct constant*)malloc(sizeof(struct constant));

etable = (struct err*)malloc(sizeof(struct err));

shead = (struct showitem*)malloc(sizeof(struct showitem));

itable->index = 0;

ctable->index = 0;

itail = itable;

ctail = ctable;

etail = etable;

stail = shead;

itable->next = NULL;

ctable->next = NULL;

etable->next = NULL;

shead->next = NULL;

fseek(pf, 0, SEEK_END);

nLen = ftell(pf);

rewind(pf);

pchBuf = (char*) malloc(sizeof(char)*nLen+1);

nLen = fread(pchBuf, sizeof(char), nLen, pf);

pchBuf[nLen] = '\0';

ch = pchBuf;

fclose(pf);

curBinary = lexicalAnalyze();

if(P() == 1){

while(curBinary->type != 21)

S(0);

}

stail = shead->next;