编译原理试验指导.docx
《编译原理试验指导.docx》由会员分享,可在线阅读,更多相关《编译原理试验指导.docx(11页珍藏版)》请在冰豆网上搜索。
![编译原理试验指导.docx](https://file1.bdocx.com/fileroot1/2023-1/29/50e0329f-6dc9-4441-8431-20578ac4ae35/50e0329f-6dc9-4441-8431-20578ac4ae351.gif)
编译原理试验指导
编译原理实验指导
计算机工程学院
内容简介
编译原理是计算机专业中的一门专业必修课程,在理论上它要求学生掌握有关形式语言和自动机的抽象概念,在技术上要求学生能够熟练地利用各种数据结构进行编程,很具有挑战性。
我们希望学生在学习完本课之后,能够对形式语言和其内部结构有一个较深刻的认识。
本书包含三个实验:
词法分析器,LL1语法分析、语义与代码生成。
这三个实验构成了编译器的主要组成部分,全部在VC++6.0环境下完成。
目录
实验一词法分析实验1
实验二LL1语法分析4
实验三语义及代码生成7
实验一词法分析实验
1、实验目的
加深对词法分析器的工作过程的理解;加强对词法分析方法的掌握;能够采用一种编程语言实现简单的词法分析程序;能够使用自己编写的分析程序对简单的程序段进行词法分析。
2、实验内容
对源程序进行词法分析:
要求识别出关键字、标识符、数字和符号,并以(单词类别,单词值)二元组的形式显示。
如inta;经过词法分析程序后得到的二元组为:
intint
IDa
;;
以下为词法分析程序的测试数据
main()
{
inta,b;
a=10;
b=a+20;
}
请对以上代码利用词法分析程序分析并得到相应的二元组。
3、实验分析
在本次实验中是对一个简化的c语言程序进行分析,它的单词符号有:
●标识符:
字母打头,后接字母数字,识别出的标识符用ID标记。
●保留字(它是标识符的子集):
if,else,for,while,do,int,write,read,识别出的保留字直接用该保
留字标记。
●无符号整数:
由数字组成,用NUM标记。
●分界符:
+、-、*、/、(、)、;、,>、<、{、}、!
等单分界符,直接用单分界符标记。
>=、<=、!
=、==等双字符分界符,直接用双分界符标记。
●注释符:
用/*….*/括起
为了从源程序字符流中正确识别出各类单词符号,相邻的标识符、整数或保留字之间至少要用一个空格分开。
此语言的各类单词符号的正则文法规则如下:
∷=|ID|ID
∷=|
∷=a|b|…|z|A|B|…|Z
∷=1|2|…|9|0
∷=+|-|*|/|=|(|)|{|}|:
|,|;|<|>|!
∷=>=|<=|!
=|==
∷=/*
∷=*/
图1单词符号的状态图
根据状态图,分析相应动作就可以构造出词法分析程序的算法流程图,如下图所示,在程序开始时,首先读入一个字符,若为空字符,则继续读,直到读进一个非空字符,读进的字符有如下6种情况,要进行不同的处理。
(1)字母。
继续读,直到遇见空格、分界符、文件尾或非字母数字字符。
组合标记符,查保留字表。
若为保留字,输出相应单词记号;若不是,输出标记符的单词记号及单词值(标识符)。
(2)数字。
继续读,直到遇见空格、或非数字字符出现或文件尾。
输出无符号整数的单词记号及数字串。
(3)=、<、>、!
。
读入下一个字符,判断是否为双字符分界符,若是,组成双字符分界符,输出相应单词记号及双分界符;若不是,输出单分界符记号。
(4)非=、<、>、/等与双分界符首字符不同的单分界字符。
输出相应单词记号及单分界符。
(5)/。
读入下一个字符。
若不是“*”,输出/的单词记号;若是“*”,进行注释处理。
词法分析不输出“/*”,并要跳过整个注释内容直到遇到“*/”为止,然后返回开始状态,继续识别下一个单词符号。
(6)非法字符。
如果读进的字符不属于上面任意情况,则说明词法分析程序从源程序读入了一个不合法的字符,即该字符不属于程序语言所定义的所有单词符号首字符集合。
词法分析程序在遇到不合法字符时要进行错误处理,报告错误信息,跳过这个字符,然后转入开始状态,继续识别下一个单词符号。
图2词法分析程序流程图
4、实验步骤
(1)启动VisualC++系统,新建一个工程;
(2)新建一个源程序文件;
(3)编译,调试该程序;
(4)运行该程序,输入测试数据,观察输出数据;
(5)分析实验结果。
实验二LL1语法分析
1、实验目的
(1)一切LL
(1)文法;含有直接左递归但可以转化为LL
(1)文法的文法;含有间接左递归但可以转化为LL
(1)文法的文法
(2)计算出文法的First()Follow()
(3)构造相应文法的预测分析表
(4)对某个输入句子进行分析
2、实验内容
LL
(1)文法是一类可以进行确定的自顶向下语法分析的文法。
就是要求描述语言的文法是无左递归的和无回溯的。
根据LL
(1)文法的定义,对于同一非终结符A的任意两个产生式A:
=a和A:
=b,都要满足:
SELECT(A:
=a)∩SELECT(A:
=b)=Ø。
(1)文法的左递归
当一个文法是左递归文法时,采用自顶向下分析法会使分析过程进入无穷循环之中。
所以采用自顶向下语法分析需要消除文法的左递归性。
文法的左递归是指若文法中对任一非终结符A有推导AA…,则称该文法是左递归的。
左递归又可以分为直接左递归和间接左递归。
●直接左递归
若文法中的某一产生式形如A→Aα,α∈V*,则称该文法是直接左递归的。
消除直接左递归的方法:
设有产生式是关于非终结符A的直接左递归:
A→Aα|β(α,β∈V*,且β不以A开头)
对A引入一个新的非终结符A′,把上式改写为:
A→βA′
A′→αA′|ε
●间接左递归
若文法中存在某一非终结符A,使得AA…至少需要两步推导,则称该文法是间接左递归的。
消除间接左递归的方法:
【方法一】采用代入法把间接左递归变成直接左递归。
【方法二】直接改写文法:
设有文法G10[S]:
S→Aα|β⑴
A→Sγ⑵
因为SAαSγα,所以S是一个间接递归的非终结符。
为了消除这种间接左递归,将⑵式代入⑴式,即可得到与原文法等价的文法(可以证明):
S→Sγα|β⑶
⑶式是直接左递归的,可以采用前面介绍的消除直接左递归的方法,对文法进行改写后可得文法:
S→βS′
S′→γαS′|ε
1计算first集合
(1)若X∈VT,则First(X)={X}
(2)若X∈VN,且有产生式X→a…,a∈VT则First(X)={X}
(3)若X∈VN,且有产生式X→ε,则First(X)={X}
(4)若X,Y1,Y2,…,Yn都∈VN,而由产生式X→Y1Y2…Yn。
当Y1,Y2,…,Yi-1都能推导出ε时,(其中1≤i≤n),则First(Y1)-{ε},First(Y2)-{ε},…,First(Yi)都包含在First(X)中
(5)当(4)中所有Yi都能推导出ε,(i=1,2,…,n),则First(X)=First(Y1)∪First(Y2)∪…First(Yn)∪{ε}
反复使用上述步骤直到每个符合的First集合不再增大为止。
2计算Follow集
对文法中的每个A∈VN,计算Follw(A):
(1)设S为文法的开始符合,把{#}加入Follow(S)中;
(2)若A→αBβ是一个产生式,则把First(β)的非空元素加入Follow(B)中,如果β能推导出ε,则把Follow(A)也加入(B)中;
(3)反复使用以上步骤直到每个非终结符号的Follow集不再增大为止。
3预测分析方法
预测分析方法是自顶向下分析的另一种方法,一个预测分析器是由三个部分组成:
预测分析程序;先进后出栈;预测分析表。
预测分析程序的框图如下:
实验三语义及代码生成
1、实验目的
理解并掌握语义分析的基本概念,基本方法;掌握代码优化与目标生成的基本原理与技术实现;编写类C语言编译程序的目标代码生成的程序,调试成功后,以给出的程序段为测试数据,并按一定格式显示结果。
2、实验内容和分析
与实验二的语法规则相比,只有部分规则需要添加动作符号,下面我们列出添加了动作符号的规则。
(1)↓vartablep,datap->intID↑n@name-def↓n,t;
动作解释:
vartablep指出符号表的最后一个记录的下一个位置,即第一个空白记录位置。
每当有一个记录加入符号表,该值加1;datap表示已经分配的地址空间,它开始时为0,每声明一个变量,该值则根据变量类型累加,如整型加2,实型加4等等。
@name-def↓n,t的动作:
查询符号表,从vartablep所指的前一个位置起往回查直到第一个记录,若没有,将标识符名n及类型1、datap的值填入符号表vartablep所指的位置,然后vartablep加1,datap根据类型t增加;若有,报告错误:
变量重复定义。
(2):
:
=ID↑n@LOOK↓n↑d@ASSIGN=@STO↓d|
(3):
:
=
|>@GT
|<@LES
|>=@GE
|<=@LE
|==@EQ
|!
=@NOTEQ
(4):
:
={(+@ADD|-<项>@SUB)}
(5):
:
={(*@MULT|/@DIV)}
(6):
:
=()|ID↑n@LOOK↓n↑d@LOAD↓d|NUM↑i@LOADI↓i
(2)、(3)、(4)、(5)、(6)规则中的动作符号解释如下:
@LOOK↓n↑d:
查符号表n,给出变量地址d;没有,变量没定义
@ASSIGN:
超前读一个符号,如果是'=',则表示进入赋值表达式,如果不是'=',则选择<比较表达式>,然后还要将超前读的这个符号退回。
@STO↓d:
输出指令代码STOd,且codep++(因产生了指令,所以指令记数加1)
@LOADI↓i:
输出指令代码LOADIi,且codep++
@LOAD↓d:
输出指令代码LOADd,且codep++
@GT、@ADD等:
输出后的指令代码GT、ADD等
(7):
:
=if()@BRF↑label1@BR↑label2
@SETlabel↓label1[else]@SETlabel↓label2
其中动作符号的含义如下
@BRF↑label1:
输出BRFlabel1,codep++
@BR↑label2:
输出BRlabel2,codep++
@SETlabel↓label1:
设置标号label1
@SETlabel↓label2:
设置标号label2
(8):
:
=while@SETlabel↑label1()@BRF↑label2
@BR↓label1@SETlabel↓label2
动作解释如下:
@SETlabel↑label1:
设置标号label1
@BRF↑label2:
输出BRFlabel2,codep++
@BR↓label1:
输出BRlabel1,codep++
@SETlabel↓label2:
设置标号label2
(9):
:
=for(;
@SETlabel↑label1@BRF↑label2@BR↑label3;
@SETlabel↑label4@BR↓label1)
@SETlabel↓label3@BR↓label4@SETlabel↓label2
动作解释:
@SETlabel↓label1:
设置标号label1
@BRF↑label2:
输出BRFlabel2,codep++
@BR↑label3:
输出BRlabel3,codep++
@SETlabel↓label4:
设置标号label4
@BR↑label1:
输出BRlabel1,codep++
@SETlabel↓label3:
设置标号label3
@BR↑label4:
输出BRlabel4,codep++
@SETlabel↓label2:
设置标号label2
(10):
:
=write@OUT;
动作解释:
@OUT:
输出OUT
(11):
:
=readID↑nLOOK↓n↑d@IN↓d;
动作解释:
@LOOK↓n↑d:
查符号表n,给出变量地址d;没有,变量没定义
@IN:
输出IN
@STI↓d:
输出指令代码STId
抽象机常用汇编指令如下:
LOADD将D中的内容加载到操作数栈
LOADI常量将常量压入操作数栈
LOAD(D)将变量地址D压入操作数栈
STOD将操作数栈栈顶单元内容存入D
ADD将次栈顶单元与栈顶单元内容相加,和置于栈顶
SUB将栈顶单元减去次栈顶单元内容,差置于栈顶
MULT将次栈顶单元与栈顶单元内容相乘,积置于栈顶
DIV将栈顶单元除次栈顶单元内容,商置于栈顶(分母为栈)
BRlab无条件转移到lab
BRFlab检查栈顶单元逻辑值,若为假(0)则转移到lab
EQ将栈顶两单元做等于比较,并将结果真或假(1或0)置于栈顶
NOTEQ将栈顶两单元做不等于比较,并将结果真或假(1或0)置于栈顶
GT次栈顶大于栈顶操作数,则栈顶置1,否则置0
LES次栈顶小于栈顶操作数,则栈顶置1,否则置0
GE次栈顶大于等于栈顶操作数,则栈顶置1,否则置0
LE次栈顶小于等于栈顶操作数,则栈顶置1,否则置0
AND将栈顶两单元做逻辑与运算,并将结果真或假(1或0)置于栈顶
OR将栈顶两单元做逻辑或运算,并将结果真或假(1或0)置于栈顶
NOT将栈顶的逻辑值取反
构造语义和代码生成程序,然后对测试程序进行分析
测试程序
{
inta;
intb;
reada;
writea;
if(a==10)b=1;elseb=2;
writeb;
while(a<=6)b=3;
writeb;
b=0;
for(a=0;a<5;a=a+1)b=4;
writeb;
}
3、实验分析
在本实验中仍采用递归下降分析法,根据实验二中的语法分析,用上面给出的各语句程序替换语法分析对应的同名函数程序,即可将语法分析改为语义分析和代码生成程序。
为了简化起见,在类C编译程序中没有进行复杂的错误处理。
在语法和语义分析中,一旦遇到语法或语义错误,则停止编译,立即返回,并报告发生的错误。
4、实验步骤
(1)启动VisualC++系统,新建一个工程;
(2)新建一个源程序文件;
(3)编译,调试该程序;
(4)运行该程序,输入测试数据,观察输出数据;
(5)分析实验结果。