编译原理实验报告Word格式文档下载.docx
《编译原理实验报告Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《编译原理实验报告Word格式文档下载.docx(16页珍藏版)》请在冰豆网上搜索。
//false表示当前字符未处于注释中。
while(cinf.read(&
cur_c,sizeof(char))){//从文件读一个字符
switch(in_comment){
casefalse:
if(old_c=='
/'
&
&
cur_c=='
*'
){//进入多行注释
i--;
//去除已存入扫描缓冲区的字符'
in_comment=true;
}
else{
if(old_c=='
){//进入行注释
p=1;
//去除已存入扫描缓冲区的字符'
}
else{
\\'
\n'
)//发现续行
i--;
\'
else{
if(cur_c>
='
A'
cur_c<
Z'
)//大写变小写
cur_c+=32;
if(cur_c=='
\t'
||cur_c=='
)//空格取代TAB换行
cur_c='
'
;
buf[i++]=cur_c;
}}}
break;
casetrue:
if((old_c=='
))//离开注释
in_comment=false;
if(cur_c=='
p==1)in_comment=false;
}//endofswitch
old_c=cur_c;
//保留前一个字符
}//endofwhile
buf[i++]='
#'
//在源程序尾部添加字符'
4、结果的输入与输出
Source.txt
Begin/*S=2*3.14*R*R+2*3.14*
R*H*/
RealR,h,s;
s=2*3\
14*r*(r+++h)kmoiulEnd
运行结果如下:
实验二
1、程序设计思路:
编写一个自动机(DFA)识别程序,判断一个字符序列是否为一个DFA所识别。
首先在试验一的基础上,对输入的字符序列进行预处理,然后在输入字符,看其是否能被指定的DFA识别。
构造DNA状态转换矩阵,由输入的字符,确定其是否有后继状态,即是否能被识别。
2、实现过程
DFA的主要函数是:
scanner(char*);
核心代码如下:
while(buf[i]=='
)i++;
{intcur_state=0;
while(DFA[cur_state][col(buf[i])]){//存在后继状态
cur_state=DFA[cur_state][col(buf[i])];
//进入下一状态
if(buf[++i]=='
)break;
//指向下一字符,判缓冲区内字符是否处理完。
string.h>
stdlib.h>
conio.h>
constshortWORDLEN=20;
structcode_val{
charcode;
charval[WORDLEN];
//单词编码表
constcharcode[]="
{}ac=+$*,;
()#"
//DFA列字符
constcharCOL_CHAR[]="
a0=+*,;
()#"
//状态转换矩阵(DFA)
constintDFA[][11]={//strlen("
)=11
{1,2,3,4,5,6,7,8,9,10,0},{11,11},0,12},{0},{0,0,0,13},{0},{0},{0},{0},{0},{0},{11,11},{0,12},{0}
//预处理函数原型
//扫描函数原型
code_valscanner(char*);
//主函数
voidmain()
{charbuf[4048]={'
//扫描缓冲区
//预处理
//显示buf
cout<
//单词识别
code_valt;
//临时变量
do{
t=scanner(buf);
//调用一次扫描器获得一个单词二元式
cout<
t.code<
t.val<
//在屏幕显示单词二元式
}while(t.code!
);
"
Endoflexicalanalysis!
getch();
intcol(char);
//转换函数
charsearch_table(char[]);
//查单词二元式编码表函数
structcode_valscanner(char*buf)//扫描函数,每调用一次,返回一个单词的二元式。
{
staticinti=0;
//buf指针
structcode_valt={'
"
NUL"
chartoken[WORDLEN]="
//用于拼接单词
//去除前导空格
//开始识别单词
intcur_state=0;
}
returnt;
//返回当前单词的二元式
intcol(charc)
if(c>
a'
c<
z'
)c='
0'
9'
//constcharCOL_CHAR[]="
for(inti=0;
i<
=(int)strlen(COL_CHAR);
i++)
if(c==COL_CHAR[i])returni;
Errorchar>
exit(0);
//程序终止运行
}//预处理函数
voidpro_process(char*buf)
ifstreamcinf("
inti=0;
charold_c='
//计数器,前一个字符,当前字符。
//状态标志,false表示当前字符未处于注释中。
cur_c,sizeof(char))){//从文件读一个字符
){//进入注释
//去除已存入扫描缓冲区的字符'
)//去除续行符'
,包括后续换行符。
else{
)cur_c+=32;
if(cur_c=='
||cur_c=='
)cur_c='
//空格
buf[i++]=cur_c;
}}
)//离开注释
//保留前一个字符
buf[i]='
输入内容在source.txt中,如下:
egin/*S=2*3.14*R*R+2*3.14*R*H*/
14*r*(r+++h)kmoiul
End
{NUL
cNUL
ir
NUL
ih
is
NUL
=NUL
x2
*NUL
x314
(NUL
$NUL
+NUL
)NUL
ikmoiul
}NUL
#NUL
实验三
在自上而下预测分析控制程序的基础上,根据文法规则进行语法分析,如字串是句子,写出文法的最左推导。
根据表达式文法的预测分析表,对输入的符号串进行分析。
输入的符号串需是单词二元式。
若产生式匹配,则输出产生式。
X存放当前栈顶符号的工作单元,当X是终结符时,读入下一个符号;
当X是非终结符时,判断其是否为#,若不是,则判断其M[X,a]是否是产生式(匹配),匹配则逆序出栈,然后按最左推导输出。
具体代码如下:
for(i=strlen(p[M[lin(X)][col(t.code)]])-1;
i>
=0;
i)
{stack[++top]=*(p[M[lin(X)][col(t.code)]]+i);
X<
->
p[M[lin(X)][col(t.code)]]<
charcode;
charval[20];
constchar*p[]={//指向产生式右部符号串
TD"
+TD"
FS"
*FS"
(E)"
i"
x"
y"
//0.E→TDD代表E'
//1.D→+TD
//2.D→ε
//3.T→FSS代表T'
//4.S→*FS
//5.S→ε
//6.F→(E)
//7.F→i
//8.F→x
//9.F→y
constcharT[]="
+*()ixy#"
//分析表的列符
constcharNT[]="
EDTSF"
//分析表的行符,行符为EE'
TT'
F。
constintM[][8]={
/*在预测分析表M中存放指针数组p的下标x,设M[i][j]=x,通过p[M[i][j]]=p[x]获取右部符号串。
*/
{-1,-1,0,-1,0,0,0,-1},//p[0]指向第0个产生式右部符号串"
,-1表示出错。
{1,-1,-1,2,-1,-1,-1,2},
{-1,-1,3,-1,3,3,3,-1},
{5,4,-1,5,-1,-1,-1,5},
{-1,-1,6,-1,7,8,9,-1}
//函数原型
intlin(char);
//非终结符转换为行号
intcol(char);
//终结转换为列号
boolisNT(char);
//isNT判断是否是非终结符
boolisT(char);
//isT判断是否是终结符。
voidmain(void)
inti,j=0;
lex_r.txt"
//从文件lex_r.txt输入数据
ofstreamcout("
par_r.txt"
out);
//结果输出至文件par_r.txt(cout重定义)
structcode_valt;
//定义结构变量,存放单词二元式。
cinf>
>
t.code>
t.val;
//读一个单词的二元式
charstack[20]={'
'
E'
inttop=1;
//栈赋初值
charX='
//用于显示,并非必要。
step"
stack"
X"
t.code"
//用于显示,并非必要。
j<
)'
//用于显示,并非必要。
while
(1){
for(i=0;
=top;
i++)cout<
stack[i];
//用于显示,并非必要。
X=stack[top--];
//出栈
++j<
//用于显示,并非必要。
//用于显示,并非必要。
if(X=='
){
if(X==t.code){cout<
\tAcc"
break;
//跳出循环}
else{cout<
Errin#>
}//endofif(X=='
)
if(isT(X)){//是否是终结符
if(X==t.code)
cinf>
//读下一单词二元式
ErrinT>
continue;
}//endofif(isT(X))
if(isNT(X)){//是否是非终结符
if(M[lin(X)][col(t.code)]==-1){
cout<
ErrinNT>
else{for(i=strlen(p[M[lin(X)][col(t.code)]])-1;
i--)
stack[++top]=*(p[M[lin(X)][col(t.code)]]+i);
}//endofif(isNT(X))
Errinmain()>
}//endofwhile
}//endofmain
intlin(charc)//将EDTSF分别转换为01234
{for(inti=0;
(int)strlen(NT);
if(c==NT[i])returni;
Errinlin()>
intcol(charc)//将+*()ixy#分别转换为01234567
{or(inti=0;
(int)strlen(T);
i++)if(c==T[i])returni;
Errincol()>
boolisNT(charc)//是否是非终结符
{for(inti=0;
i++)if(c==NT[i])returntrue;
returnfalse;
boolisT(charc)//是否是终结符(不包括'
)
(int)strlen(T)-1;
i++)if(c==T[i])returntrue;
文件lex_r.txt输入数据,如下:
ia+nulib#nul
结果输出至文件par_r.txt,如下:
stepstackXt.code
0)#Ei
1)#Ei
E->
TD
#DTi
2)#DTi
T->
FS
#DSFi
3)#DSFi
F->
i
#DSii
4)#DSii
#DS+
5)#DS+
S->
#D+
6)#D+
D->
+TD
#DT++
7)#DT++
8)#DTi
9)#DSFi
10)#DSii
#DS#
11)#DS#
#D#
12)#D#
##
13)##
Acc
实验四
在LR语法分析器的控制程序的基础上,添加语义栈,在对字符串进行分析的同时,也翻译字符串。
当action<
0时,进行归约,action为-n,则
,即归约编号为n的产生式。
若action=-1,则归约产生式E→E+T。
语义栈的栈顶yu[top]应变为当前位置与其后第二个位置的和,如下:
case-1:
yu[top]=yu[top]+yu[top+2];
同理,其余产生式的语义翻译也如下:
case-2:
yu[top]=yu[top];
case-3:
yu[top]=yu[top]*yu[top+2];
case-4:
case-5:
yu[top]=yu[top+1];
case-6:
最后,当程序接受acc之后,输出翻译结果,即输入栈顶元素。
structcode_val{charcode;
constchar*p[]={"
S→E"
E→E+T"
E→T"
T→T*F"
T→F"
F→(E)"
F→i"
};
constcharTNT[]="
+*()i#ETF"
//LR分析表列的字符
constintM[][9]={//LR分析表数字化,列字符+*()i#ETF用数字012345678标识。
{0,0,4,0,5,0,1,2,3},//0表示出错,s4用4表示。
{6,0,0,0,0,99},//Acc用99表示
{-2,7,0,-2,0,-2},//r2用-2表示
{-4,-4,0,-4,0,-4},
{0,0,4,0,5,0,8,2,3},
{-6,-6,0,-6,0,-6},
{0,0,4,0,5,0,0,9,3},
{0,0,4,0,5,0,0,0,10},
{6,0,0,11},
{-1,7,0,-1,0,-1},
{-3,-3,0,-3,0,-3},
{-5,-5,0,-5,0,-5}
//列定位函数原型
{intstate[50]={0};
//状态栈初值
intyu[50]={0};
charsymbol[50]={'
//符号栈初值
inttop=0;
//栈顶指针初值
//语法分析结果输出至文件par_r.txt
ifstreamcin("
//lex_r.txt存放词法分析结果,语法分析器从该文件输入数据。
//结构变量,存放单词二元式。
cin>
//读一单词
intaction;
//输出时使用的计数器,并非必要。
状态栈"
符号栈"
输入符号"
//do{
j++<
//输出