南京邮电大学编译原理——实验一:自己写一个词法生成器,第二步:利用DFA生成一个词法分析器

前言

前一篇文章写到了有穷自动机的实现。传送门
这次就用之前实现的DFA类来完成一个简单的词法分析器吧。实际上通过学习编译原理,我们可以自己写一个词法生成器的编译程序,具体的写法应该是:正则表达式词法分析器->生成转换系统->通过子集法生成DFA->简化DFA->运行DFA。但是由于没有时间,并且现在已经有了Lex之类的自动生成器,最近不再写了,毕竟这一套下来还是要很多时间的。

词法分析器

确定语言

本次实验需要设计一个类C语言的语言,现在设计语言如下:

语言种类正则
标识符(字母
数字(0-9)+
算数运算符/
逻辑运算符/
位运算符/
保留字/

需要注意的是本语言设计的标识符只能由字母和下划线组成。
对应的机内码为:
组标识符
在这里插入图片描述组内标识符
在这里插入图片描述

确定DFA

我们需要根据上述的正则表达式转换成一个DFA,另外任意的保留字都可以看成一个特殊的标识符,所以我们在设计DFA的时候可以将保留字合并到标识符的识别中去,当识别到一个标识符时,再通过查表运算确认这个标识符是否是一个保留字。下面是根据正则所写出的DFA。
在这里插入图片描述

编程

我们把需要实现的词法分析器做成一个叫做Lexical_Analyzer的类。首先来看一下整个项目的文件依赖:
在这里插入图片描述

Lexical_Analyzer的数据成员

接下来先介绍一下类的数据成员。大体上可以分成描述DFA的数据结构以及为了记录扫描指针位置、错误记录、状态转换等等辅助信息的其他数据结构。

描述DFA的成员

其中的描述DFA的成员有:

static vector<byte> Valid_State ;
static vector<byte> Termin_State;
static byte Start_State;
static vector<State_Transfer_Tuple<char>> State_Transfer_Matrix;
map<byte, State_Callback_Fun<char>> States_Fun;

其中的State_Transfer_Matrix是类似于如下的一个结构体数组,用于描述DFA的状态转移:

vector<State_Transfer_Tuple<char>> Lexical_Analyzer::State_Transfer_Matrix = {
{0,[](char a)->bool {return a == ' ' || a == '\n'; },0}
,
{ 0,[](char Char)->bool {return (Char <= 'Z' && Char >= 'A') || (Char <= 'z' && Char >= 'a') || Char == '_'; },1 }
//....
//....
}

States_Fun则是用于DFA位于某些状态时需要处理的一些函数,如回退扫描指针等。

辅助变量

而剩下的结构是辅助词法分析器工作的,其中又包括几个字典和位置记录变量。

	static map<byte, Word_Value> DFAState_TypeId_Mapping;
	static map<string, byte> Reversed_Word_Mapping;
	static map<char, byte> Separtor_Mapping;

	char* InputSource = NULL;
	unsigned long File_Length;
	unsigned long Begin_Pt = 0;
	unsigned long End_Pt = 0;
	unsigned long Row = 0;
	unsigned long Col = 0;
	bool IsEnd=false;

前三个Mapping是三个字典,记录了在设计语言时的机内码和单词的映射关系。而剩下的几个则是扫描指针以及源代码文件的相关信息。

Lexical_Analyzer的类函数声明

我们来看一下在为了输出规范的机内码,我们需要在DFA中做什么操作。大致上可以分成两类:

  1. 返回固定的机内码:除了状态2、5的其他终止状态都是这样的。这个又可以分成两种,需要回滚的不需要回滚扫描指针的。另外对于状态37,我们需要单独设计一个函数来识别机内码;
  2. 需要生成不固定机内码的:对于状态2、5,在识别出状态之后还需要进行转化,如将字符串转化为数字等这样的操作。

根据上面的抽象,我们可以写出几个状态函数F:

	void* State_Function_0(const char&, byte);
	void* State_Function_2(const char&, byte);
	void* State_Function_5(const char&, byte);
	void* State_Function_37(const char&, byte);
	void* State_Function_Other(const char&, byte);

其中0状态是用于剔除空白格和换行的;
另外还有入口函数

	Word_Value Lex_Analyze();
	void* State_Function_Other(const char&, byte);
	bool Set_Source_File(const char* File);

对于运行函数Lex_Analyze,程序运行流程大致如下:

  1. 检查源文件是否扫描完,源文件是否载入等等情况;
  2. 剔除空格,换行符等特殊字符;
  3. 运行DFA类的Run函数,如果运行失败,则抛出异常;
  4. 运行正常,重置DFA,返回结果;

运行结果

对于这个阶段来说,任意可读字符的输入都是符合条件的,如标识符abc123将会被识别为{0,"abc"}{1,123}这两个机内码,所以异常抛出暂时无法测试
在这里插入图片描述

源码

头文件

#pragma once
#include<string>
#include<vector>
#include<map>
#include"VarType.h"
#include"DFA.hpp"
using namespace std;
using namespace DFA;
typedef struct {
	byte Group_Id;
	union
	{
		unsigned long Value;
		string* Str;
	};
}Word_Value;

namespace LexicalAnalyzer_VarType {
	union Symbal_Tuple_Value
	{
		string* Marker;
		int Constant;
	};

	struct Symbal_Tuple {
		byte Type_Id;
		Symbal_Tuple_Value Value;
		unsigned long Source_Line;

		Symbal_Tuple(byte Id, unsigned long Line, void* Pt);
	};
}
namespace Lexical_Analyzer_Label {
	constexpr byte Marker = 0;
	constexpr byte Constant = 1;
	constexpr byte Math_Op = 2;
	constexpr byte Logic_Op = 3;
	constexpr byte Separtor = 4;
	constexpr byte Reversed = 5;
	constexpr byte Bit_Op = 6;
	constexpr byte Error = -1;// )
};



class Lexical_Analyzer {
public:
	Lexical_Analyzer();
	static vector<byte> Valid_State ;
	static vector<byte> Termin_State;
	static byte Start_State;
	static vector<State_Transfer_Tuple<char>> State_Transfer_Matrix;
	map<byte, State_Callback_Fun<char>> States_Fun;

	static map<byte, Word_Value> DFAState_TypeId_Mapping;
	static map<string, byte> Reversed_Word_Mapping;
	static map<char, byte> Separtor_Mapping;

	char* InputSource = NULL;
	unsigned long File_Length;
	unsigned long Begin_Pt = 0;
	unsigned long End_Pt = 0;
	unsigned long Row = 0;
	unsigned long Col = 0;
	bool IsEnd=false;
	Dfa<char> Lex_DFA;
	//*******回滚和同步指针********//
	void RollbackEndPt();
	void SynBeginEndPt();
	//*******回滚和同步指针********//
	//*******状态函数F********//
	void* State_Function_0(const char&, byte);
	void* State_Function_2(const char&, byte);
	void* State_Function_5(const char&, byte);
	void* State_Function_37(const char&, byte);
	void* State_Function_Other(const char&, byte);

	//*******状态函数F********//

	Word_Value Lex_Analyze();
	bool Set_Source_File(const char* File);
	
};

cpp

#include "Lexical_Analyzer.h"
#include <string>
#include<stdlib.h>
#include"DFA.hpp"
#include<cstring>
#include<stdlib.h>
#pragma warning(disable:4996)
vector<byte> Lexical_Analyzer::Valid_State = { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,38,39 };
vector<byte> Lexical_Analyzer::Termin_State = { 2, 5, 7, 8, 10, 11, 13, 14, 16,  17, 19,
20, 22, 38,23,25,39,26,28,29,31,32,34,35,36,37,38,39 };
vector<State_Transfer_Tuple<char>> Lexical_Analyzer::State_Transfer_Matrix = {
{0,[](char a)->bool {return a == ' ' || a == '\n'; },0}
,
{ 0,[](char Char)->bool {return (Char <= 'Z' && Char >= 'A') || (Char <= 'z' && Char >= 'a') || Char == '_'; },1 }
,
{ 1,[](char Char)->bool {return (Char <= 'Z' && Char >= 'A') || (Char <= 'z' && Char >= 'a') || Char == '_'; },1 }
,
{ 1,[](char Char)->bool {return !((Char <= 'Z' && Char >= 'A') || (Char <= 'z' && Char >= 'a') || Char == '_'); },2 }
,
{ 0,[](char Char)->bool {return Char >= '0' && Char <= '9'; },4 }
,
{ 4,[](char Char)->bool {return Char >= '0' && Char <= '9'; },4 }
,
{ 4,[](char Char)->bool {return !(Char >= '0' && Char <= '9'); },5 }
,
{ 0,[](char Char)->bool {return Char == '+'; },6 }
,
{ 6,[](char Char)->bool {return Char == '+'; },8 }
,
{ 6,[](char Char)->bool {return Char != '+'; },7 }
,
{ 0,[](char Char)->bool {return Char == '-'; },9 }
,
{ 9,[](char Char)->bool {return Char == '-'; },11 }
,
{ 9,[](char Char)->bool {return Char != '-'; },10 }
,
{ 0,[](char Char)->bool {return Char == '*'; },12 }
,
{ 12,[](char Char)->bool {return Char != '*'; },13 }
,
{ 12,[](char Char)->bool {return Char == '*'; },14 }
,
{ 0,[](char Char)->bool {return Char == '/'; },15 }
,
{ 15,[](char Char)->bool {return Char == '/'; },17 }
,
{ 15,[](char Char)->bool {return Char != '/'; },16 }
,
{ 0,[](char Char)->bool {return Char == '!'; },18 }
,
{ 18,[](char Char)->bool {return Char != '!'; },19 }
,
{ 18,[](char Char)->bool {return Char == '='; },20 }
,
{ 0,[](char Char)->bool {return Char == '<'; },21 }
,
{ 21,[](char Char)->bool {return Char != '/' && Char != '<'; },22 }
,
{ 21,[](char Char)->bool {return Char == '<'; },38 }
,
{ 21,[](char Char)->bool {return Char == '='; },23 }
,
{ 0,[](char Char)->bool {return Char == '>'; },24 }
,
{ 24,[](char Char)->bool {return Char != '>' && Char != '='; },25 }
,
{ 24,[](char Char)->bool {return Char == '>'; },39 }
,
{ 24,[](char Char)->bool {return Char == '='; },26 }
,
{ 0,[](char Char)->bool {return Char == '='; },27 }
,
{ 27,[](char Char)->bool {return Char != '='; },28 }
,
{ 27,[](char Char)->bool {return Char == '='; },29 }
,
{ 0,[](char Char)->bool {return Char == '&'; },30 }
,
{ 30,[](char Char)->bool {return Char != '&'; },31 }
,
{ 30,[](char Char)->bool {return Char == '&'; },32 }
,
{ 0,[](char Char)->bool {return Char == '|'; },33 }
,
{ 33,[](char Char)->bool {return Char != '|'; },34 }
,
{ 33,[](char Char)->bool {return Char == '|'; },35 }
,
{ 0,[](char Char)->bool {return Char == '~'; },36 }
,
{ 0,
[](char Char)->bool {
	constexpr char Contrast_Str[] = "()[]{};,";
	for (int i = 0; i < sizeof(Contrast_Str); i++)
	{
		if (Char == Contrast_Str[i])
		return true;
		}
		return false;
}
,37
} 
};

byte Lexical_Analyzer::Start_State = 0;

typedef pair<byte, Word_Value> Pair_Word_Value;
map<byte, Word_Value> Lexical_Analyzer::DFAState_TypeId_Mapping = {
	   Pair_Word_Value(2,{0,0}),
	   Pair_Word_Value(5,{1,0}),
	   Pair_Word_Value(7,{2,0}),
	   Pair_Word_Value(8,{2,7}),
	   Pair_Word_Value(10,{2,1}),
	   Pair_Word_Value(11,{2,6}),
	   Pair_Word_Value(13,{2,2}),
	   Pair_Word_Value(14,{2,4}),
	   Pair_Word_Value(16,{2,3}),
	   Pair_Word_Value(17,{2,5}),
	   Pair_Word_Value(19,{3,0}),
	   Pair_Word_Value(20,{3,3}),
	   Pair_Word_Value(22,{3,1}),
	   Pair_Word_Value(23,{3,4}),
	   Pair_Word_Value(25,{3,2}),
	   Pair_Word_Value(26,{3,5}),
	   Pair_Word_Value(28,{4,6}),
	   Pair_Word_Value(29,{3,8}),
	   Pair_Word_Value(31,{6,1}),
	   Pair_Word_Value(32,{3,6}),
	   Pair_Word_Value(34,{6,2}),
	   Pair_Word_Value(35,{3,7}),
	   Pair_Word_Value(36,{6,0}),
	   Pair_Word_Value(38,{6,3}),
	   Pair_Word_Value(39,{6,4}),

};
typedef pair<string, byte> Pair_Type_Id;
map<string, byte> Lexical_Analyzer::Reversed_Word_Mapping = { \
		Pair_Type_Id(string("if"),0),
		Pair_Type_Id(string("while"), 1),
		Pair_Type_Id(string("do"), 2),
		Pair_Type_Id(string("for"), 3),
		Pair_Type_Id(string("int"), 4),
		Pair_Type_Id(string("float"), 5),
		Pair_Type_Id(string("char"), 6),
		Pair_Type_Id(string("unsigned"), 7),
		Pair_Type_Id(string("double"), 8),
};
typedef pair<char, byte> Pair_Sepator;
map<char, byte> Lexical_Analyzer::Separtor_Mapping = { \
		Pair_Sepator('(',0),
		Pair_Sepator(')', 1),
		Pair_Sepator('[', 2),
		Pair_Sepator(']', 3),
		Pair_Sepator('{', 4),
		Pair_Sepator('}', 5),
		Pair_Sepator(';', 7),
		Pair_Sepator(',', 8),
};

void Lexical_Analyzer::RollbackEndPt() {
	End_Pt--;
}
void Lexical_Analyzer::SynBeginEndPt() {
	Begin_Pt = End_Pt;
}

Lexical_Analyzer::Lexical_Analyzer() {
	State_Callback_Fun<char> F = std::bind(&Lexical_Analyzer::State_Function_0, this, placeholders::_1, placeholders::_2);
	States_Fun[0] = F;
	F = std::bind(&Lexical_Analyzer::State_Function_2, this, placeholders::_1,placeholders::_2);
	States_Fun[2] = F;
	F= std::bind(&Lexical_Analyzer::State_Function_5, this, placeholders::_1, placeholders::_2);
	States_Fun[5] = F;
	F = std::bind(&Lexical_Analyzer::State_Function_37, this, placeholders::_1, placeholders::_2);
	States_Fun[37] = F;
	F = std::bind(&Lexical_Analyzer::State_Function_Other, this, placeholders::_1, placeholders::_2);
	for (byte i:Termin_State)
	{
		if (i != 2 && i != 5 && i!=37) {
			States_Fun[i] = F;
		}
	}
	Lex_DFA.Set_Start_State(Start_State);
	Lex_DFA.Set_Termin_State(Termin_State);
	Lex_DFA.Set_Transfer_Matrix(State_Transfer_Matrix);
	Lex_DFA.Set_Termin_State(Termin_State);
	Lex_DFA.Set_Valid_States(Valid_State);
	Lex_DFA.Set_State_Fun(States_Fun);
	Lex_DFA.Set_Input_Check([](char&) ->bool {return true; });
}

Word_Value Lexical_Analyzer::Lex_Analyze() {

	if (!InputSource)
		throw exception("No Input File!\n");
	Word_Value* Result=NULL;
	if (End_Pt == File_Length) {
		IsEnd = true;
		Word_Value Placeholder = { 0,0 };
		return Placeholder;
	}
	while (InputSource[End_Pt])
	{
		char Current_Char = InputSource[End_Pt++];
		Col++;
		if (Current_Char == '\n') {
			Row++;
			Col = 0;
		}
		if (Current_Char == ' ') {
		}
		if (!Lex_DFA.Run(Current_Char, (void**)&Result)) {
			string Exception_Info = "Syntax Wrong at Line " + to_string(Row)  + "\n";
			throw Exception_Info;
		}
		if (Lex_DFA.Is_Termination_State) {
			Lex_DFA.Restart();
			return *Result;
		}
			
	}
}
void* Lexical_Analyzer::State_Function_0(const char&, byte) {
	Begin_Pt++;
	return NULL;
}
void* Lexical_Analyzer::State_Function_2(const char& Input,byte Current_State) {
	Word_Value* Result = new Word_Value;
	this->RollbackEndPt();
	string* TmpStr = new string;
	for (int i = this->Begin_Pt; i < this->End_Pt; i++)
	{
		((string*)TmpStr)->push_back(*(this->InputSource + i));
	}
	map<string,byte>::iterator It=Reversed_Word_Mapping.find(*TmpStr);
	if (It != Reversed_Word_Mapping.end()) {
		Result->Group_Id = 5;
		Result->Value = It->second;
	}
	else {
		*Result = DFAState_TypeId_Mapping.find(Current_State)->second;
		Result->Str = TmpStr;
	}
	this->SynBeginEndPt();
	return Result;
}

void* Lexical_Analyzer::State_Function_5(const char& Input, byte Current_State) {
	Word_Value* Result = new Word_Value;
	this->RollbackEndPt();
	string* TmpStr = new string;
	for (int i = this->Begin_Pt; i < this->End_Pt; i++)
	{
		((string*)TmpStr)->push_back(*(this->InputSource + i));
	}
	*Result = DFAState_TypeId_Mapping.find(Current_State)->second;
	Result->Value = strtoul(TmpStr->c_str(), NULL, 10);
	delete TmpStr; 
	this->SynBeginEndPt();
	return Result;
}
void* Lexical_Analyzer::State_Function_37(const char& Input, byte Current_State) {
	map<char, byte>::iterator It = Separtor_Mapping.find(Input);
	if (It == Separtor_Mapping.end())
		throw new exception();
	Word_Value* Result = new Word_Value;
	Result->Group_Id = 4;
	Result->Value = It->second;
	this->SynBeginEndPt();
	return Result;
}
void* Lexical_Analyzer::State_Function_Other(const char& Input, byte Current_State) {
	Word_Value* Result = new Word_Value;
	switch (Current_State)
	{
	case 7:
	case 10:
	case 13:
	case 16:
	case 19:
	case 22:
	case 25:
	case 28:
	case 31:
	case 34:
		this->RollbackEndPt();
		break;
	default:
		break;
	}
	*Result = DFAState_TypeId_Mapping.find(Current_State)->second;
	this->SynBeginEndPt();
	return Result;
}

bool Lexical_Analyzer::Set_Source_File(const char* File_Path) {
	FILE* fp = fopen(File_Path, "r");
	if (!fp)
		return false;
	fseek(fp, 0, 0);
	fseek(fp, 0, SEEK_END);
	File_Length = ftell(fp);
	fseek(fp, 0, 0);
	InputSource = new char[File_Length + 1];
	fread((void*)InputSource, 1, File_Length, fp);
	InputSource[File_Length] = '\0';
	fclose(fp);
	return true;
}




  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 构造一个词法分析器的步骤如下: a. 定义所有可能的词法单元 b. 根据定义编正则表达式 c. 将正则表达式转换为NFA d. 将NFA转换为DFA e. 编代码实现DFA 2. 从NFA转DFA的步骤如下: a. 将NFA中的ε转换为普通的字符 b. 对于每个状态集合,找到所有可能的转换,即将所有状态集合中的状态进行合并 c. 对于新的状态集合,重复步骤b直至没有新的状态集合出现 d. 标记开始和结束状态 e. 编代码实现DFA 示例: 假设我们要构造一个词法分析器,能够识别出所有的数字和变量名,其中变量名由字母和数字组成,但必须以字母开头。我们可以按照以下步骤构造词法分析器: a. 定义词法单元: 数字:[0-9]+ 变量名:[a-zA-Z][a-zA-Z0-9]* b. 根据定义编正则表达式: 数字:[0-9]+ 变量名:[a-zA-Z][a-zA-Z0-9]* c. 将正则表达式转换为NFA: 数字:0-9 -> [0-9]+ 变量名:a-zA-Z -> [a-zA-Z] -> [a-zA-Z0-9]* d. 将NFA转换为DFA: 数字:0-9 -> [0-9]+ 变量名:a-zA-Z -> [a-zA-Z] -> [a-zA-Z0-9]* 状态集合:{0} -> {1} -> {2} -> {3} e. 编代码实现DFA: // DFA的状态集合 const states = [ { id: 0, isStart: true }, { id: 1 }, { id: 2 }, { id: 3, isEnd: true }, ]; // DFA的转换表 const transitions = [ { from: 0, to: 1, input: /[a-zA-Z]/ }, { from: 1, to: 2, input: /[a-zA-Z0-9]/ }, { from: 2, to: 2, input: /[a-zA-Z0-9]/ }, { from: 1, to: 3, input: null }, { from: 2, to: 3, input: null }, { from: 0, to: 1, input: /[0-9]/ }, { from: 1, to: 2, input: /[0-9]/ }, { from: 2, to: 2, input: /[0-9]/ }, { from: 1, to: 3, input: null }, { from: 2, to: 3, input: null }, ]; // DFA的输入字符串 const input = '123abc'; // DFA的当前状态 let currentState = states.find(s => s.isStart); // 遍历输入字符串,根据转换表进行状态转换 for (let i = 0; i < input.length; i++) { const transition = transitions.find(t => t.from === currentState.id && t.input.test(input[i])); if (!transition) { console.error(`Invalid input ${input[i]} at index ${i}`); break; } currentState = states.find(s => s.id === transition.to); } // 判断最终状态是否为结束状态 if (!currentState.isEnd) { console.error('Invalid input, input does not match any lexeme'); } else { console.log(`Input matches lexeme ${input}`); }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值