编译原理实验报告-合肥工业大学版

更新时间:2023-07-24 10:18:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

编译原理实验报告

合肥工业大学计算机科学与技术

完成日期:2013.6.3

实验一 词法分析设计

一、实验功能:

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

对输入的txt文件内的内容进行词法分析: 由文件流输入test.txt中的内容, 对文件中的各类字符进行词法分析 打印出分析后的结果;

二、程序结构描述:(源代码见附录)

1、利用Key[]进行构造并存储关键字表;利用optr[]进行构造并存储运算符表;利用separator[]进行构造并存储分界符表;

2、bool IsKey(string ss) {}判断是否是关键字函数若是关键字返回true,否则返回false;

bool IsLetter(char c) {}判断当前字符是否字母,若是返回true,否则返回false;

bool IsDigit(char c) {}判断当前字符是否是数字,若是返回true,否则返回false;

bool IsOptr(string ss) {}判断当前字符是否是运算符,若是返回true,否则返回false; bool IsSeparator(string ss) {}判断当前字符是否是分界符,若是返回true,否则返回false; void analyse(ifstream &in) {}分析函数构造; 关系运算符通过switch来进行判断;

三、实验结果

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

实验总结:

词法分析的程序是自己亲手做的,在实现各个函数时花了不少功夫,

1、要考虑到什么时候该退一字符,否则将会导致字符漏读甚至造成字符重复读取。

2、在实现行数和列数打印时要考虑到row++和line++应该放在什么位置上才可以,如当读取一个\n时line要增加一,而row需要归0处理,在读取某一字符串或字符后row需要加一;

3、对于关系运算符用switch结构进行选择判断即可解决一个字符和两个字符的运算符之间的差异;

4、将自己学过的知识应用到实践中是件不怎么容易的事情,只有亲身尝试将知识转化成程序才能避免眼高手低,对于知识的理解也必将更加深刻。

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

实验二 LL(1)分析法

一、实验原理: 1、写出

LL(1)分析法的思想:当一个文法满足LL(1)条件时,我们就可以

为它构造一个不带回溯的自上而下的分析程序,这个分析程序是有一组递归过程组成的,每个过程对应文法的一个非终结符。实现LL(1)分析的一种有效的方法是使用一张分析表和一个站进行联合控制。预测分析表是一个M[A,a]形式的矩阵,存储着分析规则;栈STACK用于存放文法符号。从栈顶取符号,按照分析表给出的规则进行有步骤的分析。 2.实验要求实现的文法: (1)E->TG (2)G->+TG|—TG (3)G->ε (4)T->FS (5)S->*FS|/FS (6)S->ε (7)F->(E) (8)F->i

二、程序结构:

各个模块:

(1)定义部分:定义常量、变量、数据结构。

(2)初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等);

(3)控制部分:从键盘输入一个表达式符号串;

(4)利用LL(1)分析算法进行表达式处理:根据LL(1)分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示错误信息。

程序各个部分的实现:

(1)Vn[]存储非终结符数组; Vt[]存储终结符数组;

char strToken[Length];//存储规约表达式

struct LL//ll(1){char *c}分析表的构造字初始化

Class stack实现栈的要求功能:初始化,判断空满,入栈出栈等;

Run()函数实现LL(1)文法分析的函数:先将表达式字符入栈,#最先入栈底,依次取栈顶

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

符号,查和符号栈和分析表,进行相应的操作。

三、实验结果:

测试方法:运行程序,输入需要分析的语句 测试结果如下:

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

四、实验总结:

1、出现下列两种情况说明遇到了语法错误: (1)栈顶的终结符与当前的输入符号不匹配。

(2)非终结符A处于栈顶,面临输入符号为a,但分析表M中M[A,a]为空。发现错误后要尽快的从错误中恢复过来使分析能继续进行下去。

2、对于符号的入栈出栈,哪个应该先入栈,栈顶是哪个元素需要搞清楚,不然得到的结果肯定不对。

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

实验三 LR(1)分析法

一实验原理

LR(1)分析法实验设计思想及算法

(1)总控程序,也可以称为驱动程序。对所有的LR分析器总控程序都是相同的。 (2)分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。

(3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。 分析器的动作就是由栈顶状态和当前输入符号所决定。

二、程序结构

LR分析器由三个部分组成:

其中:SP为栈指针,S[i]为状态栈,X[i]为文法符号栈。状态转换表用GOTO[i,X]=j表示,规定当栈顶状态为i,遇到当前文法符号为X时应转向状态j,X为终结符或非终结符。

ACTION[i,a]规定了栈顶状态为i时遇到输入符号a应执行。动作有四种可能:

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

(1)移进:

action[i,a]= Sj:状态j移入到状态栈,把a移入到文法符号栈,其中i,j表示状态号。 (2)归约:

action[i,a]=rk:当在栈顶形成句柄时,则归约为相应的非终结符A,即文法中有A- B的产生式,若B的长度为R(即|B|=R),则从状态栈和文法符号栈中自顶向下去掉R个符号,即栈指针SP减去R,并把A移入文法符号栈内,j=GOTO[i,A]移进状态栈,其中i为修改指针后的栈顶状态。 (3)接受acc:

当归约到文法符号栈中只剩文法的开始符号S时,并且输入符号串已结束即当前输入符是'#',则为分析成功。 (4)报错:

当遇到状态栈顶为某一状态下出现不该遇到的文法符号时,则报错,说明输入端不是该文法能接受的符号串。

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

三、实验结果:

程序测试:输入需要规约的字符串 测试结果:

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

四、实验总结

1、与算符优先分析方法比较,用LR分析时,设计特定出错处理子程序比较容易,因为不会发生不正确的归约。在分析表的每一个空项内,可以填入一个指示器,指向特定的出错处理子程序,第一类错误的处理一般采用插入、删除或修改的办法,但要注意,不能从栈内移去任何那种状态,它代表已成功地分析了程序中的某一部分。

2、LR分析法的归约过程是规范推导的逆过程,所以LR分析过程是一种规范归约过程。LR分析法正是给出一种能根据当前分析栈中的符号串(通常以状态表示)和向右顺序查看输入串的K个(K≥0)符号就可唯一地确定分析器的动作是移进还是归约和用哪个产生式归约,因而也就能唯一地确定句柄。其中LR(0)分析器是在分析过程中不需向右查看输入符号,因而它对文法的限制较大,然而,它是构造其它LR类分析器的基础。因此,首先应学好LR(0)项目集规范族构造的基本原理和方法。当K=1时,已能满足当前绝大多数高级语言编译程序实现的需要。SLR(1)分析是为学习LR(1)分析做准备,LR(1)项目集族的构造是LALR(1)分析器的构造原理和基础。LALR(1) 分析器是当前大多数高级程序设计语言编译程序所采用的语法分析技术,也是编译程序语法分析器自动构造工具YACC的实现基本原理。由此,LR(0)、SLR(1)、LALR(1)、LR(1)四种分析器的构造方法都必须深入理解和掌握。

3、经过以上三个实验的锤炼,不得不说自己编译原理这门课的认识又提高了一个阶层,对编译原理的知识运用更加深入,编写过程中遇到不少的问题,结合课本及强大的网络资源,在完成的过程中得到很多收获,不仅来自于对知识点的了解更加深入,更是对自己编程能力的一次很好的锻炼,希望有更多这样实验的机会。

4、本人很希望在完成实验后,老师可以根据自己讲的课本,将自己所写的程序花一段时间来讲解,我想这样会对不会编写的是一种教学,对会了的同学是一种榜样效应,可以让我们有个目标追求,这样我们收获了的也会更加准确与丰富。

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

附录:

实验一源代码:

#include<iostream> #include<fstream> #include<string> using namespace std;

string key[8]={"do","end","for","if","printf","scanf","then","while"}; string optr[4]={"+","-","*","/"};

string separator[6]={",",";","{","}","(",")"}; char ch;

//判断是否为保留字 bool IsKey(string ss) { int i; for(i=0;i<8;i++)

if(!strcmp(key[i].c_str(),ss.c_str())) return true; return false; }

//字母判断函数

bool IsLetter(char c) { if(((c>='a')&&(c<='z'))||((c>='A')&&(c<='Z'))) return true; return false; }

//数字判断函数

bool IsDigit(char c) { if(c>='0'&&c<='9') return true; return false; }

//运算符判断函数

bool IsOptr(string ss) { int i; for(i=0;i<4;i++)

if(!strcmp(optr[i].c_str(),ss.c_str())) return true ;

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

return false; }

//分界符判断函数

bool IsSeparator(string ss) { int i; for(i=0;i<6;i++)

if(!strcmp(separator[i].c_str(),ss.c_str())) return true; return false; }

void analyse(ifstream &in) { string st=""; char ch; int line=1,row=0; while((in.get(ch))) { st=""; if((ch==' ')||(ch=='\t')){} //空格,tab健 else if(ch=='\n') {line++;row=0; } //换行行数加一处理 else if(IsLetter(ch)) //关键字、标识符的处理 {

row++; while(IsLetter(ch)||IsDigit(ch)) {

st+=ch; in.get(ch); } in.seekg(-1,ios::cur);//文件指针(光标)后退一个字节 if(IsKey(st)) //判断是否为关键字 查询关键字表; cout<<st<<"\t("<<st<<","<<1<<")"<<'\t'<<'\t'<<""<<'\t'<<"("<<line<<","<<row<<")"<<endl; else //否则为标示符

cout<<st<<"\t("<<st<<","<<2<<")"<<'\t'<<'\t'<<""<<'\t'<<"("<<line<<","<<row<<")"<<endl; }

else

if(IsDigit(ch)) //无符号整数处理 {

关键标识字

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

row++; while(IsDigit(ch)) {st+=ch; ch=in.get(); } in.seekg(-1,ios::cur); cout<<st<<"\t("<<st<<","<<3<<")"<<'\t'<<'\t'<<"常数"<<'\t'<<"("<<line<<","<<row<<")"<<endl; // break; } else {st=""; st+=ch; if(IsOptr(st)) //运算符处理 { row++; cout<<st<<"\t("<<st<<","<<4<<")"<<'\t'<<'\t'<<"运算符"<<"("<<line<<","<<row<<")"<<endl;

} else

if(IsSeparator(st))//分隔符处理 { row++;

cout<<st<<"\t("<<st<<","<<5<<")"<<'\t'<<'\t'<<"分界符"<<'\t'<<"("<<line<<","<<row<<")"<<endl; }

else{ switch(ch){row++;

case'=' : {row++;cout<<"="<<"\t("<<"="<<","<<"6"<<")"<<'\t'<<"\t关系运算符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;} case'>' :{row++;ch=in.get(); if(ch=='=')

cout<<">="<<'\t'<<"("<<">="<<","<<"6"<<")"<<'\t'<<"\t关系运算符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;

else {cout<<">"<<"\t("<<">"<<","<<"6"<<")"<<'\t'<<"\t关系运算符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;

in.seekg(-1,ios::cur);} } break;

case'<' :{row++;ch=in.get();

if(ch=='=')cout<<"<="<<'\t'<<"("<<"="<<","<<"6"<<")"<<"\t关系运算符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

else if(ch=='>') cout<<"<>"<<'\t'<<"("<<"<>"<<","<<"6"<<")"<<'\t'<<"\t关系运算符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;

else{cout<<"<"<<"\t("<<"<"<<","<<"6"<<")"<<"\t"<<"\t关系运算符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;

in.seekg(-1,ios::cur);} }break; default :{row++; cout<<ch<<'\t'<<"\t$无法识别字符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;} } }} } }

int main() { ifstream in; in.open("test.txt",ios::in); cout<<"关键字1 标识符2 常数3 运算符4 分隔符5关系运算符6"<<endl; if(in.is_open()) { analyse(in); in.close();

system("pause"); } else

cout<<"文件操作出错"<<endl; }

实验二源代码:

#include<iostream> using namespace std;

const int MaxLen=20; //初始化栈的长度 const int Length=20;//初始化数组长度

char Vn[5]={'E','G','T','S','F'};//非终结符数组 char Vt[8]={'i','(',')','+','-','*','/','#'};//终结符数组

char ch,X;//ch读当前字符,X获取栈顶元素 char strToken[Length];//存储规约表达式

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

struct LL//ll(1)分析表的构造字初始化 {

char*c; };

LL E[8]={"TG","TG","error","error","error","error","error","error"}; LL G[8]={"error","error","null","+TG","-TG","error","error","null"}; LL T[8]={"FS","FS","error","error","error","error","error","error"}; LL S[8]={"error","error","null","null","null","*FS","/FS","null"}; LL F[8]={"i","(E)","error","error","error","error","error","error"};

class stack//栈的构造及初始化 {

public:

stack();//初始化

bool empty() const;//是否为空 bool full() const;//是否已满

bool get_top(char &c)const;//取栈顶元素 bool push(const char c);//入栈 bool pop();//删除栈顶元素 void out();//输出栈中元素 ~stack(){}//析构 private:

int count;//栈长度

char data[MaxLen];//栈中元素 };

stack::stack() {

count=0; }

bool stack::empty() const {

if(count==0) return true; return false; }

bool stack::full() const {

if(count==MaxLen) return true; return false; }

bool stack::get_top(char &c)const {

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

if(empty()) return false; else {

c=data[count-1]; return true; } }

bool stack::push(const char c) {

if(full()) return false;

data[count++]=c; return true; }

bool stack::pop() {

if(empty()) return false; count--; return true; }

void stack::out() {

for(int i=0;i<count;i++) cout<<data[i]; cout<<'\t'; }

int length(char *c) {

int l=0;

for(int i=0;c[i]!='\0';i++) l++; return l; }

void print(int i,char*c)//剩余输入串的输出 {

for(int j=i;j<Length;j++) cout<<c[j]; cout<<'\t';

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

}

void run() {

bool flag=true;//循环条件

int step=0,point=0;//步骤、指针 int len;//长度

cout<<"输入规约的字符串:"<<endl; cin>>strToken;

ch=strToken[point++];//读取第一个字符 stack s;

s.push('#');//栈中数据初始化 s.push('E');

s.get_top(X);//取栈顶元素

cout<<"步骤\t"<<"分析栈\t"<<"剩余输入串\t\t"<<"所用产生式\t"<<"动作"<<endl; cout<<step++<<'\t'; s.out();

print(point-1,strToken);

cout<<'\t'<<"初始化"<<endl; while(flag) {

if((X==Vt[0])||(X==Vt[1])||(X==Vt[2])||(X==Vt[3])||(X==Vt[4])||(X==Vt[5])||(X==Vt[6])) //判断是否为终结符(不包括#) {

if(X==ch)//终结符,识别,进行下一字符规约 {

s.pop();

s.get_top(X);

ch=strToken[point++]; cout<<step++<<'\t'; s.out();

print(point-1,strToken);

cout<<'\t'<<"GETNEXT(I)"<<endl; } else {

flag=false; } }

else if(X=='#')//规约结束 {

if(X==ch) {

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

cout<<step++<<'\t'; s.out();

print(point-1,strToken);

cout<<X<<"->"<<ch<<'\t'<<"结束"<<endl; s.pop(); flag=false; } else {

flag=false; } }

else if(X==Vn[0]) //非终结符E {

for(int i=0;i<8;i++)//查分析表 if(ch==Vt[i]) {

if(strcmp(E[i].c,"error")==0)//出错 {

flag=false; }

else{ //对形如 X->X1X2的产生式进行入栈操作 s.pop();

len=length(E[i].c)-1; for(int j=len;j>=0;j--) s.push(E[i].c[j]); cout<<step++<<'\t'; s.out();

print(point-1,strToken);

cout<<X<<"->"<<E[i].c<<'\t'<<"POP,PUSH("; for(int j=len;j>=0;j--) cout<<E[i].c[j]; cout<<")"<<endl; s.get_top(X); } } }

else if(X==Vn[1]) //同上,处理 G {

for(int i=0;i<8;i++) if(ch==Vt[i]) {

if(strcmp(G[i].c,"null")==0) {

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

s.pop();

cout<<step++<<'\t'; s.out();

print(point-1,strToken);

cout<<X<<"->"<<"ε"<<'\t'<<"POP"<<endl; s.get_top(X); }

else if(strcmp(G[i].c,"error")==0) {

flag=false; } else{

s.pop();

len=length(G[i].c)-1; for(int j=len;j>=0;j--) s.push(G[i].c[j]); cout<<step++<<'\t'; s.out();

print(point-1,strToken);

cout<<X<<"->"<<G[i].c<<'\t'<<"POP,PUSH("; for(int j=len;j>=0;j--) cout<<G[i].c[j]; cout<<")"<<endl; s.get_top(X); } } }

else if(X==Vn[2]) //同上 处理 T {

for(int i=0;i<8;i++) if(ch==Vt[i]) {

if(strcmp(T[i].c,"error")==0) {

flag=false; } else{

s.pop();

len=length(T[i].c)-1; for(int j=len;j>=0;j--) s.push(T[i].c[j]); cout<<step++<<'\t'; s.out();

print(point-1,strToken);

合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,

cout<<X<<"->"<<T[i].c<<'\t'<<"POP,PUSH("; for(int j=len;j>=0;j--) cout<<T[i].c[j]; cout<<")"<<endl; s.get_top(X); } } }

else if(X==Vn[3])//同上 处理 S {

for(int i=0;i<8;i++) if(ch==Vt[i]) {

if(strcmp(S[i].c,"null")==0) {

s.pop();

cout<<step++<<'\t'; s.out();

print(point-1,strToken);

cout<<X<<"->"<<"ε"<<'\t'<<"POP"<<endl; s.get_top(X); }

else if(strcmp(S[i].c,"error")==0) {

flag=false; } else{

s.pop();

len=length(S[i].c)-1; for(int j=len;j>=0;j--) s.push(S[i].c[j]); cout<<step++<<'\t'; s.out();

print(point-1,strToken);

cout<<X<<"->"<<S[i].c<<'\t'<<"POP,PUSH("; for(int j=len;j>=0;j--) cout<<S[i].c[j]; cout<<")"<<endl; s.get_top(X); } } }

else if(X==Vn[4]) //同上 处理 F {

本文来源:https://www.bwwdw.com/article/n9nm.html

Top