编译原理实验Word文档格式.docx
- 文档编号:21243418
- 上传时间:2023-01-28
- 格式:DOCX
- 页数:68
- 大小:975.36KB
编译原理实验Word文档格式.docx
《编译原理实验Word文档格式.docx》由会员分享,可在线阅读,更多相关《编译原理实验Word文档格式.docx(68页珍藏版)》请在冰豆网上搜索。
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、需要识别出的运算符
运算符
运算符种别码
运算符属性
<
(
=
)
>
[
]
==
->
!
.
&
||
++
--
+=
-=
~
*=
*
/=
/
33
;
%
34
{
+
35
}
-
36
‘
37
“
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)
state=k;
}
elseif(CHAR==’/’)
state=l;
}
else
{FAIL();
}
break;
{
case0:
CHAR=GETCHAR(buffer[],searchIndex);
if(LETTER(CHAR)==TRUE)
state=1;
}
else
{FAIL();
case1:
CHAR=GETCHAR(buffer[],searchIndex);
if(LETTER(CHAR)==TRUE||DIGIT(CHAR)==TRUE)
{
state=1;
}
{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;
}
state=4;
case4:
//构造TOKEN[]对应的二元式
//返回多读去的一个字符
实验3:
构造词法分析器-DFA
使用DFA实现词法分析(函数实现,该函数以后还要用到,输入预处理过的源程序,输出是分离出的单词符号和种别码的列表)
基于DFA设计一个词法分析器。
Continue
4、根据词法绘制状态转换图
(下图为示例图,实际的状态转化图要自己绘制完成)
5、根据状态转化图生成转换表(DFA)
(下表为示例表格,实际的状态转化表要根据自己绘制完成状态转换图转换)
字母
数字
=
+
*
(
)
#
空格
0
1
2
3
4
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"
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
[/n];
[0-9]+printf("
Interger:
%s/n"
yytext);
[0-9]*/.[0-9]+printf("
Float:
%s/n"
[a-zA-Z][a-zA-Z0-9]*printf("
Word:
%s/n"
.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<
testfile
x
=
355
y
113
p
/
实验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(出栈运算符是逻辑或)
生成一对新的开始结束节点C;
从C的开始节点拉一条ε指示的箭弧到A的开始节点;
从C的开始节点拉一条ε指示的箭弧到B的开始节点;
从A的结束节点拉一条ε指示的箭弧到C的结束节点;
从B的结束节点拉一条ε指示的箭弧到C的结束节点;
C的开始节点和结束节点作为一对节点入状态栈;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编译 原理 实验