实验一:词法分析程序的设计

文章目录

  • 一、实验目的
  • 二、实验原理与要求
    •  1、原理
    •  2、要求
  • 三、实验设备
  • 四、实验内容
    •  1. 定义语言子集并编码,要求有保留字、标识符、常数、运算符、界符。
    •  2. 画出状态转换图。
    •  3. 编写代码,实现分析。
  • 五、实验步骤
    •  1. 定义语言子集的单词符号的种别编码及内码值
    •  2. 构造状态转换图(自动机)
    •  3. 状态转换图的实现(编码)
    •  4. 测试
  • 六、配套资源

一、实验目的

  理解词法分析的功能,熟悉词法分析程序的构造。

二、实验原理与要求

 1、原理

 利用状态转换图来确定程序的流程。

 2、要求

 定义一个单词集,能用状态转换图描述。测试应满足分支覆盖。

三、实验设备

 配置有C/C++开发环境的计算机设备。

四、实验内容

 1. 定义语言子集并编码,要求有保留字、标识符、常数、运算符、界符。

 2. 画出状态转换图。

 3. 编写代码,实现分析。

五、实验步骤

 1. 定义语言子集的单词符号的种别编码及内码值

   如果一个种别只含有一个单词符号,则内码值为-1;如果一个种别含有多个单词符号(如:标识符、常数),用它自身的值作为内码值。

实验一:词法分析程序的设计_第1张图片

   定义一个结构体数组Result,用它存放识别出的单词符号的种别编码及内码值。如:输入k=99; 则输出为:(100, k), (13, -1), (110, 99), (18, -1), (0,)
实验一:词法分析程序的设计_第2张图片

 2. 构造状态转换图(自动机)

实验一:词法分析程序的设计_第3张图片

实验一:词法分析程序的设计_第4张图片
  说明:状态96~100表示输入非法字符。

 3. 状态转换图的实现(编码)

// -*- coding: utf-8 -*-
//  @ Date   : 2020/5/20 13:14
//  @ Author : RichardLau_Cx
//  @ file   : Richard.cpp
//  @ IDE    : Dex-C++
//  @ Source : 编译原理实验

/**
* 1. 以学习他人的经验为主,带入自己的想法为辅
* 2. 频繁debug各函数实现,是一种变相的效率提升 
* 3. 由于很多变量都是公共变量,所以函数调用时则不必传值 
*/

#include  

#include 
#include 

using namespace std;

const char KW[6][10] = {"if", "else", "while", "int", "float", "char"};  // 保留字存储:以保留字为行,以保留字的每个字母为列 
char inputString[99]; 
int number=0;  // 各单词结构体数组的索引,相当于统计单词个数 
int i=0;  // 字符串匹配位置 
int k=0;  // k为单词的内码值下标

//(1)定义语言子集的单词符号的种别编码及内码值
	// 定义结构体数组Result 
	typedef struct{
		int typeNumber;  // 单词符号的种别编码 
		char code[100];  //  内码值 
//		string code;
	} Word;  // 单词类型定义 
	
	Word Result[100];
	

void words();
void keyWord();

void state0(); 
void state1();
void state2();
void state3();
void state4();
void state5();
void state6();
void state7();
void state8();
void state9();
void state10();
void state11();
void state12();
void state13();
void state14();
void state15();
void state16();
void state17();
void state18();
void state19();
void state20();
void state21();

void output();
void error();
void end();

/*
  当前进度:
  	1. 完成state0()和state1()的功能实现 
*/ 

	
void words()
{
	/*
		若传字符串,则考虑使用指针 
	*/ 
	cout << "function: words(): " << endl << "input: ";
	gets(inputString); 
//	cin >> inputString;  // 此方法拿不到字符串中的空格 
	
	while (inputString[i] != '\0')
	{
		k = 0;  // k为单词的内码值下标,即Result[number].Code[k]
		
		while (inputString[i] == ' ') i++;  // 剔除空格
		
		state0();  // 从0状态出发,直至到达一个终态,就识别出一个单词
		
		// 若识别出的是标识符,则需要进一步判断是否为保留字
		
		if (Result[number].typeNumber == 100)
		{  // 如果单词为标识符,再进行判断是不是保留字 
			keyWord();
		} 
		 
		// 输出当前(最后一个)单词 
//		cout << "number: " << number << "\t typeNumber: " << Result[number].typeNumber << "\t Result[number].code: " << Result[number].code << endl;
		
		i++;  //  从输入串中读出下一个字符
		number++;  // 全局变量,统计单词个数 
	}
	
//	gets(string)
 } 



void keyWord() 
{
	int i;
	
//	cout << "function: keyWord()" << endl;
	
	for (i=0; i < 6; i++)
	{  // 目前共有6个保留字 
		if (strcmp(Result[number].code, KW[i]) == 0)
		{  // 将标识符与保留字进行比较 
			Result[number].typeNumber = i+1;  // 种别编码刚好是保留字下标+1
			strcpy(Result[number].code, "-1"); 
			 
			break;
		}
	}
}


//(3)状态转换图的实现
void state0()
{  // 初态函数 
	if ((inputString[i] >= 'a' && inputString[i] <= 'z') || (inputString[i] >= 'A' && inputString[i] <= 'Z'))
	{  // 判断当前输入的字符是否为;字母 
		Result[number].code[k] = inputString[i];  // 把当前输入字符串,加入到返回结果的二元组的内码值当中
		i++;  // 读取下一个输入字符 -输入 
		k++;  // 内码值位置加1 -存储 
		
		state1();  // 转到状态1 
	} 
	
	else if (inputString[i] == '+')
	{  // 如果当前输入字符串为 '+' 
		strcpy(Result[number].code, "-1");  // '+'的内码值为-1 
		i++;
		
		state2();
	}
	
	else if (inputString[i] == '>')
	{
		strcpy(Result[number].code, "-1");
		i++;
		
		state3();
	}
	
	else if (inputString[i] == '=')
	{
		strcpy(Result[number].code, "-1");
		i++;
		
		state4();
	}
	
	else if (inputString[i] == '*')
	{
		strcpy(Result[number].code, "-1");
		i++;
		
		state5();
	}
	
	else if (inputString[i] == ',')
	{
		strcpy(Result[number].code, "-1");
		
		state6();
	}
	
	else if (inputString[i] == ';')
	{
		strcpy(Result[number].code, "-1");
		
		state7();
	}
	
	else if (inputString[i] == '(')
	{
		strcpy(Result[number].code, "-1");
		
		state8();
	}
	
	else if (inputString[i] == ')')
	{
		strcpy(Result[number].code, "-1");
		
		state9();
	}
	
	else if (inputString[i] == '-')
	{
		strcpy(Result[number].code, "-1");
		
		state10();
	}
	
	else if (inputString[i] == '/')
	{
		strcpy(Result[number].code, "-1");
		
		state11();
	}
	
	else if (inputString[i] == '{')
	{
		strcpy(Result[number].code, "-1");
		
		state12();
	}
	
	else if (inputString[i] == '}')
	{
		strcpy(Result[number].code, "-1");
		
		state13();
	}
	
	else if (inputString[i] == '<')
	{
		strcpy(Result[number].code, "-1");
		i++;
		
		state14(); 
	}
	
	else if (inputString[i] == '!')
	{
		strcpy(Result[number].code, "-1");
		i++;
		
		state15();
	}
	
	else if (inputString[i] >= '0' && inputString[i] <= '9')
	{
		Result[number].code[k] = inputString[i];  // 把当前输入字符,加入到返回结果的二元组的内码值中
		i++;
		k++; 
		
		state16();
	}
	
	else
	{  // 若输入非法字符
		error();
	}
 } 
 
 
void state1()
{  // 由于1状态含有回路,则对于包含回路的状态,通过while语句来实现 
   while ((inputString[i] >= 'a' && inputString[i] <= 'z') || (inputString[i] >= 'A' && inputString[i] <= 'Z') || (inputString[i] >= '0' && inputString[i] <= '9')) 
   {  // 若继续为字母或者数字(首字符不能为数字) 
   	  Result[number].code[k] = inputString[i];  // 把当前输入字符继续存入到内码值中
	  i++;
	  k++; 
   }
   
   Result[number].typeNumber = 100;  // 标识符:种类编号为100
   Result[number].code[k] = '\0';  // 给当前内码值的末端加上结束符
   i--;  // 由于读出其他字符才能到达终态,故多了一个字符,则需将当前读入的字符回退 
 } 
 

void state2() 
{
	if (inputString[i] == '+')  // 当前输入字符串为'+'号时 
	{
		Result[number].typeNumber=8;  // 识别出'++', 种别为8 
	}
	
	else if (inputString[i] == '=')
	{
		Result[number].typeNumber=9;  // 识别出'+=', 种别为9 
	}
	
	else
	{  // 当前输入字符为其他字符时
		Result[number].typeNumber=7;  // 识别出单个'+',种别为7 
		i--;  // 由于读出其他字符,所以当前读入字符需回退 
	}
}


void state3()
{
	if (inputString[i] == '=')
	{
		Result[number].typeNumber=11;  // 识别出'>=',种别为11 
	}
	
	else if (inputString[i] == '>')
	{
		Result[number].typeNumber=12;  // 识别出'>>',种别为12 
	}
	
	else
	{
		Result[number].typeNumber=10;  // 识别出单个'>',种别为10
		i--;   
	 } 
 } 
 
 
void state4()
{
	if (inputString[i] == '=')
	{
		Result[number].typeNumber=14;  // 识别出'==', 种别为14
	}
	
	else 
	{
		Result[number].typeNumber=13;  // 识别出单个'=',种别为13
		i--; 
	}
 } 


void state5()
{
	if (inputString[i] == '*')
	{
		Result[number].typeNumber=16;  // 识别出'**',种别为16 
	}
	
	else
	{
		Result[number].typeNumber=15;  // 识别出单个'*',种别为15
		i--; 
	 } 
}


void state6()
{
	Result[number].typeNumber=17;  // 单个',',种别为17 
}

void state7()
{
	Result[number].typeNumber=18;  // 单个';',种别为18
}

void state8()
{
	Result[number].typeNumber=19;  // 单个'(',种别为19
}

void state9()
{
	Result[number].typeNumber=20;  // 单个')',种别为20
}

void state10()
{
	Result[number].typeNumber=21;  // 单个'-',种别为21
}

void state11()
{
	Result[number].typeNumber=22;  // 单个'/',种别为22 
}

void state12()
{
	Result[number].typeNumber=23;  // 单个'{',种别为23 
}

void state13()
{
	Result[number].typeNumber=24;  // 单个'}',种别为24 
}

void state14()
{
	if (inputString[i] == '=')
	{
		Result[number].typeNumber=26;  // '<='
	 } 
	 
	else if (inputString[i] == '<')
	{
		Result[number].typeNumber=27;  // '<<'
	 } 
	 
	else
	{
		Result[number].typeNumber=25;  // '<'
		i--;
	}
	
	 
}


void state15()
{
	if (inputString[i] == '=')
	{
		Result[number].typeNumber=28;  // '!='
	}
	
	else
	{
		error();
		i--;
	}
}


void state16()
{  // 相当于树状结构 
	while(inputString[i] >= '0' && inputString[i] <= '9')
	{  // 当前输入字符为若干个数字时 
		Result[number].code[k] = inputString[i];  // 把当前输入字符加到内码值中 
		i++;
		k++; 
	}
	
	if (inputString[i] == '.')
	{  // 当前输入字符若为'.'时,则转到状态17;若为'E|e'时,转到状态19;若为其他字符时,到达终态,识别出常数,并且标记种别为110 
		Result[number].code[k] = inputString[i];
		i++;  
		k++;
		
		state17();
	}
	
	else if (inputString[i] == 'E' || inputString[i] == 'e')
	{
		Result[number].code[k] = inputString[i];
		i++;
		k++;
		
		state19(); 
	}
	
	else 
	{
		end(); 
	 } 
 } 
 

void state17()
{
	if (inputString[i] >= '0' && inputString[i] <= '9')
	{
		Result[number].code[k] = inputString[i];
		i++;
		k++;
		// 双方同步后移 
		
		state18();
	}
	
	else
	{
		error();  // '.'后无内容 
	 } 
}


void state18()
{
	while(inputString[i] >= '0' && inputString[i] <= '9')
	{  // 当前输入字符为若干个数字时 
		Result[number].code[k] = inputString[i];  // 把当前输入字符加到内码值中 
		i++;
		k++; 
	}
	
	if (inputString[i] == 'E' || inputString[i] == 'e')
	{
		Result[number].code[k] = inputString[i];
		i++;
		k++;
		
		state19();
	}
	
	else
	{
		end();
	}
 } 


void state19()
{
	if (inputString[i] == '-' || inputString[i] == '+')
	{  // 指数携带了正负号 
		Result[number].code[k] = inputString[i];
		i++;
		k++;
		
		state20();
	}
	
	else if (inputString[i] >= '0' && inputString[i] <= '9')
	{
		Result[number].code[k] = inputString[i];
		i++;
		k++;
		
		state21();
	}
	
	else
	{
		error();  // 'E|e'后无内容 
	 } 
 }
 
 
void state20()
{
	if (inputString[i] >= '0' && inputString[i] <= '9')
	{
		Result[number].code[k] = inputString[i];
		i++;
		k++;
		
		state21();
	}
	
	else 
	{
		error();  // '+|-'后无内容 
	}
 }
 

void state21()
{
	while(inputString[i] >= '0' && inputString[i] <= '9')
	{  // 当前输入字符为若干个数字时 
		Result[number].code[k] = inputString[i];  // 把当前输入字符加到内码值中 
		i++;
		k++; 
	}
	
	end();
}
 

void output()
{  // (4)测试
	cout << endl << "词法分析结果(种别编码,内码值):" << endl << "output: ";
	
	for (int i=0; i <= number; i++)
	{
		cout << "(" << Result[i].typeNumber << ", " << Result[i].code << ")";
		
		if (i != number)
		{
			cout << ','; 
		}
		
		else 
		{
//			cout << endl;
			;
		}
	}
//	cout << "number: " << number << "\t typeNumber: " << Result[number].typeNumber << "\t Result[number].code: " << Result[number].code << endl;
}


void error()
{  // 错误态 
	Result[number].typeNumber = 0;  // 上面的情况都不符合,则表示输入的字符非法,置种别为0,内码值为"Error" 
	strcpy(Result[number].code, "Input Error!");
}


void end()
{  // 终态 
	Result[number].typeNumber=110;  // 常数种类编号为110
	Result[number].code[k]='\0';  // 内码值末端加上结束符
	i--; 
}


int main()
{
//	string strings;
//	char strings[10];
	
//	gets(strings);
//	cin >> strings;
	
	words();  // 词法分析
//	keyWord();  // 判断识别出的标识符是否为保留字

//	keyWord_test(strings); 

	output();
	
	return 0;
}


// ---------------------------------------------------------------------- testing -------------------------------------------------------------------------------
/*

int main() {
//	(2)构造状态转换图(自动机)
//	char InputString[100];  // 字符数组存放输入串 
	string inputString; 
	cin >> inputString;
	
//	while(inputString[i] == ' ') i++;  // 剔除空格


// test 
	cout << "inputString: " << inputString;
	cout << "KW: " << KW[2];
	
	//	整体模块设计
	words();  // 词法分析 
	keyWord();  // 判断识别出的标识符是否为保留字
	
	// 为每个非终态编写函数,其中staten()表示状态n的函数。


	 
	
	return 0;
} 




void keyWord_test(char *strings) 
{
	int i;
	
	cout << "function: keyWord(): " << endl;
	
	for (i=0; i < 6; i++)
	{  // 目前共有6个保留字 
		if (strcmp(strings, KW[i]) == 0)
		{  // 将标识符与保留字进行比较 
//			Result[number].typeNumber = i+1;  // 种别编码刚好是保留字下标+1
//			strcpy(Result[number].code, "-1"); 
			cout << "这是保留字!"; 
			 
			break;
		}
		
//		cout << i << endl;
		
		if (i == 5)
		{  // 不属于前6个保留字 
			cout << "这不是一个保留字!";
		}
	}
}

*/

 4. 测试

  • 如:输入520.13E+14*9+99,则输出为:(110, 520.13E+14),(15, -1),(110, 9),(7, -1),(110, 99),(0, )实验一:词法分析程序的设计_第5张图片
  • 如:输入if(k <= 45) sum += 2;,则输出为:(1, -1),(19, -1),(100, k),(26, -1),(110, 45),(20, -1),(100, sum),(9, -1),(110, 2),(18, -1),(0, )实验一:词法分析程序的设计_第6张图片
  • 测试常数:k=36; 或者 15.67 或者 13e-14实验一:词法分析程序的设计_第7张图片
    实验一:词法分析程序的设计_第8张图片
    实验一:词法分析程序的设计_第9张图片
  • 测试含有非法字符的:char string11?? > !min;,则输出为:(6, -1),(100, string11),(0, Input Error!),(0, Input Error!),(10, -1),(0, Input Error!),(100, min),(18, -1),(0, )

Note:简单起见,除标识符、常数外,其余单词均为一个单词一类(如一个保留字一类,一个运算符一类),则标识符、常数的内码值为自身的值,其余单词的种别编码代表了它自身的值,故内码值用 -1表示。

六、配套资源

  • 实验指导书

你可能感兴趣的:(c++,c语言,编译器,数据结构,状态机)