编译原理实验.docx

上传人:b****5 文档编号:8107164 上传时间:2023-01-28 格式:DOCX 页数:68 大小:975.36KB
下载 相关 举报
编译原理实验.docx_第1页
第1页 / 共68页
编译原理实验.docx_第2页
第2页 / 共68页
编译原理实验.docx_第3页
第3页 / 共68页
编译原理实验.docx_第4页
第4页 / 共68页
编译原理实验.docx_第5页
第5页 / 共68页
点击查看更多>>
下载资源
资源描述

编译原理实验.docx

《编译原理实验.docx》由会员分享,可在线阅读,更多相关《编译原理实验.docx(68页珍藏版)》请在冰豆网上搜索。

编译原理实验.docx

编译原理实验

实验1:

源程序预处理

一、实验目的:

对源程序进行预处理(函数实现,该函数以后还要用到;输入是源程序,输出是预处理过的程序)

二、实验内容:

对源程序进行预处理,去掉空格,跳格,回车,换行,注释等;

三、实验要求:

从文本文件中读入源代码文本字符串,预处理结束后写入另外一个文本文件中;

实验2:

构造词法分析器-自然分词

一、实验目的:

从源程序中分离出单词并归类(自然分词构造词法分析程序)

二、实验内容:

设计一个词法分析器,用C语言或者其他的高级语言实现;

从预处理过的源代码文本文件(实验一的输出文件)中读取源代码字符串,词法分析输出的二元式写入另外一个文本文件中;

三、实验要求:

1、需要识别出的关键字

序号

关键字

单词种别码

属性值

备注

序号

关键字

单词种别码

属性值

备注

1

Auto

 

 

 

17

Int

 

 

 

2

Break

 

 

 

18

long

 

 

 

3

Char

 

 

 

19

return

 

 

 

4

Case

 

 

 

20

register

 

 

 

5

Const

 

 

 

21

short

 

 

 

6

continue

 

 

 

22

signed

 

 

 

7

Default

 

 

 

23

sizeof

 

 

 

8

Do

 

 

 

24

static

 

 

 

9

Double

 

 

 

25

struct

 

 

 

10

Else

 

 

 

26

switch

 

 

 

11

Enum

 

 

 

27

typedef

 

 

 

12

Extern

 

 

 

28

union

 

 

 

13

Float

 

 

 

29

unsigned

 

 

 

14

For

 

 

 

30

void

 

 

 

15

Goto

 

 

 

31

volatile

 

 

 

16

If

 

 

 

32

while

 

 

 

2、需要识别出的运算符

序号

运算符

运算符种别码

运算符属性

备注

序号

运算符

运算符种别码

运算符属性

备注

1

 

 

 

20

 

 

 

2

 

 

 

21

<=

 

 

 

3

 

 

 

22

 

 

 

4

[

 

 

 

23

>=

 

 

 

5

]

 

 

 

24

==

 

 

 

6

->

 

 

 

25

!

=

 

 

 

7

.

 

 

 

26

&&

 

 

 

8

!

 

 

 

27

||

 

 

 

9

++

 

 

 

28

=

 

 

 

10

--

 

 

 

29

+=

 

 

 

11

&

 

 

 

30

-=

 

 

 

12

~

 

 

 

31

*=

 

 

 

13

*

 

 

 

32

/=

 

 

 

14

/

 

 

 

33

;

 

 

 

15

%

 

 

 

34

{

 

 

 

16

+

 

 

 

35

}

 

 

 

17

-

 

 

 

36

 

 

 

18

<< 

 

 

 

37

 

 

 

19

>> 

 

 

 

 

 

 

 

 

3、需要识别出常数

常数类型(无符号)

常数种别码

常数属性

备注

整型常数(10进制)

实型常数(10进制)

4、根据文法绘制状态转化图

(本图为示例图,实际的状态转化图要自己绘制完成)

自定义函数或者使用到变量的意义

charbuffer[]字符数组,存放源代码的文本;

charCHAR字符变量,存放最新读进的源程序字符;

charTOKEN[]字符数组,存放构成单词的字符串;

charGETCHAR(charbuffer[],int*searchIndex)将下一输入字符读入CHAR,搜索指示器searchIndex前移一个字符;

voidGETBC(charbuffer[])检查CHAR中的字符是否为空白。

若是则调用GETCHAR直至CHAR中进入一个非空白字符。

voidCONCAT(charTOKEN[],charCHAR)把CHAR中的字符连接到TOKEN之后。

intLETTER(charCHAR)判断CHAR中的字符是不是字母,从而给出真假值TRUE、FALSE。

intDIGIT(charCHAR)判断CHAR中的字符是不是数字,从而给出真假值TRUE、FALSE。

voidRESERVE(charRESERVE_TABLE[][],charTOKEN[])在保留字表RESERVE_TABLE[][]中查找TOKEN

voidRETRACT(charbuffer[],int*searchIndex)把搜索指示器回调一个字节,把CHAR中的字符置为空白。

5、把状态转换图转化成程序,每个状态要建立一段程序,做的工作如下:

第一步:

从输入缓冲区中取一个字符。

使用函数GETCHAR,每次调用,推进先行指针,送回一个字符。

第二步:

确定在本状态下,哪一条箭弧是用刚刚来的输入字符标识的。

如果找到,控制就转到该弧所指向的状态;若找不到,那么寻找该单词的企图就失败了。

失败:

先行指针必须重新回到开始指针处,并用另一状态图来搜索另一单词。

如果所有的状态转换图都试过之后,还没有匹配的,就表明这是一个词法错误,此时,调用错误校正程序。

典型状态转换图处理流程如下

如上的状态转换图,处理代码如下所示:

switch(state)

{

casei:

CHAR=GETCHAR(buffer[],searchIndex);

if(LETTER(CHAR)==TRUE)

{

CONCAT(TOKEN[],CHAR);

state=j;

}

elseif(DIGIT(CHAR)==TRUE)

{

CONCAT(TOKEN[],CHAR);

state=k;

}

elseif(CHAR==’/’)

{

CONCAT(TOKEN[],CHAR);

state=l;

}

else

{FAIL();}

break;

}

如上的状态转换图,处理代码如下所示:

switch(state)

{

case0:

CHAR=GETCHAR(buffer[],searchIndex);

if(LETTER(CHAR)==TRUE)

{

CONCAT(TOKEN[],CHAR);

state=1;

}

else

{FAIL();}

break;

case1:

CHAR=GETCHAR(buffer[],searchIndex);

if(LETTER(CHAR)==TRUE||DIGIT(CHAR)==TRUE)

{

CONCAT(TOKEN[],CHAR);

state=1;

}

else

{state=2;}

break;

case2:

//构造TOKEN[]对应的二元式

RETRACT(buffer[],searchIndex);//返回多读去的一个字符

returnTOKEN[]对应的二元式;

}

如上的状态转换图,处理代码如下所示:

switch(state)

{

case3:

CHAR=GETCHAR(buffer[],searchIndex);

if(DIGIT(CHAR)==TRUE)

{

CONCAT(TOKEN[],CHAR);

state=3;

}

else

{

state=4;

}

break;

case4:

//构造TOKEN[]对应的二元式

RETRACT(buffer[],searchIndex);//返回多读去的一个字符

returnTOKEN[]对应的二元式;

}

 

实验3:

构造词法分析器-DFA

一、实验目的:

使用DFA实现词法分析(函数实现,该函数以后还要用到,输入预处理过的源程序,输出是分离出的单词符号和种别码的列表)

二、实验内容:

基于DFA设计一个词法分析器。

从预处理过的源代码文本文件(实验一的输出文件)中读取源代码字符串,词法分析输出的二元式写入另外一个文本文件中;

三、实验要求:

1、需要识别出的关键字

序号

关键字

单词种别码

属性值

备注

序号

关键字

单词种别码

属性值

备注

1

Auto

 

 

 

17

Int

 

 

 

2

Break

 

 

 

18

long

 

 

 

3

Char

 

 

 

19

return

 

 

 

4

Case

 

 

 

20

register

 

 

 

5

Const

 

 

 

21

short

 

 

 

6

Continue

 

 

 

22

signed

 

 

 

7

Default

 

 

 

23

sizeof

 

 

 

8

Do

 

 

 

24

static

 

 

 

9

Double

 

 

 

25

struct

 

 

 

10

Else

 

 

 

26

switch

 

 

 

11

Enum

 

 

 

27

typedef

 

 

 

12

Extern

 

 

 

28

union

 

 

 

13

Float

 

 

 

29

unsigned

 

 

 

14

For

 

 

 

30

void

 

 

 

15

Goto

 

 

 

31

volatile

 

 

 

16

If

 

 

 

32

while

 

 

 

2、需要识别出的运算符

序号

运算符

运算符种别码

运算符属性

备注

序号

运算符

运算符种别码

运算符属性

备注

1

 

 

 

20

 

 

 

2

 

 

 

21

<=

 

 

 

3

 

 

 

22

 

 

 

4

[

 

 

 

23

>=

 

 

 

5

]

 

 

 

24

==

 

 

 

6

->

 

 

 

25

!

=

 

 

 

7

.

 

 

 

26

&&

 

 

 

8

!

 

 

 

27

||

 

 

 

9

++

 

 

 

28

=

 

 

 

10

--

 

 

 

29

+=

 

 

 

11

&

 

 

 

30

-=

 

 

 

12

~

 

 

 

31

*=

 

 

 

13

*

 

 

 

32

/=

 

 

 

14

/

 

 

 

33

;

 

 

 

15

%

 

 

 

34

{

 

 

 

16

+

 

 

 

35

}

 

 

 

17

-

 

 

 

36

 

 

 

18

<< 

 

 

 

37

 

 

 

19

>> 

 

 

 

 

 

 

 

 

3、需要识别出常数

常数类型(无符号)

常数种别码

常数属性

备注

整型常数(10进制)

实型常数(10进制)

4、根据词法绘制状态转换图

(下图为示例图,实际的状态转化图要自己绘制完成)

5、根据状态转化图生成转换表(DFA)

(下表为示例表格,实际的状态转化表要根据自己绘制完成状态转换图转换)

字母

数字

*

;

#

空格

0

1

2

3

4

5

6

7

8

9

10

0

1

1

1

2

2

3

4

11

5

6

7

8

9

10

11

5、算法流程

初始化源程序文件;

标识符字串设置为空;

当前状态设置为初态;

从源程序文件中读取字符设置为当前字符;

do{

while(DFA[当前状态][当前字符]存在后继状态)

{

将当前字符拼接进标识符字串中;

后继状态=DFA[当前状态][当前字符];

当前字符指向源程序中后继字符;

当前状态设置为后继状态;

}

判断标识符字串的类别(自定义标识符、关键字(保留字)、常数、运算符);

构造标识符字串所对应的二元式;

将二元式写入二元式文件;

当前状态设置为初态;

标识符字串设置为空;

从源程序文件中读取下一个字符设置为当前字符;

}while(源程序未结束);

实验4:

人狼羊菜过河

一、实验目的:

输出人狼羊菜过河的方法

二、实验内容:

组合出所有可能状态

去除禁忌状态

构造图(邻接矩阵或者邻接表)

查找路径(深度优先、广度优先)

三、实验要求:

实验5:

词法分析-LEX

一、实验目的:

使用LEX分析工具将LEX源程序编译为词法分析器

二、实验内容:

Lex工具是词法分析程序的生成器,它根据词法构成规则(正则表达式)生成单词识别程序,由该程序识别出输入源程序(程序设计者根据词法构成规则编写的源程序)中的各个单词。

1、lex程序的结构共有三部分:

定义部分、规则部分、-用户子程序部分。

其中规则部分是必须的,定义和用户子程序部分是任选的。

(1)定义部分

定义部分起始于"%{"符号,终止于"%}"符号,其间可以是包括include语句、声明语句在内的C语句。

%{

#include"stdio.h"

#include"y.tab.h"

externintlineno;

%}

(2)规则部分

规则部分起始于"%%"符号,终止于"%%"符号,其间则是词法规则。

词法规则由模式和动作两部分组成。

模式部分可以由任意的正则表达式组成,动作部分是由C语言语句组成,这些语句用来对所匹配的模式进行相应处理。

需要注意的是,lex将识别出来的单词存放在yytext[]字符数据中,因此该数组的内容就代表了所识别出来的单词的内容。

%%

[/t]{;}

[0-9]+/.?

|[0-9]*/.[0-9]+

{sscanf(yytext,"%1f",&yylval.val);

returnNUMBER;}

/n{lineno++;return'/n';}

.{returnyytex+[0];}

%%

(3)用户子程序部分

用户子程序部分可以包含用C语言编写的子程序。

这些子程序可以用在前面的动作中,可以达到简化编程的目的。

下面是带有用户子程序的lex程序片段。

"/*"skipcmnts();

/*restofrules*/

%%

skipcmnts()

{

for(;;)

{

while(input()!

='*');

if(input()!

='/')unput(yytext[yylen-1]);

elsereturn;

}

2、lex工具的使用方法

首先编写一个lex程序

vilex.l

%{

#include"stdio.h"

%}

%%

[/n];

[0-9]+printf("Interger:

%s/n",yytext);

[0-9]*/.[0-9]+printf("Float:

%s/n",yytext);

[a-zA-Z][a-zA-Z0-9]*printf("Word:

%s/n",yytext);

.printf("Othersymbol:

%c/n",yytext[0]);

%%

然后使用lex将lex.l转换成C语言程序

$lexlex.l

使用上述命令产生的C语言程序为lex.yy.c

然后使用C编译程序将lex.yy.c编译成可执行程序regn

$cc-clex.yy.c

$cclex.yy.o-ll-oregn

下面可以使用regn来识别单词

$vitestfile

x=355

y=113

p=x/y

#./regn

Word:

x

Othersymbol:

=

Interger:

355

Word:

y

Othersymbol:

=

Interger:

113

Word:

p

Othersymbol:

=

Word:

x

Othersymbol:

/

Word:

y

#

三、实验要求:

实验6:

正则式转化为NFA

一、实验目的:

将输入的正则表达式转化为NFA

二、实验内容:

编程序实现正则表达式转化为NFA。

三、实验要求:

(1)程序接受文本文件中输入的正则表达式,生成该正则表达式对应的NFA,在屏幕上显示出这个NFA。

(2)统计并输出该NFA中的节点个数和边的个数;

(3)输入的正则表达式中包含的运算符包括:

连接运算符”.”,闭包运算符“*”,逻辑或运算符“|”,左括号“(“,右括号“)”。

运算符的运算优先级:

*

.

|

#

*

.

|

#

(4)输入的正则表达式中的字符限于大写英文字母,小写英文字母,数字0~9;

(5)NFA使用图的邻接链表或者邻接矩阵存储;

(6)程序的调试者和执行者保证输入的正则表达式正确,程序不检查正则表达式的正确性。

四、结构体和算法流程

如果NFA使用图的邻接链表存储,邻接链表中存储边信息的结构体:

图的邻接链表中存储图的节点(NFA的状态)信息的结构体:

NFA中的状态在图中用图的节点表示,NFA的所有状态保存在邻接链表的节点结点结构体数组中,结构体定义:

每个输入符号都要生成一个NFA(就是一对开始结束节点和中间连着的箭弧),输入符号生成的NFA要进栈,输入符号对应的NFA的栈结构体:

structstateStack

{

structState*pStateList[MAX];//栈空间

inttop;//栈顶,栈顶元素在数组中的下标

};

正则表达式的运算符栈

算符优先算法

初始化状态栈;

初始化运算符栈;

#压进入运算符栈;

在正则表达式末尾添加#运算符;

产生一个初始0号节点

读取正则表达式的第一个字符;

while(正则表达式没有结束)

{

if(当前字符是正则表达式的字符)

{

产生一对新开始和结束节点;

在开始节点和结束节点之间拉一条标注为当前字符的箭弧;

将开始节点和结束节点压入状态栈;

读取下一个字符;

}

else

{

if(当前操作符运算优先级别比栈顶运算符优先级别高)

{

当前操作符压入符号栈;

读取下一个字符;

}

elseif(当前操作符运算优先级别比栈顶运算符优先级别低)

{

运算符栈的栈顶运算符出栈;

if(出栈运算符是连接符)

{

从状态栈中弹出一对开始结束节点A;

从状态栈中弹出一对开始结束节点B;

从B的结束节点拉一条ε指示的箭弧到A的开始节点;

B的开始节点和A的结束节点作为一对开始结束节点入状态栈;

}

elseif(出栈运算符是逻辑或)

{

从状态栈中弹出一对开始结束节点A;

从状态栈中弹出一对开始结束节点B;

生成一对新的开始结束节点C;

从C的开始节点拉一条ε指示的箭弧到A的开始节点;

从C的开始节点拉一条ε指示的箭弧到B的开始节点;

从A的结束节点拉一条ε指示的箭弧到C的结束节点;

从B的结束节点拉一条ε指示的箭弧到C的结束节点;

C的开始节点和结束节点作为一对节点入状态栈;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 其它

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1