【编译原理】实验一 词法分析器设计与实现

实验类型: 设计性   实验学时: 2   实验要求:必修

一、实验目的

设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。

二、实验内容

2.1 待分析的简单的词法

(1)关键字:

begin  if  then  while  do  end

所有的关键字都是小写。

(2)运算符和界符

: =  +  -  *  /  <  <=  <>  >  >=  =  ; (  )  #

(3)其他单词是标识符【编译原理】实验一 词法分析器设计与实现和整型常数【编译原理】实验一 词法分析器设计与实现,通过以下正规式定义:

【编译原理】实验一 词法分析器设计与实现

【编译原理】实验一 词法分析器设计与实现

(4)空格有空白、制表符和换行符组成。空格一般用来分隔【编译原理】实验一 词法分析器设计与实现【编译原理】实验一 词法分析器设计与实现、运算符、界符和关键字,词法分析阶段通常被忽略。

2.2 各种单词符号对应的种别码:

                                   表2.1 各种单词符号对应的种别码

单词符号

种别码

单词符号

种别码

begin

1

:

17

if

2

:

18

then

3

<

20

while

4

<>

21

do

5

<=

22

end

6

>

23

letter (letter|digit)*

10

>=

24

digit digit*

11

=

25

+

13

;

26

-

14

(

27

*

15

)

28

/

16

#

0

2.3 词法分析程序的功能:

输入:所给文法的源程序字符串。

输出:二元组(【编译原理】实验一 词法分析器设计与实现,【编译原理】实验一 词法分析器设计与实现【编译原理】实验一 词法分析器设计与实现)构成的序列。

其中:【编译原理】实验一 词法分析器设计与实现为单词种别码;

      【编译原理】实验一 词法分析器设计与实现为存放的单词自身字符串;

      【编译原理】实验一 词法分析器设计与实现为整型常数。

例如:对源程序

begin x:=9: if x>9 then x:=2*x+1/3; end #

的源文件,经过词法分析后输出如下序列:

(1,begin)
(10,x)
(18,:=)
(11,9)
(26,;)
(2,if)
……

三、仪器设备

计算机,C++6.0软件环境。

四、所需耗材

五、实验原理、方法和手段

算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。

5.1 主程序示意图:

主程序示意图如图3-1所示。其中初始包括以下两个方面:

⑴ 关键字表的初值。

关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。如能查到匹配的单词,则该单词为关键字,否则为一般标识符。关键字表为一个字符串数组,其描述如下:

Char *rwtab[6] = {“begin”, “if”, “then”, “while”, “do”, “end”};

【编译原理】实验一 词法分析器设计与实现

 

 

(2)程序中需要用到的主要变量为【编译原理】实验一 词法分析器设计与实现,【编译原理】实验一 词法分析器设计与实现【编译原理】实验一 词法分析器设计与实现

3.2 扫描子程序的算法思想:

首先设置3个变量:①【编译原理】实验一 词法分析器设计与实现用来存放构成单词符号的字符串;②【编译原理】实验一 词法分析器设计与实现用来整型单词;③【编译原理】实验一 词法分析器设计与实现用来存放单词符号的种别码。扫描子程序主要部分流程如图3-2所示。

【编译原理】实验一 词法分析器设计与实现

六、实验步骤

阅读实验说明,做好实验准备,然后进行编辑调试。

七、实验结果处理

演示结果并保存相关文件。

八、实验注意事项

注意数据变量类型,单词组输出格式。

九、预习与思考题

预习:阅读课本相关内容,分析相关算法设计思想,熟悉VC++6.0使用方式。

思考题:类C语言程序的词法分析。

十、实验报告要求

1、实验报告中应包括相关操作步骤和程序代码,。

2.书写实验报告时要结构合理,层次分明,在分析描述的时候,需要注意语言的流畅。

实现代码

/*
未添加功能:1、符号表和常数表的构建
*/
#include<iostream>
#include<string>
#include<fstream>
#include<windows.h> 
using namespace std;
#define MAXROW 100
string ReservedWordList[6]={"begin","if","then","while","do","end"};//关键字表 
//声明全局变量 
string ScanBuffer[MAXROW];//扫描缓冲区,定义为字符串数组
int row=0,col=0;//搜索指示器,row指行,col指列 
int endrow;
char ch;//搜索指示器指示的当前字符 
string strToken;//当前字符串 
//声明全局函数 
void Input();//子程序过程,将源代码输入进扫描缓冲区 
void GetChar();//子过程程序,将下一输入字符读到ch中,搜索指示器前移一字符位置 
void GetDel();//子程序过程,检查ch中的字符是否为分隔符。若是,则调用GetChar直至ch中进入一个非分隔符(delimiters->分隔符) 
void Concat();//子程序过程,,将ch中的字符连接到strToken之后 
bool IsLetter();//布尔函数过程,判断ch中的字符是否为字母 
bool IsDigit();//布尔函数构成,判断ch中的字符是否为数字 
int Reserve();//整型函数过程,对strToken中的字符串查找保留字表,若它是一个保留字则返回它的编码,否则返回0值(假定0不是保留字的编码)
void Retract();//子程序过程,将搜索指示器回调一个字符位置,将ch置为空白字符 
int InsertID();//整型函数过程,将strToken中的标识符插入符号表,返回符号表指针 
int InsertConst();//整型函数过程,将strToken中的常数插入常数表,返回常数表指针
void ProcError();//子程序过程,词法分析出错,提示错误信息 
//定义函数
void Input(){
	int op;
	cout<<"请输入数字选择输入格式"<<endl;
	cout<<"1,键盘输入"<<endl<<"2,文件输入"<<endl;
	cin>>op;
	int i=0;
	char c;//输入流中的当前字符 
	if(op==1){
		while((c=cin.get())!=EOF){
			ScanBuffer[i].push_back(c);
			if(c=='\n') i++;
		}
		endrow=--i;
	}
	else{
		fstream in;
		in.open("test.txt",ios::in);
		while(in.peek()!=EOF){
			c=in.get();
			ScanBuffer[i].push_back(c);
			if(c=='\n') i++;
		}
		endrow=--i;
	}
} 
void GetChar(){
	ch=ScanBuffer[row][col];
	col++;
} 
void GetDel(){
	while(ch=='\n'){
		row++;
		col=0;
		GetChar();
	} 
	while(ch==' '||ch=='\t') GetChar();
}
void Concat(){
	strToken.push_back(ch);
}
bool IsLetter(){
	return isalpha(ch);
}
bool IsDigit(){
	return isdigit(ch);
}
int Reserve(){
	int i;
	for(i=0;i<6;i++)
		if(ReservedWordList[i]==strToken) return i+1;
	return 10; 
}
void Retract(){
	col--;
	ch='\0'; 
}
void ProcError(){
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);//字体为红色 
	cout<<"[Error]"<<row<<" row"<<','<<col<<" col"<<endl;
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);//字体为白色 
} 
void LexicalAnalyzer(){
	while(row!=endrow||ScanBuffer[row][col]!='\n'){
		int code,value;
		strToken="";
		GetChar();
		GetDel();
		if(IsLetter()){
			while(IsLetter()||IsDigit()){
				Concat();
				GetChar();
			}
			Retract();
			code=Reserve();
			if(code!=10){
				//value=InsertID(strToken);
				cout<<'('<<code<<','<<strToken<<')'<<endl;
				//return (code,value);
			}
			else
				cout<<'('<<code<<','<<strToken<<')'<<endl;
				//return (code,-);
		}
		else if(IsDigit()){
			while(IsDigit()){
				Concat();
				GetChar();
			}
			Retract();
			//value=InsertConst();
			cout<<'('<<11<<','<<strToken<<')'<<endl;
			//return ($INT,value);
		}
		else if(ch=='+') //return (13,-);
			cout<<"(13,+)"<<endl;
		else if(ch=='-') //return (14,-);
			cout<<"(14,-)"<<endl;
		else if(ch=='*') //return (15,-);
			cout<<"(15,*)"<<endl;
		else if(ch=='/') //return (16,-);
			cout<<"(16,/)"<<endl;
		else if(ch==':'){
			GetChar();
			if(ch=='=') //return (18,-);
				cout<<"(18,:=)"<<endl;
			else{
				Retract();
				//return (17,-);
				cout<<"(17,:)"<<endl;
			}
		}
		else if(ch=='<'){
			GetChar();
			if(ch=='>') //return (21,-);
				cout<<"(21,<>)"<<endl;
			else if(ch=='=') //return (22,-);
				cout<<"(22,<=)"<<endl;
			else{
				Retract();
				//return (20,-);
				cout<<"(20,<)"<<endl;
			}
		}
		else if(ch=='>'){
			GetChar();
			if(ch=='=') //return (24,-);
				cout<<"(24,>=)"<<endl;
			else{
				Retract();
				//return (23,-);
				cout<<"(23,>)"<<endl;
			}
		}
		else if(ch=='=') //return (25,-);
			cout<<"(25,=)"<<endl;
		else if(ch==';') //return (26,-);
			cout<<"(26,;)"<<endl;
		else if(ch=='(') //return (27,-);
			cout<<"(27,()"<<endl;
		else if(ch==')') //return (28,-);
			cout<<"(28,))"<<endl;
		else if(ch=='#')
			//return (0,-);
			cout<<"(0,#)"<<endl;
		else ProcError();
	}
}
int main(){
	Input();
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);//字体为白色 
	LexicalAnalyzer();
	return 0; 
}