kl800.com省心范文网

陈朔鹰版编译原理词法分析实验报告.doc


为中华人民之崛起而读书

日期:2013 年 5 月 9 日
一. 实验目的
1.理解并掌握正规文法、正规式、有限自动机之间的内在联系及相互转换原 理; 2.学会如何使用 Visual C++等高级语言编程实现上述转换关系; 3.以四则混合运算表达式为例,编写词法分析程序; 4.通过实验,理解模块化程序设计思想,从全局角度领会一个完整软件的设 计精髓,为后续实验的顺利完成奠定坚实的基础。

二.实验仪器与设备
微型电子计算机(PC 机) 配置 Windows XP 及以上版本操作系统 安装 Visual C++6.0 或 Visual C#2002010 或 Delphi6.0 等以上版本的开发 环境

二. 实验内容与步骤
1. 已知正整数的四则运算的表达式的状态转换图如右图所示,要求编写相 应词法分析程序,以识别符号串:((23+12)*9-200)/5 最终输出单词流。 、 注:能识别 0、5、13、342 等形式的整数,但可以将形如 067 的数据识别为 2 个数值:0、67。

1

为中华人民之崛起而读书

流程图:
开始 接受输入字符串 是 是否为字符串尾 否 按位字符判断 否 是否为有效输入 是 进入自动机 判断结果 结束

一. 正则文法
设 a:0-9 b:1-9 c:?|其他
2

为中华人民之崛起而读书 文法 G=( Vn , Yt , S , P ); 其中:Vn={?,①}; Vt={②,③,④,⑤,⑥,⑦,⑧,⑨}; S=0; P:?→0②;?→b①; ①→a①;①→c②; ?→'('③;?→')'④;?→'+'⑤;?→'-'⑥;?→' *'⑦;?→'/'⑧;?→'c'⑨

二. 正则表达式
设 a:0-9 b:0 c:1-9 d:?|其他 e:{‘(’,’)’,’+’,’-’,’*’,’/’}

三. 词法分析程序
类定义
// StringLEX.h: interface for the CLEXExpression class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_STRINGLEX_H__1AB7E0B1_0076_4937_B0C2_8DCE5160DB82__INCLUDED_) #define AFX_STRINGLEX_H__1AB7E0B1_0076_4937_B0C2_8DCE5160DB82__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #pragma warning(disable:4786)//屏蔽“由于 string 和 vector 等 STL 模版产生很长的标识符 而引起的警告信息” #include<iostream> #include<iomanip> #include<string>
3

为中华人民之崛起而读书
//#include<vector> using namespace std; struct SignProperty { // 属性字 int SignKind; // 单词种别 /* 设置单词种别: (可根据需要自行规定)1:分隔符 2:操作数 3:运算符*/ string SignValue; // 单词值 }; class CLEXExpression { public: CLEXExpression(); virtual ~CLEXExpression(); public: void SetSourceString(string str);// 设置源串 SignProperty GetToken(); // 识别单词,返回属性字 string GetRestString(); // 返回剩余串 private: char nextchar(); void untread(); private: int pos; string proBuffer; string restString; // 读取下一个字符 // 回退一个字符 // 指针 // 待分析的源串 // 分析后的剩余串

}; #endif // !defined(AFX_STRINGLEX_H__1AB7E0B1_0076_4937_B0C2_8DCE5160DB82__INCLUDED_)

类实现
// StringLEX.cpp: implementation of the CLEXExpression class. // ////////////////////////////////////////////////////////////////////// #include "LEXExpression.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CLEXExpression::CLEXExpression(){ proBuffer = ""; restString = ""; } CLEXExpression::~CLEXExpression(){} // 读一个字符: char CLEXExpression::nextchar(){ if(pos+1<proBuffer.length()) // 若符号尚未读完
4

为中华人民之崛起而读书
return proBuffer[++pos]; else return '\0'; } // 回退一个字符: void CLEXExpression::untread(){ --pos; } // 返回剩余串: string CLEXExpression::GetRestString(){ return restString; } // 词法分析,返回一个单词属性字: SignProperty CLEXExpression::GetToken(){ SignProperty Token; // 属性字变量 Token.SignKind = -1; Token.SignValue = ""; if(proBuffer.empty()) // 若待分析串为空,则直接返回: return Token; //(1)初始化 pos=-1; int state=0; char char1; bool Flag1=true; //(2) while(Flag1){ switch(state){ case 0: char1 = nextchar(); // 读入一个字符 if(char1>='1'&&char1<='9') state = 1; else if(char1=='0') state = 2; else{ switch (char1){ case '(': state = 3; break; case ')': state = 4; break; case '+': state = 5; break; case '-':
5

// 若已读完

为中华人民之崛起而读书
state = 6; break; case '*': state = 7; break; case '/': state = 8; break; default: state = 9;} } break; case 1: do{ char1 = nextchar(); // 读入一个字符 }while(char1>='0'&&char1<='9'); // 输入字符为数字:0 ~ 9 state = 2; // 若为其他字符,则转到状态 2 break; case 2: if(char1!='\0'&&char1!='0') // 如果读入其他符号,则 untread(); // 回退一个已读进的字符 Token.SignKind = 2; // 2:操作数 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break; case 3: Token.SignKind = 1; // 1:分隔符 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break; case 4: Token.SignKind = 1; // 1:分隔符 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break; case 5: Token.SignKind = 3; // 3:运算符 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break; case 6: Token.SignKind = 3; // 3:运算符 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break;
6

为中华人民之崛起而读书
case 7: Token.SignKind = 3; // 3:运算符 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break; case 8 : Token.SignKind = 3; // 3:运算符 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break; case 9: untread(); cout<<"警告:读入了非法符号!"<<endl; Flag1=false; break;} } // 保留剩余串: if(proBuffer.length()-pos-1>=0) restString= proBuffer.substr(pos+1,proBuffer.length()-pos-1); else restString=""; return Token; } void CLEXExpression::SetSourceString(string str){ proBuffer = str; restString = str; }

主函数
#include "LEXExpression.h" // 显示单词(属性字格式) void DisplayToken(SignProperty token){ if(token.SignKind!=-1) {// 若无错误,则显示: string temp; cout<<"( "<<setw(6)<<left<<token.SignValue<<","; if(token.SignKind==1) temp="分隔符"; else if(token.SignKind==2) temp="操作数"; else if(token.SignKind==3) temp="运算符"; else if(token.SignKind==4) temp="界符";
7

为中华人民之崛起而读书
else temp=""; cout<<setw(8)<<left<<temp<<")"<<endl; } } // 主函数: void main(){ CLEXExpression CSL1; string temp1="((23+12)*9-200)/5"; // string temp1="01"; do{ CSL1.SetSourceString(temp1); SignProperty temp2=CSL1.GetToken(); if(temp2.SignKind==-1) // 若有错误,则退出: break ; DisplayToken(temp2); temp1=CSL1.GetRestString(); // 返回剩余串,以继续识别 }while(!temp1.empty()); }

运行结果:

四. 思考题
上面考察的是无符号整数。若改为无符号实数,将如何修改你的程序? 下面是基于无符号实数的表达式文法的状态转换图:

8

为中华人民之崛起而读书

若要修改程序,只需修改上面代码的一部分就可以,修改 SignProperty CLEXExpression::GetToken()函数中的内容如下:
SignProperty CLEXExpression::GetToken(){ SignProperty Token; // 属性字变量 Token.SignKind = -1; Token.SignValue = ""; if(proBuffer.empty()) // 若待分析串为空,则直接返回: return Token; //**************************** char*vPath=new char[20]; int vpp=-1; int length=0; //**************************** //(1)初始化 pos=-1; int state=0; char char1; bool Flag1=true; //(2) while(Flag1){ switch(state){ case 0: char1 = nextchar(); // 读入一个字符 if(char1>='1'&&char1<='9'){ vPath[++vpp]='0'; state = 1; } else if(char1=='0'){ vPath[++vpp]='0';
9

为中华人民之崛起而读书
state = 2; //char1 = nextchar(); } else{ switch (char1){ case '(': state = 6; break; case ')': state = 7; break; case '+': state = 8; break; case '-': state = 9; break; case '*': state = 10; break; case '/': state = 11; break; default: state = 12;}} break; case 1: vPath[++vpp]='1'; do{ char1 = nextchar(); // 读入一个字符 }while(char1>='0'&&char1<='9'); // 输入字符为数字:0 ~ 9 if(char1=='.') state=3; else state = 5; // 若为其他字符,则转到状态 5 break; case 2: vPath[++vpp]='2'; char1 = nextchar(); if(char1=='.') state=3; else if(char1>='0'&&char1<='9') state=12; else state=5; break; case 3: vPath[++vpp]='3';
10

为中华人民之崛起而读书
char1 = nextchar(); if(char1>='0'&&char1<='9') state=4; else state=12; break; case 4: while(char1>='0'&&char1<='9'){ // 输入字符为数字:0 ~ 9 char1 = nextchar(); // 读入一个字符 } state=5; break; case 5: if(char1!='\0'&&char1!='0') // 如果读入其他符号,则 untread(); // 回退一个已读进的字符 Token.SignKind = 2; // 2:操作数 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break; case 6: Token.SignKind = 1; // 1:分隔符 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break; case 7: Token.SignKind = 1; // 1:分隔符 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break; case 8: Token.SignKind = 3; // 3:运算符 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break; case 9: Token.SignKind = 3; // 3:运算符 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break; case 10: Token.SignKind = 3; // 3:运算符 Token.SignValue = proBuffer.substr(0,pos+1);
11

为中华人民之崛起而读书
Flag1=false; break; case 11 : Token.SignKind = 3; // 3:运算符 Token.SignValue = proBuffer.substr(0,pos+1); Flag1=false; break; case 12: untread(); vPath[++vpp]='\0'; //cout<<vPath[0]<<vPath[1]<<vPath[2]<<endl; if(vPath[0]='0'){ if((vPath[1]=='2'&&vPath[2]=='3')||(vPath[1]=='1'&&vPath[2]=='3')){ cout<<"无法识别的小数!! !!"<<endl; OutputError(); } if((vPath[1]=='2'&&vPath[2]=='\0')){ do{ char1 = nextchar(); // 读入一个字符 }while(char1>='0'&&char1<='9'); untread(); cout<<"无法识别的整数!!"<<endl; ! OutputError(); } } else cout<<"警告:读入了非法符号!"<<endl; Flag1=false; break; } }

识别表达式((23.4343+12.342)*9.9-0.32)/5 结果如下:

12

为中华人民之崛起而读书

13


赞助商链接