编译原理(一):实现词法分析程序

前言

本文仅是作为个人学习笔记,对知识进行总结。参考书目:《编译原理及编译程序构造》

基本概念

1. 语法
  • 任何语言程序都可以看成是一定字符集(字母表) 上的字符串;语法使得这串字符形成一个形式上正确的程序。

  • 语法=词法规则+语法规则

其中词法规则规定了字母表中哪些字符串是单词符号。
其中语法规则规定了如何从单词符号来形成语法单位
语法单位有表达式、子句、语句、函数、过程、程序

2. 字母表、符号串、句子、语言
  • 字母表是符号的非空有穷集合
  • 符号是语言中最基本的不可分割的单位
  • 符号串是由字母表中的符号组成
  • 句子是是字母表上符合某种规则构成的串
  • 语言是字母表上句子的集合
3. 基础运算
  • 连接运算
  • 幂运算
  • 闭包运算(正闭包指不包含空串)
3. 文法
  • 文法是描述语言的语法结构的形式规则

  • 终结符 V T V_T VT

  • 非终结符 V N V_N VN

  • 0形文法(只要产生式左边有一个非终结符即可)

  • 1形文法(也称长度增加文法或者上下文有关文法,对非终结符进行替换时务必考虑上下文)

  • 2形文法(产生式左部一定是非终结符,对非终结符进行替换时无需考虑上下文)

  • 3形文法(称为正规文法,有左线性和右线性之分)

3. 短语、直接短语
  • 短语:语法树中,所有的子树根结点构成的就是短语
  • 直接短语:只有2层子树构成的短语,是直接短语
4. 文法的二义性
  • 如果文法的一个句子存在对应的两棵或两棵以上 的语法树,则该句子是二义的。

  • 用某文法推导某个句子,如果有好几种推导方式,那么说明这个文法就是二义性的。

算法

1.构造无ε产生式的上下文无关文法

  1. 找出所有能够推出ε非终结符
  2. 对于这些非终结符,如果他们出现在产生式的右部,则用它本身和ε代换

直接看例题比较好理解
在这里插入图片描述

2.文法的化简算法

  1. 消去P->P
  2. 消去不可达的非终结符
  3. 消去不能导出终结符的非终结符

看例题比较好理解
在这里插入图片描述

3.NFA的确定化算法

直接看例题比较好理解,如下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.DFA的最小化

参见
在这里插入图片描述

  1. 将M的状态分为两个子集一个由终态k1={C,D,E,F}组成,一个由非终态k2={S,A,B}组成,

  2. 考察{S,A,B}是否可分.

  3. 因为A经过a到达C属于k1.而S经过a到达A属于k2.B经过a到达A属于k2,所以K2继续划分为{S,B},{A},

  4. 考察{S,B}是否可再分:

  5. B经过b到达D属于k1.S经过b到达B属于k2,所以S,B可以划分。划分为{S},{B}

  6. 考察{C,D,E,F}是否可再分:

  7. 因为C,D,E,F经过a和b到达的状态都属于{C,D,E,F}=k1所以相同,所以不可再分:

  8. {C,D,E,F}以{D}来代替则,因为CDEF相同,你也可以用C来代替。无所谓的最小化的DFA如图,:

总结:先对非终态集进行划分,直到不能划分为止,然后再对终态集进行划分,直到不能划分为止,从所有划分之后的集合中选出一个代表即可。

5. 根据正则表达式构造NFA

即反复应用下面算法
在这里插入图片描述

7.确定化含ε弧的NFA

确定化含ε弧的NFA实际上就是多了一个求ε闭包,ε闭包定义如下:
在这里插入图片描述
步骤几乎与3一摸一样,只是多了一步求ε闭包
在这里插入图片描述

6.根据文法构造NFA

这里指的文法通常是指左线性文法或者右线性文法。
在这里插入图片描述
在这里插入图片描述

词法分析程序的实现

程序设计步骤
  1. 画出词法的NFA
  2. 确定化NFA,生成DFA
  3. 化简DFA
  4. 合并DFA
  5. 编码实现最终实现的DFA

给定输入文件
在这里插入图片描述

输出:
在这里插入图片描述

ifndef LEX
#define LEX
#include <string>
#include <fstream>
#include "table.h"
#include <map>
#include <vector>
#include<iostream>
using namespace std;
#define STATE_END 20



class  LexAnalyzer
{
public:
	string content;
	int cursor;
	map<string, vector<int>> result;
public:
	void preprocess(){
		string temp = "";
		int index = 0;
		int s = 0;
		while (content[index] != '\0')
		{
			char ch = content[index];

			if (s == 0 && ch != '/'){
				temp += ch;
			}
			else if (s ==0 && ch=='/'){
				s = 1;
			}
			else if (s == 1 && ch == '/'){
				s = 2;
			}
			else if (s == 1 && ch == '*'){
				s = 3;
			}
			else if (s == 1 && (ch != '/'||ch!='*')){
				temp = temp + '/' + ch;
				s = 0;
			}
			else if (s==2 && ch !='\n'){
				s = 2;
			}else if(s==2 && ch=='\n'){
				s = 0;
			}
			else if (s==3 && ch=='*'){
				s = 4;
			}
			else if (s==4 && ch=='/'){
				s = 0;
			}
			else if (s==4 && ch!='/'){
				s = 3;
			}
			index++;
		}
		cout << temp<<endl;
		content = temp;
	}
public:
	LexAnalyzer(string filename){
		ifstream in(filename);
		string line;
		while (getline(in, line)){
			content =content+ line+"\n";
		}
		cursor = 0;
		in.close();
	}
	~LexAnalyzer(){
	}
private:
	int state = 0; // 初始化状态
public:
	char scanner(){
		char res = content[cursor++];
		return res;
	}
	string adscanner(int i){
		string res = "";
		while (i--)
		{
			res = content[cursor + i]+res;
		}
		return res;
	}
	void parser(){
		try{
			string token = "";
			while (true){
				char ch = this->scanner();
				if (ch == '\0'){
					break;
				}
				switch (state){
				case 0:
					state_convet_0(ch);
					break;
				case 1:
					state_convet_1(ch);
					break;
				case 2:
					state_convet_2(ch);
					break;
				case 3:
					state_convet_3(ch);
					break;
				case 4:
					state_convet_4(ch);
					break;
				case 5:
					state_convet_5(ch);
					break;
				case 6:
					state_convet_5(ch);
					break;
				default:
					break;
				}
				if (state == 0){

				}
				else if (state != STATE_END){
					token += ch;
				}
				else{
					vector<int> v;
					if (isBaseField(token)){
						v.push_back(getClassId(token));
						result[token] = v;
						cout << "关键字:";
					}
					else if (isConstant(token)){
						addConstant(token);
						cout << "常量:";
					}
					else{
						int innerID;
						if (existIdentifier(token)){
							innerID = getIdentifierID(token);
						}
						else{
							innerID = addIdentifier(token);
						}
						v.push_back(getClassId(IDENT));
						v.push_back(innerID);
						result[token] = v;
						cout << "标识符:";
					}
					cout << token << endl;

					token = "";
					state = 0;
					back();
				}
			}
		}
		catch (exception &e){
			throw e;
		}
	}
public:
	map<string, vector<int>> getResult(){
		int a = 10;
		return result;
	}
private:
	void back(int i=1){
		cursor -= i;
	}
	void skip(){
		while (content[cursor] == ' ')
			cursor++;
	}

private:
	bool isCharactor(int ch){
		return (ch >= 97 && ch <= 122) || (ch >= 65 && ch <= 90);
	}
	bool isNum(int ch){
		return (ch >= 48 && ch <= 57);
	}
	bool isNoDisplayCharactor(int ch){
		return (ch >= 0 && ch <= 32) || (ch == 127);
	}
	bool isConstant(string str){
		for (int i = 0; i < str.size();i++){
			char c = str[i];
			if (!(c>='0' && c<='9')){
				return false;
			}
		}
		return true;
	}
	
private:
	void state_convet_6(char ch){
		state = STATE_END;
	}

	void state_convet_5(char ch){
		state = STATE_END;
	}

	void state_convet_4(char ch){
		if (isNoDisplayCharactor(ch) || ch == '='){
			state = STATE_END;
		}else{
			throw exception("词法错误");
		}
	}


	void state_convet_3(char ch){
		if (isNum(ch)){
			state = 2;
		}
		else if(ch=='='){
			state = 6;
		}
		else if (isNoDisplayCharactor(ch) || isCharactor(ch)){
			state = STATE_END;
		}
		else{
			throw exception("词法错误");
		}
	}


	void state_convet_2(char ch){
		if (this->isNum(ch)){
			return;
		}
		else if (isNoDisplayCharactor(ch) || ch == ';'){
			state = STATE_END;
		}
		else{
			throw exception("词法错误");
		}
	}

	void state_convet_1(char ch){
		if (this->isCharactor(ch) || this->isNum(ch)){
			return;
		}
		state = STATE_END;
	}
	void state_convet_0(char ch){
		if (this->isCharactor(ch)){
			state = 1;
		}
		else if (this->isNum(ch)){
			state = 2;
		}
		else{
			switch (ch)
			{
			case '+':
			case '-':
				state = 3;
				break;
			case '*':
			case '/':
				state = 4;
				break;
			case '=':
				state = 5;
				break;
			default:
				break;
			}
		}
	}
};
#endif

  • 2
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ReWz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值