C++-c语言词法分析器

news2025/4/17 9:30:09

一、运行截图

  1. 对于 Test.c 的词法分析结果
  • 在这里插入图片描述
  1. 对于词法分析器本身的源代码的分析结果
  • 在这里插入图片描述

二、主要功能

经过不断的修正和测试代码,分析测试结果,该词法分析器主要实现了以下功能:

1. 识别关键字

  • 实验要求:if else while do for main return int float double char。以及:
  • 数据类型关键字 void unsigned long enum static short signed struct union;
  • 控制语句关键字 continue break switch case default goto;
  • 存储类型关键字 auto static extern register;
  • 其他关键字 const volatile sizeof typedef;
  • 预编译指令 #xxx。

2. 识别运算符

  • 实验要求:= + - * / % < <= > >= != ==
  • 算术运算符 ++ –
  • 逻辑运算符 && || !
  • 位运算符 & | ^ ~ << >>
  • 赋值运算符 += -= *= /= %= <<= >>= &= ^= |=
  • 杂项运算符 , ? : -> .

3. 识别界限符

  • 实验要求:; ( ) { }
  • 其他:[ ]

4. 识别常量

  • 实验要求:无符号十进制整型常量,正规式为:(1-9)(0-9)*
  • 无符号二进制整型常量,正规式为: 0(B|b)(0-1)*
  • 无符号八进制整型常量,正规式为: 0(0-7)*
  • 无符号十六进制整型常量,正规式为: 0(X|x)(0-9|a-f|A-F)*
  • 字符串常量,正规式为: “(all char)*”
  • 字符常量,正规式为: ‘(all char)*’

5. 识别标识符

  • 实验要求:以字母开头,正规式为:letter(letter|digit)*
  • 以下划线开头,正规式为:_ (letter|digit|$ | _) *
  • 以美元符号开头,正规式为:$ (letter|digit|$ | _ ) *

6. 识别其他符号

  • 实验要求:空格符(’ ‘),制表符(’\t’),换行符(‘\n’)
  • 单行注释(“//”)
  • 多行注释(“/*”)
  • 转义字符(‘\’)

特别的,在预处理阶段,识别单/多行注释时,遇到了一个小问题,由于要支持字符串常量和字符常量,而该常量中可能包含//,/*,导致将字符串内容识别为注释,另外,由于需要支持转义字符‘\’的存在,正确识别的字符串,也成为了一大问题,在多次修改匹配代码后,终于将问题解决。

7. 词法高亮

利用词法分析的token结果,按不同的类型码,对源代码文件进行着色输出。

运算符和界限符:黄色。
关键字:淡蓝色。
无符号二,八,十,十六进制整型常量:淡红色。
标识符:淡绿色。
字符串常量:淡黄色。

8. 词法错误处理

当朴素匹配或者正规匹配失败,或者匹配结束后,回退字符之前,出现非法字符时,对相应的错误进行记录并在分析完毕后进行输出。

目前已处理错误:未找到匹配的界限符()]}),多行注释未找到结束符(*/),出现未定义的字符(@¥`)。

值得注意的一点,当遇到未处理的词法错误时,程序存在可能的崩溃隐患。

三、项目内容

1. 测试代码 Test.c

/**
 * used to test keywords
 * //ohhhhhhhhhhhhhhh
 */
void $Func$ForKey_2(int a, unsigned b)
{
start:	if (1){}else{}
	while (1) { continue; }
	do{}while (1);
	for (;;){          }}
	switch (1){case 1: break;default: break;}
	enum { run };
	goto start;
}

struct FStruct{int val = 0000x1234;};
union FUnion{int val = 0B1 + 0b1 + 01 + 0X1 + 0x1;};
extern i;

// used to test operator
void __FuncForOperation5(const float c, long d, signed e, short f)
{
	typedef int Moota;
	register int i = 1234 + sizeof(Moota) + sizeof("/**/hello world//\\") + sizeof('\a');
	volatile int j = i + 1 - 1 * 1 / 1 % 1 <= 1 < 1 > 1 >= 1 != 1 == 1;
	auto int m = (i++) + (++i) + (i && i || i & i & i | i ^ i << 1) + i >> 1 + ~i;
	m += 1;m -= 2;m *= 3;m / 4;m %= 5;m <<= 6;m >>= 7;m &= 8;m |= 9;m ^= 10;
	m = m ? 1 : 0;
	struct FStruct* Ohhh;Ohhh->val;
	struct FStruct Emmm;Emmm.val;
}

/*
int main(void)
{
	$Func$ForKey_2(1, 1);__FuncForOperation5(1, 1, 1, 1);
	return 0;
}

2. 项目代码 LexicalAnalyzer.cpp

/** Copyright Moota, Private. All Rights Reserved. */

#include <iostream>
#include <map>
#include <stack>
#include <vector>
#include <string>
#include <fstream>
#include "Windows.h"

/**
 * 词法分析器
 * 可以识别的单词种类包括以下部分(括号代表实验要求之外的单词)
 * 
 * (1) 关键字
 * if else while do for main return int float double char
 * (数据类型关键字 void unsigned long enum static short signed struct union)
 * (控制语句关键字 continue break switch case default goto)
 * (存储类型关键字 auto static extern register)
 * (其他关键字 const volatile sizeof typedef)
 * (预编译指令 #xxx)
 *  
 * (2) 运算符
 * = + - * / % < <= > >= != ==
 * (算术运算符 ++ --)
 * (关系运算符)
 * (逻辑运算符 && || !)
 * (位运算符 & | ^ ~ << >>)
 * (赋值运算符 += -= *= /= %= <<= >>= &= ^= |=)
 * (杂项运算符 , ? : -> .)
 * 
 * (3) 界限符
 * ; ( ) { }
 * ([ ])
 * 
 * (4) 常量
 * 正规式为 digit1 digit2*,只考虑无符号十进制整型常量,digit1包括1-9,digit2包括0-9)
 * (无符号二进制整型常量 0(B|b)(0-1)*)
 * (无符号八进制整型常量 0(0-7)*)
 * (无符号十六进制整型常量 0(X|x)(0-9|a-f|A-F)*)
 * (字符串常量 "(all char)*" )
 * (字符常量 '(all char)*' )
 * 
 * (5) 标识符
 * 正规式为 letter(letter|digit)*,区分大小写
 * (_(letter|digit|$)*)
 * ($(letter|digit|$)*)
 * 
 * (6) 其他符号
 * 空格符(' '),制表符('\t'),换行符('\n'),单行多行注释("//","\/\*") 应该在词法分析阶段被忽略
 */
class FLexicalAnalyzer
{
public:
	FLexicalAnalyzer()
	{
		SetConsoleTitle(L"Lexical Analyzer V1.2.6");
		ShowWindow(GetForegroundWindow(), SW_MAXIMIZE);
		SetConsoleOutputCP(65001);
	}

private:
	// 工具函数

	// 字符是否小写
	static inline bool IsLower(char Data)
	{
		return 'a' <= Data and Data <= 'z';
	}

	// 字符是否大写
	static inline bool IsUpper(char Data)
	{
		return 'A' <= Data and Data <= 'Z';
	}

	// 字符是否是字母字符
	static inline bool IsLetter(char Data)
	{
		return IsLower(Data) || IsUpper(Data);
	}

	// 字符是否是数字字符
	static inline bool IsDigit(char Data)
	{
		return '0' <= Data and Data <= '9';
	}

	// 读取文件
	std::string ReadFile(const std::string& FilePath)
	{
		std::string Result;
		std::ifstream InputFile(FilePath, std::ios::in);
		if (!InputFile.is_open())
		{
			std::cerr << "The file failed to open, perhaps you need to change the file path." << "\n";
			return Result;
		}
		char Ch;
		while (InputFile.peek() != EOF)
		{
			InputFile.get(Ch);
			Result += Ch;
		}
		InputFile.close();
		TokenizeData.FilePath = FilePath;
		return Result;
	}

	// 保存文件
	static void SaveFile(const std::string& Data, const std::string& FilePath)
	{
		std::ofstream OutputFile(FilePath, std::ios::out);
		OutputFile << Data;
		OutputFile.close();
	}

private:
	std::map<std::string, int> KeywordMap;	// 关键字符号表
	std::map<std::string, int> RegularMap;	// 正规(常量,标识符)符号表
	std::map<std::string, int> SpecialMap;	// 特殊(运算符,界限符)符号表

	// 单词序列数据
	struct FTokenData
	{
		std::string Token;		// 单词符号
		int Code = 0;			// 类别码
	};

	// 词法分析数据
	struct FTokenizeData
	{
		std::string FilePath;				// 文件地址
		std::string Result;					// 最终结果
		std::string Data;					// 待分析数据
		size_t Size = 0;					// 数据长度
		size_t Index = 0;					// 当前字符索引
		char Start = ' ';					// 当前字符
		FTokenData TokenData;				// 当前符号信息
		std::stack<int> Delimiter[3];		// 界限符栈
		size_t Lines = 0;					// 词法分析当前行
		std::vector<std::string> Errors;	// 词法分析错误池
		std::vector<std::string> Warnings;	// 词法分析警告池
	} TokenizeData;

	/**
	 * 初始化各个符号表
	 */
	void Initialize()
	{
		KeywordMap["main"] = 1;
		KeywordMap["if"] = 2;
		KeywordMap["else"] = 3;
		KeywordMap["while"] = 4;
		KeywordMap["do"] = 5;
		KeywordMap["for"] = 6;
		KeywordMap["return"] = 7;

		RegularMap["letter(letter|digit)*"] = 8;
		RegularMap["digit digit*"] = 9;
		RegularMap["\"(all char)*\""] = 200;
		RegularMap["\'(all char)*\'"] = 201;
		RegularMap["_(letter|digit|$)*"] = 202;
		RegularMap["$(letter|digit|$)*"] = 203;
		RegularMap["0(B|b)(0-1)*"] = 204;
		RegularMap["0(0-7)*"] = 205;
		RegularMap["0(X|x)(0-9 a-f)*"] = 206;

		SpecialMap["+"] = 10;
		SpecialMap["-"] = 11;
		SpecialMap["*"] = 12;
		SpecialMap["/"] = 13;
		SpecialMap["%"] = 14;
		SpecialMap[">"] = 15;
		SpecialMap[">="] = 16;
		SpecialMap["<"] = 17;
		SpecialMap["<="] = 18;
		SpecialMap["=="] = 19;
		SpecialMap["!="] = 20;
		SpecialMap["="] = 21;
		SpecialMap[";"] = 22;
		SpecialMap["("] = 23;
		SpecialMap[")"] = 24;
		SpecialMap["{"] = 25;
		SpecialMap["}"] = 26;
		SpecialMap["["] = 100;
		SpecialMap["]"] = 101;
		SpecialMap[","] = 102;
		SpecialMap[":"] = 103;
		SpecialMap["++"] = 104;
		SpecialMap["--"] = 105;
		SpecialMap["&&"] = 106;
		SpecialMap["||"] = 107;
		SpecialMap["!"] = 108;
		SpecialMap["&"] = 109;
		SpecialMap["|"] = 110;
		SpecialMap["^"] = 111;
		SpecialMap["~"] = 112;
		SpecialMap["<<"] = 113;
		SpecialMap[">>"] = 114;
		SpecialMap["+="] = 115;
		SpecialMap["-="] = 116;
		SpecialMap["*="] = 117;
		SpecialMap["/="] = 118;
		SpecialMap["%="] = 119;
		SpecialMap["<<="] = 120;
		SpecialMap[">>="] = 121;
		SpecialMap["&="] = 122;
		SpecialMap["|="] = 123;
		SpecialMap["^="] = 124;
		SpecialMap["?"] = 125;
		SpecialMap["->"] = 126;
		SpecialMap["."] = 127;

		KeywordMap["int"] = 27;
		KeywordMap["float"] = 28;
		KeywordMap["double"] = 29;
		KeywordMap["char"] = 30;
		KeywordMap["void"] = 31;
		KeywordMap["unsigned"] = 32;
		KeywordMap["long"] = 33;
		KeywordMap["const"] = 34;
		KeywordMap["continue"] = 35;
		KeywordMap["break"] = 36;
		KeywordMap["enum"] = 37;
		KeywordMap["switch"] = 38;
		KeywordMap["case"] = 39;
		KeywordMap["static"] = 40;
		KeywordMap["auto"] = 41;
		KeywordMap["short"] = 42;
		KeywordMap["signed"] = 43;
		KeywordMap["struct"] = 44;
		KeywordMap["union"] = 45;
		KeywordMap["goto"] = 46;
		KeywordMap["default"] = 47;
		KeywordMap["extern"] = 48;
		KeywordMap["register"] = 49;
		KeywordMap["volatile"] = 50;
		KeywordMap["sizeof"] = 51;
		KeywordMap["typedef"] = 52;
		KeywordMap["#"] = 53;

		std::cout << "///\n";
	}

	/**
	 * 数据预处理
	 * 主要处理制表符('\t')
	 * 空格符将在词法分析时自动进行忽略
	 * 换行符将在词法分析时作为报错的依据
	 */
	std::string Preprocess(const std::string& Data)
	{
		std::string Result;
		const size_t Size = Data.size();
		size_t Lines = 0;
		for (size_t i = 0; i < Size; ++i)
		{
			if (Data[i] == '"')
			{
				Result += Data[i];
				++i;
				while (i < Size && Data[i] != '"')
				{
					if (Data[i] == '\\')
					{
						Result += Data[i];
						++i;
					}
					if (i < Size)
					{
						Result += Data[i];
						++i;
					}
				}
				if (Data[i] == '"')
				{
					Result += Data[i];
				}
			}
			else if (Data[i] == '\'')
			{
				Result += Data[i];
				++i;
				while (i < Size && Data[i] != '\'')
				{
					if (Data[i] == '\\')
					{
						Result += Data[i];
						++i;
					}
					Result += Data[i];
					++i;
				}
				if (Data[i] == '\'')
				{
					Result += Data[i];
				}
			}
			else if (Data[i] == '/' && (i + 1) < Size && Data[i + 1] == '/')// 处理单行注释
			{
				while (i < Size && Data[i] != '\n')
				{
					++i;
				}
				if (Data[i] == '\n')
				{
					++Lines;
					Result += Data[i];
				}
			}
			else if (Data[i] == '/' && (i + 1) < Size && Data[i + 1] == '*')// 处理多行注释
			{
				i = i + 2;
				bool IsFound = false;
				while (i < Size)
				{
					if (Data[i] == '\n')
					{
						++Lines;
					}
					if (Data[i] == '*' && (i + 1) < Size && Data[i + 1] == '/')
					{
						IsFound = true;
						i = i + 2;
						break;
					}
					++i;
				}
				if (Data[i] == '\n')
				{
					++Lines;
				}
				if (!IsFound)
				{
					TokenizeData.Errors.push_back("ERR: " + TokenizeData.FilePath + " " + std::to_string(Lines) + " " + "no matching '*/' symbol was found.");
				}
			}
			else if (Data[i] == '\n')
			{
				++Lines;
				Result += Data[i];
			}
			else if (Data[i] == '\t')// 处理制表符
			{
				Result += ' ';
			}
			else
			{
				Result += Data[i];
			}
		}
		return Result;
	}

	/**
	 * 获取下一个有效字符,忽略空格符
	 */
	bool GetValidChar()
	{
		bool Result = false;
		while (TokenizeData.Index < TokenizeData.Size)
		{
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start != ' ')
			{
				Result = true;
				break;
			}
		}
		return Result;
	}

	/**
	 * 识别以字母为开始符号的
	 * 1. 关键字-letter(letter)*
	 * 2. 识别标识符-letter(letter|digit)*
	 */
	void TokenizeAlpha()
	{
		do
		{
			TokenizeData.TokenData.Token += TokenizeData.Start;
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
		}
		while (IsLetter(TokenizeData.Start) || IsDigit(TokenizeData.Start) || TokenizeData.Start == '$'|| TokenizeData.Start == '_');
		const auto Found = KeywordMap.find(TokenizeData.TokenData.Token);
		if (Found != KeywordMap.end())
		{
			TokenizeData.TokenData.Code = Found->second;
		}
		else
		{
			TokenizeData.TokenData.Code = RegularMap["letter(letter|digit)*"];
		}
		TokenizeData.Index--;
	}

	/**
	 * 识别以数字为开始符号的
	 * 1. 无符号十进制整型常量-digit digit*
	 */
	void TokenizeDigit()
	{
		if ('1' <= TokenizeData.Start && TokenizeData.Start <= '9')
		{
			do
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			}
			while (IsDigit(TokenizeData.Start));
			TokenizeData.TokenData.Code = RegularMap["digit digit*"];
			TokenizeData.Index--;
		}
		else
		{
			TokenizeData.TokenData.Token += TokenizeData.Start;
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == 'B' || TokenizeData.Start == 'b')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
				do
				{
					TokenizeData.TokenData.Token += TokenizeData.Start;
					TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
				}
				while (TokenizeData.Start == 0 || TokenizeData.Start == 1);
				TokenizeData.TokenData.Code = RegularMap["0(B|b)(0-1)*"];
				TokenizeData.Index--;
			}
			else if (TokenizeData.Start == 'X' || TokenizeData.Start == 'x')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
				do
				{
					TokenizeData.TokenData.Token += TokenizeData.Start;
					TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
				}
				while (IsDigit(TokenizeData.Start) || ('a' <= TokenizeData.Start and TokenizeData.Start <= 'f') || ('A' <= TokenizeData.Start and TokenizeData.Start <= 'F'));
				TokenizeData.TokenData.Code = RegularMap["0(X|x)(0-9 a-f)*"];
				TokenizeData.Index--;
			}
			else if ('0' <= TokenizeData.Start and TokenizeData.Start <= '7')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
				do
				{
					TokenizeData.TokenData.Token += TokenizeData.Start;
					TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
				}
				while ('0' <= TokenizeData.Start and TokenizeData.Start <= '7');
				TokenizeData.TokenData.Code = RegularMap["0(0-7)*"];
				TokenizeData.Index--;
			}
			else
			{
				TokenizeData.TokenData.Code = RegularMap["digit digit*"];
				TokenizeData.Index--;
			}
		}
	}

	/**
	 * 识别以非数字非字母为开始符号的
	 * 1. 运算符
	 * 2. 界限符
	 */
	void TokenizeSpecial()
	{
		for (auto& Special : SpecialMap)
		{
			if (TokenizeData.Start == Special.first[0])
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = Special.second;
				break;
			}
		}
		if (TokenizeData.Start == '(')
		{
			TokenizeData.Delimiter[0].push(TokenizeData.Start);
		}
		if (TokenizeData.Start == '[')
		{
			TokenizeData.Delimiter[1].push(TokenizeData.Start);
		}
		else if (TokenizeData.Start == '{')
		{
			TokenizeData.Delimiter[2].push(TokenizeData.Start);
		}
		else if (TokenizeData.Start == ')')
		{
			if (!TokenizeData.Delimiter[0].empty())
			{
				TokenizeData.Delimiter[0].pop();
			}
			else
			{
				TokenizeData.Errors.push_back("ERR: " + TokenizeData.FilePath + " " + std::to_string(TokenizeData.Lines) + " there is an unmatched ')' symbol.");
			}
		}
		else if (TokenizeData.Start == ']')
		{
			if (!TokenizeData.Delimiter[1].empty())
			{
				TokenizeData.Delimiter[1].pop();
			}
			else
			{
				TokenizeData.Errors.push_back("ERR: " + TokenizeData.FilePath + " " + std::to_string(TokenizeData.Lines) + " there is an unmatched ']' symbol.");
			}
		}
		else if (TokenizeData.Start == '}')
		{
			if (!TokenizeData.Delimiter[2].empty())
			{
				TokenizeData.Delimiter[2].pop();
			}
			else
			{
				TokenizeData.Errors.push_back("ERR: " + TokenizeData.FilePath + " " + std::to_string(TokenizeData.Lines) + " there is an unmatched '}' symbol.");
			}
		}
		else if (TokenizeData.Start == '!')
		{
			TokenizeData.TokenData.Code = SpecialMap["!"];
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == '=')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["!="];
			}
			else
			{
				TokenizeData.Index--;
			}
		}
		else if (TokenizeData.Start == '=')
		{
			TokenizeData.TokenData.Code = SpecialMap["="];
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == '=')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["=="];
			}
			else
			{
				TokenizeData.Index--;
			}
		}
		else if (TokenizeData.Start == '<')
		{
			TokenizeData.TokenData.Code = SpecialMap["<"];
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == '=')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["<="];
			}
			else if (TokenizeData.Start == '<')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["<<"];
				TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
				if (TokenizeData.Start == '=')
				{
					TokenizeData.TokenData.Token += TokenizeData.Start;
					TokenizeData.TokenData.Code = SpecialMap["<<="];
				}
				else
				{
					TokenizeData.Index--;
				}
			}
			else
			{
				TokenizeData.Index--;
			}
		}
		else if (TokenizeData.Start == '>')
		{
			TokenizeData.TokenData.Code = SpecialMap[">"];
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == '=')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap[">="];
			}
			else if (TokenizeData.Start == '>')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap[">>"];
				TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
				if (TokenizeData.Start == '=')
				{
					TokenizeData.TokenData.Token += TokenizeData.Start;
					TokenizeData.TokenData.Code = SpecialMap[">>="];
				}
				else
				{
					TokenizeData.Index--;
				}
			}
			else
			{
				TokenizeData.Index--;
			}
		}
		else if (TokenizeData.Start == '+')
		{
			TokenizeData.TokenData.Code = SpecialMap["+"];
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == '=')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["+="];
			}
			else if (TokenizeData.Start == '+')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["++"];
			}
			else
			{
				TokenizeData.Index--;
			}
		}
		else if (TokenizeData.Start == '-')
		{
			TokenizeData.TokenData.Code = SpecialMap["-"];
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == '=')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["-="];
			}
			else if (TokenizeData.Start == '-')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["--"];
			}
			else if (TokenizeData.Start == '>')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["->"];
			}
			else
			{
				TokenizeData.Index--;
			}
		}
		else if (TokenizeData.Start == '*')
		{
			TokenizeData.TokenData.Code = SpecialMap["*"];
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == '=')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["*="];
			}
			else
			{
				TokenizeData.Index--;
			}
		}
		else if (TokenizeData.Start == '/')
		{
			TokenizeData.TokenData.Code = SpecialMap["/"];
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == '=')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["/="];
			}
			else
			{
				TokenizeData.Index--;
			}
		}
		else if (TokenizeData.Start == '%')
		{
			TokenizeData.TokenData.Code = SpecialMap["%"];
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == '=')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["%="];
			}
			else
			{
				TokenizeData.Index--;
			}
		}
		else if (TokenizeData.Start == '&')
		{
			TokenizeData.TokenData.Code = SpecialMap["&"];
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == '=')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["&="];
			}
			else if (TokenizeData.Start == '&')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["&&"];
			}
			else
			{
				TokenizeData.Index--;
			}
		}
		else if (TokenizeData.Start == '|')
		{
			TokenizeData.TokenData.Code = SpecialMap["|"];
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == '=')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["|="];
			}
			else if (TokenizeData.Start == '|')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["||"];
			}
			else
			{
				TokenizeData.Index--;
			}
		}
		else if (TokenizeData.Start == '^')
		{
			TokenizeData.TokenData.Code = SpecialMap["^"];
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			if (TokenizeData.Start == '=')
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.TokenData.Code = SpecialMap["^="];
			}
			else
			{
				TokenizeData.Index--;
			}
		}
		else if (TokenizeData.Start == '"')
		{
			TokenizeData.TokenData.Code = RegularMap["\"(all char)*\""];
			TokenizeData.TokenData.Token += TokenizeData.Start;
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			while (true)
			{
				if (TokenizeData.Start == '"')
				{
					TokenizeData.TokenData.Token += TokenizeData.Start;
					TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
					break;
				}
				if (TokenizeData.Start == '\\')
				{
					TokenizeData.TokenData.Token += TokenizeData.Start;
					TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
				}
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			}
			TokenizeData.Index--;
		}
		else if (TokenizeData.Start == '\'')
		{
			TokenizeData.TokenData.Code = RegularMap["\'(all char)*\'"];
			TokenizeData.TokenData.Token += TokenizeData.Start;
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			while (true)
			{
				if (TokenizeData.Start == '\'')
				{
					TokenizeData.TokenData.Token += TokenizeData.Start;
					TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
					break;
				}
				if (TokenizeData.Start == '\\')
				{
					TokenizeData.TokenData.Token += TokenizeData.Start;
					TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
				}
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			}
			TokenizeData.Index--;
		}
		else if (TokenizeData.Start == '_')
		{
			TokenizeData.TokenData.Code = RegularMap["_(letter|digit|$)*"];
			do
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			}
			while (IsLetter(TokenizeData.Start) || IsDigit(TokenizeData.Start) || TokenizeData.Start == '$' || TokenizeData.Start == '_');
			TokenizeData.Index--;
		}
		else if (TokenizeData.Start == '$')
		{
			TokenizeData.TokenData.Code = RegularMap["$(letter|digit|$)*"];
			do
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			}
			while (IsLetter(TokenizeData.Start) || IsDigit(TokenizeData.Start) || TokenizeData.Start == '$' || TokenizeData.Start == '_');
			TokenizeData.Index--;
		}
		else if (TokenizeData.Start == '#')
		{
			TokenizeData.TokenData.Code = KeywordMap["#"];
			TokenizeData.TokenData.Token += TokenizeData.Start;
			TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			while (IsLetter(TokenizeData.Start))
			{
				TokenizeData.TokenData.Token += TokenizeData.Start;
				TokenizeData.Start = TokenizeData.Data[TokenizeData.Index++];
			}
			TokenizeData.Index--;
		}
		if (TokenizeData.TokenData.Code == 0)
		{
			TokenizeData.TokenData.Token = TokenizeData.Start;
			TokenizeData.Errors.push_back("ERR: " + TokenizeData.FilePath + " " + std::to_string(TokenizeData.Lines) + " there is an undefined " +
				TokenizeData.TokenData.Token + " character whose ascii code is " + std::to_string(static_cast<int>(TokenizeData.TokenData.Token[0])) + ".");
		}
	}

	/**
	 * 单词分析
	 */
	std::string Tokenize(const std::string& Data)
	{
		TokenizeData.Data = Data;
		TokenizeData.Index = 0;
		TokenizeData.Size = Data.size();

		while (GetValidChar())
		{
			TokenizeData.TokenData = {"", 0};

			if (TokenizeData.Start == '\n')
			{
				TokenizeData.Lines++;
			}
			else if (IsLetter(TokenizeData.Start))
			{
				TokenizeAlpha();
			}
			else if (IsDigit(TokenizeData.Start))
			{
				TokenizeDigit();
			}
			else
			{
				TokenizeSpecial();
			}
			if (!TokenizeData.TokenData.Token.empty())
			{
				TokenizeData.Result += "(" + TokenizeData.TokenData.Token + "," + std::to_string(TokenizeData.TokenData.Code) + ")" + "\n";
			}
		}
		return TokenizeData.Result;
	}

	/** 打印彩色字
	 * 0=黑色	1=蓝色	2=绿色	3=湖蓝色
	 * 4=红色	5=紫色	6=黄色   7=白色
	 * 8=灰色   9=淡蓝色	10=淡绿色 11=淡浅绿色
	 * 12=淡红色 13=淡紫色 14=淡黄色 15=亮白色
	 * @param ForeColor 字体颜色
	 * @param BackColor 字体背景颜色
	*/
	static void SetFontColor(int ForeColor, int BackColor)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), static_cast<WORD>(ForeColor + BackColor * 0x10));
	}

	//模板一下,方便调用,T表示任何可以被cout输出的类型
	template <typename T>
	static void CoutWithColor(T t, int ForeColor = 7, int BackColor = 0)
	{
		SetFontColor(ForeColor, BackColor);
		std::cout << t;
		SetFontColor(7, 0);
		Sleep(4);
	}

	/**
	 * 识别单词高亮
	 */
	static void Highlight(const std::string& SourceCode, const std::string& TokenData)
	{
		const size_t CodeSize = SourceCode.size();
		const size_t ContentSize = TokenData.size();
		size_t Index = 0;
		size_t Lines = 0;
		CoutWithColor(std::to_string(Lines) + "\t", 7);
		++Lines;
		for (size_t i = 0; i < CodeSize; ++i)
		{
			if (SourceCode[i] == '\n')
			{
				CoutWithColor(SourceCode[i] + std::to_string(Lines) + "\t", 7);
				++Lines;
			}
			else if (SourceCode[i] == ' ' || SourceCode[i] == '\t')
			{
				CoutWithColor(SourceCode[i], 7);
			}
			else if (SourceCode[i] == '/' && (i + 1) < CodeSize && SourceCode[i + 1] == '/')
			{
				std::string Temp;
				while (i < CodeSize && SourceCode[i] != '\n')
				{
					Temp += SourceCode[i++];
				}
				i--;
				CoutWithColor(Temp, 2);
			}
			else if (SourceCode[i] == '/' && (i + 1) < CodeSize && SourceCode[i + 1] == '*')
			{
				std::string Temp;
				Temp += SourceCode[i];
				Temp += SourceCode[i + 1];
				i = i + 2;
				while (i < CodeSize)
				{
					if (SourceCode[i] == '\n')
					{
						CoutWithColor(Temp, 2);
						CoutWithColor(SourceCode[i] + std::to_string(Lines) + "\t", 7);
						++Lines;
						++i;
						Temp = "";
					}
					else if (SourceCode[i] == '*' && (i + 1) < CodeSize && SourceCode[i + 1] == '/')
					{
						Temp += SourceCode[i++];
						Temp += SourceCode[i++];
						break;
					}
					else
					{
						Temp += SourceCode[i++];
					}
				}
				CoutWithColor(Temp, 2);
				i--;
			}
			else
			{
				std::string Doc;
				while (Index < ContentSize && TokenData[Index] != '\n')
				{
					Doc += TokenData[Index++];
				}
				if (TokenData[Index] == '\n')
				{
					Index++;
				}
				size_t Mid = 0;
				std::string Token;
				int Code = 0;

				// 寻找 , 分隔符
				for (size_t Pos = Doc.size() - 1; Pos != 0; --Pos)
				{
					if (Doc[Pos] != ',')
					{
						Mid = Pos - 1;
					}
					else
					{
						break;
					}
				}
				// 截取 Token
				for (size_t Start = 1; Start < Mid; ++Start)
				{
					Token += Doc[Start];
				}
				// 截取 Code
				for (size_t Start = Mid + 1; Start < (Doc.size() - 1); ++Start)
				{
					Code = Code * 10 + (Doc[Start] - '0');
				}

				// 判断类型颜色
				int ForeColor = 15;
				if ((10 <= Code and Code <= 26) or (100 <= Code and Code <= 127)) // 运算符和界限符
				{
					ForeColor = 6;
				}
				else if ((1 <= Code and Code <= 7) or (27 <= Code and Code <= 53)) // 关键字
				{
					ForeColor = 9;
				}
				else if (Code == 9 or (204 <= Code and Code <= 206)) // 无符号二,八,十,十六进制整型常数
				{
					ForeColor = 12;
				}
				else if (Code == 8 or Code == 202 or Code == 203) // 标识符
				{
					ForeColor = 10;
				}
				else if (Code == 200 or Code == 201) // 字符串常量
				{
					ForeColor = 14;
				}
				CoutWithColor(Token, ForeColor);
				i += Token.size() - 1;
			}
		}
		CoutWithColor("\n", 7);
	}

	/**
	 * 显示词法分析结果
	 */
	void ShowResult() const
	{
		std::cout << "///\n";
		CoutWithColor("VER: Copyright moota, private. all rights reserved.\n", 7);
		CoutWithColor("INF: Lexical analysis is finished, " + std::to_string(TokenizeData.Warnings.size()) + " warnings, " +
					  std::to_string(TokenizeData.Errors.size()) + " errors.\n", 14);
		for (auto& Info : TokenizeData.Warnings)
		{
			CoutWithColor(Info + "\n", 9);
		}
		for (auto& Info : TokenizeData.Errors)
		{
			CoutWithColor(Info + "\n", 12);
		}
	}

public:
	/**
	 * 调试词法分析器
	 */
	void Main()
	{
		// 初始词法分析器
		Initialize();

		// 读取处理文件
		const std::string Doc = ReadFile("Test.c");
		SaveFile(Doc, "TestRead.txt");

		// 预处理读入数据
		const std::string PreDoc = Preprocess(Doc);
		SaveFile(PreDoc, "TestPre.txt");

		// 识别单词符号
		const std::string Token = Tokenize(PreDoc);
		SaveFile(Token, "TestToken.txt");

		// 识别单词高亮
		Highlight(Doc, Token);

		// 显示词法分析结果
		ShowResult();

		getchar();
	}
};

int main()
{
	FLexicalAnalyzer LexicalAnalyzer;
	LexicalAnalyzer.Main();
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/414670.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

常见排序算法

目录 一、插入排序 1、直接插入排序 2、希尔排序(缩小增量插入排序&#xff09; 二、选择排序 三、堆排序 四、冒泡排序 五、快速排序&#xff08;递归&#xff09; 1、交换法 2、挖坑法 3、前后指针法&#xff08;推荐&#xff09; 4、快排再优化 六、快速排序&…

spring常用注解(全)

一、前言 Spring的一个核心功能是IOC&#xff0c;就是将Bean初始化加载到容器中&#xff0c;Bean是如何加载到容器的&#xff0c;可以使用Spring注解方式或者Spring XML配置方式。 Spring注解方式减少了配置文件内容&#xff0c;更加便于管理&#xff0c;并且使用注解可以大大…

Vue学习笔记(6. 组件之间传值)

1. 组件基本语法 (1) template (2) script (3) style 2. 父组件传值&#xff0c;子组件接值 (1) 父组件传值给子组件 (2) 子组件接收父组件的传值&#xff08;随时接收&#xff09; 子组件的值会随着父组件值的变更而变更。但是子组件变更&#xff0c;不会影响父组件的数据…

Jetson nano部署剪枝YOLOv8

目录前言一、YOLOv8模型剪枝训练1. Pretrain[option]1.1 项目的克隆1.2 数据集1.3 训练2. Constraint training3. Prune4. finetune二、YOLOv8模型剪枝部署1. 源码下载2. 环境配置2.1 trtexec环境变量设置3. ONNX导出3.1 Transpose节点的添加3.2 Resize节点解析的问题4. 运行4.…

【RabbitMQ学习日记】—— 发布确认与交换机

一、发布确认 1.1 发布确认的原理 生产者将信道设置成 confirm 模式&#xff0c;一旦信道进入 confirm 模式&#xff0c;所有在该信道上面发布的消息都将会被指派一个唯一的 ID(从 1 开始)&#xff0c;一旦消息被投递到所有匹配的队列之后&#xff0c;broker就会发送一个确认…

小白快速学习Markdown

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…

做好Python工程师,首先你需要做好的几件事

做好Python工程师&#xff0c;需要做好的几件事&#xff0c;我想分享给大家。首先千万不要做事周折。在你提问之前&#xff0c;先好好想一想&#xff0c;这个问题自己能不能解决。如果能解决&#xff0c;尽量自己解决&#xff1b;如果解决不了&#xff0c;那就要把你的问题描述…

大宗商品进口管理软件可以帮助企业解决哪些?

什么是大宗商品贸易&#xff1f;简单讲就是大宗商品在国际上自由流通。以贸易的形式&#xff0c;把商品从价格低的地方拉到价格高的地方出售。大宗商品是指可进入流通领域&#xff0c;可在工农业领域生产与消费使用的大批量买卖的。主要包括的类别有&#xff1a;能源商品、基础…

网络编程答疑融合连环tcp/nio/bio/redis/redisson/lettuce/netty/dubbo

如果有不对的地方, 欢迎在评论区指正: bio 1.1 请求-响应模型. 对于接收方, serverSocket.accept() 为每个请求(连接)安排一个线程 1.2浪费(阻塞占比大): socket.getInputStream().read()调用是阻塞的, 实际情况对于常见的web应用, 大家都是长连接, 同一时刻, 阻塞在此在线程会…

蓝牙技术|苹果获空间音频新专利,AirPods可动态调整声学输出

美国商标和专利局&#xff08;USPTO&#xff09;公示的清单显示&#xff0c;苹果在近日获得了一项名为“测定虚拟聆听环境”的新专利。据悉&#xff0c;该技术可以改善用户的聆听体验&#xff0c;增强空间音频的沉浸感&#xff0c;未来有望应用在AirPods上。 这项专利技术可以…

第二章 Linux目录结构

第二章 Linux目录结构linux的文件系统是采用级层式的树状目录结构&#xff0c;在此结构中的最上层是根目录“/”&#xff0c;然后在此目录下再创建其他的 目录。 2)深刻理解 linux 树状文件目录是非常重要的。3)记住一句经典的话:在Linux世界里&#xff0c;一切皆文件(!!)4)示意…

4.12--计算机网络之TCP篇之TCP 协议的缺陷+如何基于 UDP 协议实现可靠传输?--(复习+大总结)---沉下心来(加油呀)

TCP 协议四个方面的缺陷&#xff1a; 1.升级 TCP 的工作很困难&#xff1b; TCP 协议是在内核中实现的&#xff0c;应用程序只能使用不能修改&#xff0c;如果要想升级 TCP 协议&#xff0c;那么只能升级内核。 而升级内核这个工作是很麻烦的事情 2.TCP 建立连接的延迟&#x…

Linux -- 进程间通信

文章目录1. vscode软件下载和使用1.1 下载1.1.1 解决下载慢问题1.1.2 推荐下载链接1.2 vscode是什么1.3 Windows本地vscode使用1.4 远程连接linux1.5 推荐插件2. 进程间通信目的3. 为什么需要通信4. 匿名管道4.1 原理4.2 代码案例4.3 玩一玩(进程池)4.3.1 模型4.3.2 代码5. 命名…

STM32+W5500实现以太网通信

STM32系列32位微控制器基于Arm Cortex-M处理器&#xff0c;旨在为MCU用户提供新的开发自由度。它包括一系列产品&#xff0c;集高性能、实时功能、数字信号处理、低功耗/低电压操作、连接性等特性于一身&#xff0c;同时还保持了集成度高和易于开发的特点。本例采用STM32作为MC…

【开懂C++】命名空间 函数重载 缺省参数

目录一.命名空间二.缺省参数三.函数重载一.命名空间 在编写C语言代码时&#xff0c;当工程较大时&#xff0c;很容易产生变量命名冲突的情况——一般有两种冲突的情况 1.变量名与库中的函数名、关键字冲突。2.工程模块化搭建时不同文件的命名冲突。 而C为了优化这一缺陷&#…

安装Ubuntu系统后的实用工具配置指南

1. 修改软件源 Ubuntu 默认的软件源是境外的&#xff0c;速度上会有些问题&#xff0c;我们可以在Software & Updates(软件和更新)中选择国内的镜像。 一般我们选择清华源或者阿里云源。 2. 安装chorme浏览器 在ubuntu下我比较习惯用火狐浏览器和谷歌浏览器。 谷歌浏览…

vue 自定义指令directive的使用场景

1. 一个指令定义对象可以提供如下几个钩子函数(均为可选) bind:只调用一次&#xff0c;指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted:被绑定元素插入父节点时调用(仅保证父节点存在&#xff0c;但不一定已被插入文档中)。update:只要当前元素不被…

Leetcode.1971 寻找图中是否存在路径

题目链接 Leetcode.1971 寻找图中是否存在路径 easy 题目描述 有一个具有 n 个顶点的 双向 图&#xff0c;其中每个顶点标记从 0 到 n - 1&#xff08;包含 0 和 n - 1&#xff09;。图中的边用一个二维整数数组 edges 表示&#xff0c;其中 edges[i] [ui, vi]表示顶点 ui和顶…

关于maxwell

这里写目录标题什么是Maxwell如何使用MaxwellMaxwell是一个mysql二进制binlog日志分析工具&#xff0c;Java语言编写&#xff0c;功能十分强大&#xff0c;可以将日志转换成json并发送到kafka&#xff0c;redis&#xff0c;rabbitmq等中间组件&#xff0c;因为最近在理解怎样在…

QtSqlite加密--QtCipherSqlitePlugin的使用

文章目录QtSqlite加密第一步&#xff1a;环境准备第二步&#xff1a;连接数据库第三步&#xff1a;数据库操作第四步&#xff1a;使用新的可视化工具查看数据库数据QtSqlite加密 上次说了QxOrm的数据库连接、映射和基础的增删改查&#xff0c;但是我们在使用数据库的时候并不希…