编译原理-词法分析

Posted 修心_666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编译原理-词法分析相关的知识,希望对你有一定的参考价值。

实验一 词法分析
一、词法分析的任务
词法分析的核心任务是从左到右读入源程序的字符流,识别出一个个的单词。所识别的每一个单词,是下一个有意义的词法元素,如标识符或整数。在识别出下一单词,同时也验证了其词法正确性之后,词法分析程序就会产生一个单词记录,传递给后续阶段使用。
词法分析程序所产生的单词记录通常由两部分信息组成:一个是单词符号(token),对应某个特定意义的词法单元,如标识符、整常数等;另一部分是单词的属性值(attribute)。
程序设计语言中有各种类别的单词,常见的如:
•保留字,也称关键字,如 C 语言中的 if、while、struct、int、typedef 等。
•标识符,用来表示各种名字,如常量名、变量名、函数/过程名、类名等。
•各种类型的常数,如整数 25,浮点数 3.1415,串常数“ABC”等。
•运算符,如 +,,<= 等。
•界符,如逗点,分号,括号等。
例如某语言构词规则 如下:
<无符号整数> ::= <数字> {<数字>}
<标识符> ::= <字母> {<字母><数字>}
<字母> ::= a | b | … | X | Y | Z
<数字> ::= 0 1 2 … 8 9
<保留字> ::= constvarprocedurbeginendoddifthencallwhiledoreadwrite
<运算符> ::= + - 
/ = # < <= > >= :=
<界符> ::= ( ) , ;

二、实验内容
对于以下 Decaf 程序片断:
class Main {
static void main() {
Print(“hello world”);
}
}

设计中还要考虑的一点就是对于单词记录中的属性值的处理,比如可能需要将标识符的
名字、类型等信息存放于符号表中。词法分析结果如下:

直接上代码,但是这个代码适用性不高:

#include <iostream>
#include <fstream>
#include <cassert>
#include <string>
#include <vector>
#include <map>
#include <iosfwd>
#include <algorithm>
using namespace std;

//以键值对的形式存储分析结果
vector<pair<string, string>> res;

//语法构词规则

//标识符:用来表示各种名字,如常量名、变量名、函数/过程名、类名等
// 字母+字母|数字

//无符号整数:数字+数字的集合

//字符串常量

//字母
vector<char> chars;
//数字
vector<int> nums = { 0,1,2,3,4,5,6,7,8,9 };
//保留字
vector<string> keywords = { "static","void","Print","const","var","procedure","begin","end","odd","if","then","call","while","do","read","write","class" };
//运算符
vector<string> operators = { "+","-","*","/","=","#","<","<=",">",">=",":=" };
//分隔符
//vector<char> delimiters = { '(',')',',',';','{','}' };
vector<string> delimiters = { "(",")",",",";","{","}" };

//初始化字母数组
void Initialize() {
	char tmp = 'A';
	for (int i = 0; i < 26; i++,tmp++) {
		chars.push_back(tmp);
	}
	char t = 'a';
	for (int i = 0; i < 26; i++, t++) {
		chars.push_back(t);
	}
}

//判断是否是保留字
bool IsKeyword(string tmp,vector<string> keywords) {
	for (int i = 0; i < keywords.size(); i++) {
		if (tmp == keywords[i]) {
			return true;
		}
	}
	return false;
}

//判断是否是运算符
bool IsOperator(string tmp) {
	if (find(operators.begin(), operators.end(), tmp) != operators.end()) {
		return true;
	}
	return false;
}

//判断是否是分隔符
bool IsDelimiter(string tmp) {
	if (find(delimiters.begin(), delimiters.end(), tmp) != delimiters.end()) {
		return true;
	}
	return false;
}


//判断字符串中是否包含分隔符
bool HaveDelimiter(string tmp) {
	for (char i : tmp) {
		string c;
		c.push_back(i);
		if (find(delimiters.begin(), delimiters.end(), c) != delimiters.end()) {
			return true;
		}
		c = "";
	}
	return false;
}

//判断字符串中是否包含""
bool Haveshuang(string tmp) {
	for (char i : tmp) {
		if (i == '"') {
			return true;
		}
	}
	return false;
}

//判断是否是标识符
bool IsIdentifier(string tmp) {
	if ( find(chars.begin(),chars.end(),tmp[0])!= chars.end() && !IsKeyword(tmp,keywords) 
		&& !HaveDelimiter(tmp) ){
		return true;
	}
	return false;
}


//分析单个字符串的属性
void Analyze(string tmp) {
	if (IsKeyword(tmp, keywords)) {
		res.push_back(pair<string, string>("保留字", tmp));
	}
	else if (IsIdentifier(tmp)){
		res.push_back(pair<string, string>("标识符", tmp));
	}
	else if (IsOperator(tmp)) {
		res.push_back(pair<string, string>("运算符", tmp));
	}
	else if (IsDelimiter(tmp)){
		res.push_back(pair<string, string>("分隔符", tmp));
	}
	else if (HaveDelimiter(tmp)) {
		//分隔符第一次出现的下标
		int index = 0;
		for (int i = 0; i < tmp.size(); i++)
		{
			string c;
			c.push_back(tmp[i]);
			if (find(delimiters.begin(), delimiters.end(),c) != delimiters.end()) {
				index = i;
				break;
			}
			c = "";
		}
		//处理分隔前面的字符串
		string a = tmp.substr(0, index);
		if (IsKeyword(a, keywords)) {
			res.push_back(pair<string, string>("保留字", a));
		}
		else if (IsIdentifier(a)) {
			res.push_back(pair<string, string>("标识符", a));
		}
		else if (IsOperator(a)) {
			res.push_back(pair<string, string>("运算符", a));
		}
		else if (IsDelimiter(a)) {
			res.push_back(pair<string, string>("分隔符", a));
		}
		string x;
		x.push_back(tmp[index]);
		res.push_back(pair<string, string>("分隔符", x));
		//找到最后一个分隔符
		int lastindex = 0;
		for (int i = index; i < tmp.size(); i++) {
			string b = "";
			b.push_back(tmp[i]);
			if (IsDelimiter(b)) {
				lastindex = i;
			}
			b = "";
		}
		if (Haveshuang(tmp))
		{
			//处理分隔符()中间的字符串
			string c = "";
			for (int i = index+1; i < lastindex-1; i++) {
				c += tmp[i];
			}
			res.push_back(pair<string, string>("字符串常量", c));
		}
		for (int i = index+1; i < lastindex; i++) {
			string d;
			d.push_back(tmp[i]);
			if (IsDelimiter(d)) {
				res.push_back(pair<string, string>("分隔符", d));
			}
			d = "";
		}
		string y;
		y.push_back(tmp[lastindex]);
		res.push_back(pair<string, string>("分隔符", y));
	}
}


//扫描整个字符串   class Main { static void main() { Print("hello world"); } }
void Saomiao(string buff) {
	//先计算输入文件流字符串的长度
	int bufflength = buff.size();
	int spaceindex = 0;
	//标志读入字符串常量的状态
	bool state = false;
	int count = 0;
	string tmp = "";
	for (int i = 0; i < bufflength; i++) {
		if (buff[i] == '"')
		{
			count++;
			state = count % 2;
		}
		if (buff[i] != ' ') {
			tmp += buff[i];
		}else if (buff[i] == ' ' && state == true)
		{
			tmp += buff[i];
		}
		else if (buff[i] == ' ' && state == false) {
				spaceindex = i;
				//cout << tmp << endl;
				Analyze(tmp);
				tmp = "";
		}
	}
}


int main() {
	ifstream infile;
	infile.open("exp1.txt", ios::in);
	if (!infile.is_open())
	{
		cout << "打开文件失败" << endl;
		return 0;
	}
	//第一种方式打开
//     char buf[1024] = { 0 };
//     while (infile >> buf)
//     {
//         cout << buf << endl;
//     }

	//打开文件 , 将数据存储到buf中
	string buff = "";
	string tmp = "";
	while (getline(infile, tmp))
	{
		//cout << buff << endl;
		buff += tmp;
	}
	//第三种 
// 	string buff;
//     char c;
//     while ((c = infile.get()) != EOF)
//     {
// 		buff += c;
//     }
//	cout << buff << endl;
//	class Main { static void main() { Print("hello world"); } }
	Initialize();
	Saomiao(buff);

	ofstream outFile;
	outFile.open("out.txt");//保存的文件名
	cout << "分析结果为:" << endl;
	for (auto i : res)
	{
		outFile << i.first << "      " << i.second << endl;
		cout << i.first << "      " << i.second << endl;
	}
	//cout << res.size() << endl;
	cout << "结果输出到同目录下的out.txt文件中" << endl;
	outFile.close();//关闭文件写入流
	infile.close();

	return 0;
}

在这里插入图片描述
在这里插入图片描述
如果觉得本文对你有帮助的话,不妨关注作者一波,小小的关注其实对我很重要。更多高质量内容与资料请访问:个人主页:修心的小屋

以上是关于编译原理-词法分析的主要内容,如果未能解决你的问题,请参考以下文章

实验一 词法分析器+编译原理

编译原理-2词法分析

编译原理-2词法分析

编译原理:词法分析PHP代码实现

GCC编译器原理------编译原理三:编译过程(2-1)---编译之词法分析

2016.9.30 编译原理-词法分析器