编译原理实验报告
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
编译原理实验报告
实验⼀词法分析
⼀、实验⽬的
设计、编制并调试⼀个词法分析程序,加深对词法分析原理的理解。
⼆、实验要求
2.1 待分析的简单的词法
(1)关键字:
begin if then while do end
所有的关键字都是⼩写。
(2)运算符和界符
:= + - * / < <= <> > >= = ; ( ) #
(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:
ID = letter (letter | digit)*
NUM = digit digit*
(4)空格有空⽩、制表符和换⾏符组成。
空格⼀般⽤来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。
2.2 各种单词符号对应的种别码:
表2.1 各种单词符号对应的种别码
单词符号种别码单词符号种别码
bgin 1 :17
If 2 := 18
Then 3 < 20
wile 4 <> 21
do 5 <= 22
end 6 > 23
lettet(letter|digit)* 10 >= 24 dight dight* 11 = 25 + 13 ;26
—14 ( 27
* 15 ) 28
/ 16 # 0
2.3 词法分析程序的功能:
输⼊:所给⽂法的源程序字符串。
输出:⼆元组(syn,token或sum)构成的序列。
其中:syn为单词种别码;
token为存放的单词⾃⾝字符串;
(1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)……
三、词法分析程序的算法思想:
算法的基本任务是从字符串表⽰的源程序中识别出具有独⽴意义的单词符号,其基本思想是根据扫描到单词符号的第⼀个字符的种类,拼出相应的单词符号。
3.1 主程序⽰意图:
主程序⽰意图如图3-1所⽰。
其中初始包括以下两个⽅⾯:
⑴关键字表的初值。
关键字作为特殊标识符处理,把它们预先安排在⼀张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。
如能查到匹配的单词,则该单词为关键字,否则为⼀般标识符。
关键字表为⼀个字符串数组,其描述如下:
Char *rwtab[6] = {“begin”, “if”, “then”, “while”, “do”, “end”,};
图3-1
(2)程序中需要⽤到的主要变量为syn,token和sum
3.2 扫描⼦程序的算法思想:
⾸先设置3个变量:①token⽤来存放构成单词符号的字符串;②sum⽤来整型单词;③syn⽤来存放单词符号的种别码。
扫描⼦程序主要部分流程如图3-2所⽰。
图3-2
四、词法分析程序的C语⾔程序源代码:
#include
#include
char prog[80],token[8],ch;
int syn,p,m,n,sum;
char *rwtab[6]={"begin","if","then","while","do","end"};
scaner();
main()
{p=0;
printf("\n please input a string(end with '#'):/n");
do{
scanf("%c",&ch);
prog[p++]=ch;
}while(ch!='#');
p=0;
do{
scaner();
case -1:printf("you have input a wrong string\n");
getch();
exit(0);
default: printf("( %-10s%5d )\n",token,syn);
break; }
}while(syn!=0);
getch(); }
scaner()
{ sum=0;
for(m=0;m<8;m++)token[m++]=NULL;
ch=prog[p++];
m=0;
while((ch==' ')||(ch=='\n'))ch=prog[p++];
if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A')))
{ while(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))||((ch>='0')&&(ch<='9'))) {token[m++]=ch; ch=prog[p++]; }
p--;
syn=10;
for(n=0;n<6;n++)
if(strcmp(token,rwtab[n])==0)
{ syn=n+1;
break; } }
else if((ch>='0')&&(ch<='9'))
{ while((ch>='0')&&(ch<='9'))
{ sum=sum*10+ch-'0';
ch=prog[p++]; }
p--;
syn=11; }
else switch(ch)
{ case '<':token[m++]=ch;
ch=prog[p++];
if(ch=='=')
p--; }
break;
case '>':token[m++]=ch; ch=prog[p++];
if(ch=='=')
{ syn=24;
token[m++]=ch; } else { syn=23;
p--; }
break;
case '+': token[m++]=ch; ch=prog[p++];
if(ch=='+')
{ syn=17;
token[m++]=ch; } else { syn=13;
p--; }
break;
case '-':token[m++]=ch; ch=prog[p++];
if(ch=='-')
{ syn=29;
token[m++]=ch; } else { syn=14;
p--; }
break;
case '!':ch=prog[p++];
if(ch=='=')
{ syn=21;
token[m++]=ch; } else { syn=31;
p--; }
{ syn=25;
token[m++]=ch; } else { syn=18;
p--; }
break;
case '*': syn=15; token[m++]=ch; break;
case '/': syn=16; token[m++]=ch; break;
case '(': syn=27; token[m++]=ch; break;
case ')': syn=28; token[m++]=ch; break;
case '{': syn=5; token[m++]=ch; break;
case '}': syn=6; token[m++]=ch; break;
case ';': syn=26; token[m++]=ch; break;
case '\"': syn=30; token[m++]=ch; break;
case '#': syn=0; token[m++]=ch;
default: syn=-1;
break; }
token[m++]='\0'; }
五、结果分析:
输⼊begin x:=9: if x>9 then x:=2*x+1/3; end # 后经词法分析输出如下序列:
(begin 1)(x 10)(:17)(= 18)(9 11)(;26)(if 2)……如图5-1所⽰:
图5-1
六、总结:
词法分析的基本任务是从字符串表⽰的源程序中识别出具有独⽴意义的单词符号,其基本思想是根据扫描到单词符号的第⼀个字符的种类,拼出相应的单词符号。
通过本试验的完成,更加加深了对词法分析原理的理解。
实验⼆语法分析
⼀、实验⽬的
编制⼀个递归下降程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析。
⼆、实验要求
利⽤C语⾔编制递归下降分析程序,并对简单语⾔进⾏语法分析。
2.1 待分析的简单语⾔的语法
⽤扩充的BNF表⽰如下:
⑴<程序>::=begin<语句串>end
⑵<语句串>::=<语句>{;<语句>}
⑶<语句>::=<赋值语句>
⑷<赋值语句>::=ID:=<表达式>
⑸<表达式>::=<项>{+<项> | -<项>}
⑹<项>::=<因⼦>{*<因⼦> | /<因⼦>
⑺<因⼦>::=ID | NUM | (<表达式>)
2.2 实验要求说明
输⼊单词串,以“#”结束,如果是⽂法正确的句⼦,则输出成功信息,打印“success”,否则输出“error”。
三、语法分析程序的算法思想
(1)主程序⽰意图如图2-1所⽰。
图2-1 语法分析主程序⽰意图
(2)递归下降分析程序⽰意图如图2-2所⽰。
图2-2 递归下降分析程序⽰意图图2-3语句串分析过程⽰意图
(4)statement语句分析程序流程如图2-4、2-5、2-6、2-7所⽰。
图2-4 statement语句分析函数⽰意图图2-5 expression表达式分析函数⽰意图
图2-6 term分析函数⽰意图图2-7 factor分析过程⽰意图四、语法分析程序的C语⾔程序源代码:#include "stdio.h"
#include "string.h"
char prog[100],token[8],ch;
char *rwtab[6]={"begin","if","then","while","do","end"};
int syn,p,m,n,sum;
int kk;
factor();
expression();
yucu();
term();
statement();
lrparser();
scaner();
main()
{
p=kk=0;
printf("\nplease input a string (end with '#'): \n");
do
{ scanf("%c",&ch);
prog[p++]=ch;
}while(ch!='#');
p=0;
lrparser();
getch();}
lrparser()
{
scaner(); /*读下⼀个单词符号*/
yucu(); /*调⽤yucu()函数;*/
if (syn==6)
{ scaner();
if ((syn==0)&&(kk==0))
printf("success!\n"); }
else { if(kk!=1) printf("the string haven't got a 'end'!\n");
kk=1; } }
else { printf("haven't got a 'begin'!\n");
kk=1; }
return;}
yucu()
{
statement(); /*调⽤函数statement();*/
while(syn==26)
{
scaner(); /*读下⼀个单词符号*/
if(syn!=6)
statement(); /*调⽤函数statement();*/ } return;}
statement()
{ if(syn==10)
{
scaner(); /*读下⼀个单词符号*/
if(syn==18)
{ scaner(); /*读下⼀个单词符号*/ expression(); /*调⽤函数statement();*/ } else { printf("the sing ':=' is wrong!\n");
kk=1; } }
else { printf("wrong sentence!\n");
kk=1; }
return;}
expression()
{ term();
term(); /*调⽤函数term();*/ }
term()
{ factor();
while((syn==15)||(syn==16))
{ scaner(); /*读下⼀个单词符号*/
factor(); /*调⽤函数factor(); */ }
return;}
factor()
{ if((syn==10)||(syn==11)) scaner();
else if(syn==27)
{ scaner(); /*读下⼀个单词符号*/
expression(); /*调⽤函数statement();*/
if(syn==28)
scaner(); /*读下⼀个单词符号*/
else { printf("the error on '('\n");
kk=1; } }
else { printf("the expression error!\n");
kk=1; }
return;}
scaner()
{ sum=0;
for(m=0;m<8;m++)token[m++]=NULL;
m=0;
ch=prog[p++];
while(ch==' ')ch=prog[p++];
if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A')))
{ while(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))||((ch>='0')&&(ch<='9'))) {token[m++]=ch; ch=prog[p++]; }
p--;
syn=10;
token[m++]='\0';
for(n=0;n<6;n++)
if(strcmp(token,rwtab[n])==0)
else if((ch>='0')&&(ch<='9')) { while((ch>='0')&&(ch<='9')) { sum=sum*10+ch-'0';
ch=prog[p++]; }
p--;
syn=11; }
else switch(ch)
{ case '<':m=0;
ch=prog[p++];
if(ch=='>')
{ syn=21; }
else if(ch=='=')
{ syn=22; }
else
{ syn=20;
p--; }
break;
case '>':m=0;
ch=prog[p++];
if(ch=='=')
{ syn=24; }
else
{ syn=23;
p--; }
break;
case ':':m=0;
ch=prog[p++];
if(ch=='=')
{ syn=18; }
else
{ syn=17;
p--; }
break;
case '*': syn=15;break;
case '/': syn=16;break;
case '(': syn=27;break;
case ')': syn=28;break;
case '=': syn=25;break;
case ';': syn=26;break;
case '#': syn=0;break;
default: syn=-1;break; } }
五、结果分析:
输⼊begin a:=9; x:=2*3; b:=a+x end # 后输出success!如图4-1所⽰:
图4-1
输⼊x:=a+b*c end # 后输出error 如图4-2所⽰:
图4-2
六、总结:
通过本次试验,了解了语法分析的运⾏过程,主程序⼤致流程为:“置初值”→调⽤scaner 函数读下⼀个单词符号→调⽤IrParse→结束。
递归下降分析的⼤致流程为:“先判断是否为begin”→不是则“出错处理”,若是则“调⽤scaner函数”→调⽤语句串分析函数→“判断是否为end”→不是则“出错处理”,若是则调⽤scaner函数→“判断syn=0&&kk=0是否成⽴”成⽴则说明分析成功打印出来。
不成⽴则“出错处理”。
实验三语义分析程序
⼀、实验⽬的:
通过上机实习,加深对语法制导翻译原理的理解,掌握将语法分析所识别的语法成分变换为中间代码的语义翻译⽅法。
⼆、实验要求:
采⽤递归下降语法制导翻译法,对算术表达式、赋值语句进⾏语义分析并⽣成四元式序列。
三、算法思想:
1、设置语义过程。
(1)emit(char *result,char *ag1,char *op,char *ag2)
该函数的功能是⽣成⼀个三地址语句送到四元式表中。
四元式表的结构如下:
struct
{ char result[8];
char ag1[8];
char op[8];
char ag2[8];
}quad[20];
(2) char *newtemp()
该函数回送⼀个新的临时变量名,临时变量名产⽣的顺序为T1,T2,…char *newtemp(void)
{ char *p;
char m[8];
p=(char *)malloc(8);
k++;
itoa(k,m,10);
strcpy(p+1,m);
p[0]=’t’;
return(p);
}
2、函数lrparser 在原来语法分析的基础上插⼊相应的语
义动作:将输⼊串翻译成四元式序列。
在实验中我们只对表达
式、赋值语句进⾏翻译。
四、源程序代码:
#include
#include
#include
#include
struct
{
char result[12];
char ag1[12];
char op[12];
char ag2[12];
}quad;
char prog[80],token[12];
char ch;
int syn,p,m=0,n,sum=0,kk; //p是缓冲区prog的指针,m是token的指针char *rwtab[6]={"begin","if","then","while","do","end"};
void scaner();
char *factor(void);
char *term(void);
char *expression(void);
int yucu();
void emit(char *result,char *ag1,char *op,char *ag2);
char *newtemp();
int statement();
int k=0;
void emit(char *result,char *ag1,char *op,char *ag2)
{
strcpy(quad.result,result);
strcpy(quad.ag1,ag1);
strcpy(quad.op,op);
strcpy(quad.ag2,ag2);
cout<
char *newtemp()
{
char *p;
char m[12];
p=(char *)malloc(12);
k++;
itoa(k,m,10);
strcpy(p+1,m);
p[0]='t';
return (p);
}
void scaner()
{
for(n=0;n<8;n++) token[n]=NULL;
ch=prog[p++];
while(ch==' ')
{
ch=prog[p];
p++;
}
if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
{
m=0;
while((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
{
token[m++]=ch;
ch=prog[p++]; }
token[m++]='\0';
p--;
syn=10;
for(n=0;n<6;n++)
if(strcmp(token,rwtab[n])==0) {
syn=n+1;
break; } }
else if((ch>='0'&&ch<='9'))
{
{
sum=0;
while((ch>='0'&&ch<='9'))
{
sum=sum*10+ch-'0';
ch=prog[p++]; } }
p--;
syn=11;
if(sum>32767)
syn=-1; }
else switch(ch)
{
case'<':m=0;token[m++]=ch;
ch=prog[p++];
if(ch=='>')
{
syn=21;
token[m++]=ch; } else if(ch=='=') {
syn=22;
token[m++]=ch; } else
{
syn=23;
p--; }
break;
case'>':m=0;token[m++]=ch;
ch=prog[p++];
if(ch=='=')
{
syn=24;
token[m++]=ch; } else
{
syn=20;
p--; }
break;
case':':m=0;token[m++]=ch;
ch=prog[p++];
if(ch=='=')
{
syn=18;
token[m++]=ch; } else
{
syn=17;
p--; }
break;
case'*':syn=13;token[0]=ch;break; case'/':syn=14;token[0]=ch;break; case'+':syn=15;token[0]=ch;break; case'-':syn=16;token[0]=ch;break; case'=':syn=25;token[0]=ch;break; case';':syn=26;token[0]=ch;break; case'(':syn=27;token[0]=ch;break; case')':syn=28;token[0]=ch;break; case'#':syn=0;token[0]=ch;break; default: syn=-1;break; }}
int lrparser()
{//cout<<"调⽤lrparser"<
int schain=0;
kk=0;
if(syn==1)
{
scaner();
schain=yucu();
if(syn==6)
{
scaner();
if(syn==0 && (kk==0)) cout<<"success!"<
{
if(kk!=1)
cout<<"缺end!"<
kk=1; } }
else
{cout<<"缺begin!"< return(schain);}
int yucu()
{// cout<<"调⽤yucu"<
int schain=0;
schain=statement(); while(syn==26)
{
scaner();
schain=statement(); } return(schain);}
int statement()
{//cout<<"调⽤statement"< char *eplace,*tt;
eplace=(char *)malloc(12); tt=(char *)malloc(12);
int schain=0;
switch(syn)
{
case 10:
strcpy(tt,token);
scaner();
if(syn==18)
{
scaner();
strcpy(eplace,expression()); emit(tt,eplace,"",""); schain=0; }
else
{
cout<<"缺少赋值符!"<
kk=1; }
return(schain);
break; }
return(schain);}
char *expression(void)。