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

一、实验目的

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

二、实验原理与要求

 1、原理

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

 2、要求

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

三、实验设备

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

四、实验内容

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

 2. 画出状态转换图。

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

五、实验步骤

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

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

单词的分类及其表示

   定义一个结构体数组Result,用它存放识别出的单词符号的种别编码及内码值。如:输入k=99; 则输出为:(100, k), (13, -1), (110, 99), (18, -1), (0,)
结构体数组Result

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

设计状态转换图-1

设计状态转换图-2
  说明:状态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 <string.h> 

#include <iostream>
#include <string>

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, )test1
  • 如:输入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, )test2
  • 测试常数:k=36; 或者 15.67 或者 13e-14test3
    test4
    test5
  • 测试含有非法字符的: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表示。

六、配套资源

  • 12
    点赞
  • 147
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip实验一 源程序的预处理及词法分析程序设计等.zip
词法分析编译器的第一个阶段,它的主要任务是将源程序中的字符序列分解成有意义的词素序列(即单词),并将每个词素分类为一种词法单元。词法分析程序通常由两部分组成: 1. 词法规则定义:定义每种词法单元的模式或正则表达式,例如标识符、数字、运算符等。 2. 词法分析器实现:根据词法规则定义,将输入的源程序逐个字符扫描,并匹配识别出各个词法单元。 下面是一个简单的词法分析程序设计实验实验要求:设计一个词法分析程序,对以下语言进行词法分析:变量名只能由字母和数字组成,必须以字母开头;数字只包含整数,不包含小数;运算符包括加、减、乘、除,分号用于表示语句结束。 样例输入: x = 10 + y * 2; 样例输出: 变量名:x 赋值运算符:= 数字:10 加运算符:+ 变量名:y 乘运算符:* 数字:2 分号:; 实验步骤: 1. 定义词法规则,包括标识符、数字、运算符和分号的正则表达式。 ``` ID = [a-zA-Z][a-zA-Z0-9]* NUM = [0-9]+ OP = [+|\-|\*|\/] SEMICOLON = [\;] ``` 2. 实现词法分析器,逐个字符扫描输入的源程序,并匹配识别出各个词法单元。 ```python import re def lexer(input_string): tokens = [] while input_string: # 匹配标识符 if re.match(ID, input_string): match = re.match(ID, input_string) tokens.append(('变量名', match.group(0))) input_string = input_string[len(match.group(0)):] # 匹配数字 elif re.match(NUM, input_string): match = re.match(NUM, input_string) tokens.append(('数字', match.group(0))) input_string = input_string[len(match.group(0)):] # 匹配运算符 elif re.match(OP, input_string): match = re.match(OP, input_string) tokens.append(('运算符', match.group(0))) input_string = input_string[len(match.group(0)):] # 匹配分号 elif re.match(SEMICOLON, input_string): match = re.match(SEMICOLON, input_string) tokens.append(('分号', match.group(0))) input_string = input_string[len(match.group(0)):] else: # 无法匹配的字符,跳过 input_string = input_string[1:] return tokens ``` 3. 对样例输入进行词法分析,并输出结果。 ```python input_string = 'x = 10 + y * 2;' tokens = lexer(input_string) for token in tokens: print(token[0] + ':', token[1]) ``` 输出结果: ``` 变量名: x 赋值运算符: = 数字: 10 加运算符: + 变量名: y 乘运算符: * 数字: 2 分号: ; ``` 至此,我们完成了一个简单的词法分析程序设计实验

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值