编译原理词法分析器(C/C++)

这篇具有很好参考价值的文章主要介绍了编译原理词法分析器(C/C++)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言&思路

        词法分析器不用多说,一开始我还不知道是什么样的,看了下别人的博客,再看看书,原来是输出二元组,这不就是字符串操作嘛。然后细看几篇博客,发现大都是用暴力判断来写的。我对代码重复性比较高的方法不太感冒,不是说我编程有多好,就是单纯的不喜欢。

        于是我就想到了用偏移量的方法,先弄好单词分类器,再用几个数组将关键字、运算符、界符的所有定义的字符串保存为全局变量,顺序要按单词分类器的顺序,然后根据这三种字符串在表中的位置,定一个偏移量。当输入的时候,将字符串进行切割提取,然后放到全局数组里面判断,返回下标加上偏移量,这样就可以得到这一个字符串在单词表中的位置(种别码)了,最后根据种别码的范围可以知道数据类型。

        上面的思路说起来比较复杂,主要是我表达能力不太好,其实一看代码就明白了。

        哦对了,补充一句,我要分析的语言是C语言,然后也是用C语言来写。但是因为有使用布尔类型,所以需要C++的运行环境。另外,我的代码没有代码检错。(老师没有要求)

NFA和DFA图

        这两个图不是我画的,看看就好。        

        我要写的词法分析器有六个类型:关键字、界符、运算符、标识符、整型和浮点型。

编译原理词法分析器(C/C++)       编译原理词法分析器(C/C++)

 单词分类表

        关键字在网上找了32个,然后自己加了几个,运算符和界符都是百度找的,其中,运算符有>>=这种三个字符的,因为不是必要的我就删去了,这样方便写代码

单词符号

种类

种别码

auto

关键字

1

bool

关键字

2

break

关键字

3

case

关键字

4

char

关键字

5

const

关键字

6

continue

关键字

7

default

关键字

8

do

关键字

9

double

关键字

10

else

关键字

11

enum

关键字

12

extern

关键字

13

float

关键字

14

for

关键字

15

goto

关键字

16

if

关键字

17

int

关键字

18

long

关键字

19

main

关键字

20

register

关键字

21

return

关键字

22

short

关键字

23

signed

关键字

24

sizeof

关键字

25

static

关键字

26

struct

关键字

27

switch

关键字

28

typedef

关键字

29

union

关键字

30

unsigned

关键字

31

void

关键字

32

volatile

关键字

33

while

关键字

34

scanf

关键字

35

printf

关键字

36

include

关键字

37

define

关键字

38

+

运算符

39

-

运算符

40

*

运算符

41

/

运算符

42

%

运算符

43

++

运算符

44

--

运算符

45

==

运算符

46

!=

运算符

47

>

运算符

48

<

运算符

49

>=

运算符

50

<=

运算符

51

&&

运算符

52

||

运算符

53

!

运算符

54

=

运算符

55

+=

运算符

56

-=

运算符

57

*=

运算符

58

/=

运算符

59

%=

运算符

60

&=

运算符

61

^=

运算符

62

|=

运算符

63

&

运算符

64

|

运算符

65

^

运算符

66

~

运算符

67

<<

运算符

68

>>

运算符

69

(

界符

70

)

界符

71

[

界符

72

]

界符

73

{

界符

74

}

界符

75

.

界符

76

,

界符

77

;

界符

78

界符

79

#

界符

80

?

界符

81

’’

界符

82

整型

整型

83

浮点型

浮点型

84

标识符

标识符

85

 具体代码解释

        下面是定义的全局变量,因为+-*/这些符号比较特殊,在VS里面运行会报错,所以我使用[]将它括起来,主要看报不报错吧,不报错可以直接写。

        我这样用全局变量写的好处就是,当我需要添加关键字或者其他什么的时候,只需要修改下面这一部分的代码就好。编译原理词法分析器(C/C++)

        然后下面是函数的声明,具体就放在后面的源代码中了,看注释也可以很清楚的知道是做什么的。编译原理词法分析器(C/C++)

         其他都没什么好说的,还有一点就是下面,因为要返回一个字符串数组,所以我用静态局部变量来返回。编译原理词法分析器(C/C++)

2023.3.26日补充:

        有一个很关键的点忘记说了,这个思路还是挺重要的,就是如何不用暴力判断的方法提取出运算符。运算符的提取是在这个位置:

编译原理词法分析器(C/C++)

       看一下代码,是不是特别简单?原本30个运算符只需要这十来行代码就可以从字符串中提取出来。这个思路我是觉得很好的,下面来讲一下我的思路。

        因为运算符只有两种长度,1或者2(之前是有长度为3的,因为没必要我删掉了)。所以一开始我也是想直接暴力判断的,就是看第一位是什么,再看下一位是什么,能不能凑出和运算符里面一样的,然后差不多写完的时候发现,代码太多了,而且重复量很大,所以我就想能不能简单一点呢?然后我就简单列了个表。

+    后缀:+,=

-     后缀:-,=

*     后缀:=

/     后缀:=

%   后缀:=

=    后缀:=

!     后缀:=

>    后缀:>,=

<    后缀:<,=

&    后缀:&,=

|     后缀:|,=

^    后缀:=

~    后缀:无

         列完了我就发现,除了一个单独会出现的~运算符外,其他运算符都是由单个运算符组合起来的,而且组合的话,要么第一个字符和第二个字符相等,要么就是第二个字符就是=(等号),按照这个思路,写出来的代码不就简单多了?解释完毕,应该很好理解哈哈。

        更多的不进行分析,自行看代码注释。

源代码

        用dev-c++或者vs、vsc都可以运行。(要是报错自己解决不了的可以找我)代码大概是160行,比其他博客少挺多的了,当然,我们老师没有要求我们进行代码的检错,所以我这就是很简单的字符串操作。(注意使用VS运行代码的话需要创建项目,然后关闭SDL检查,很多人不常用VS不知道,关闭步骤:打开项目后,点击项目->属性->->C/C++->常规->SDL检查->将是改为否->点击应用后确定,不关掉SDL检查的话很多常用的函数都会报错说不安全

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define Maxline  1024

//-----全局变量------
char keyword[][10] = { "auto","bool","break","case","char","const","continue","default","do"
,"double","else","enum","extern","float","for","goto","if","int","long","main","register","return"
,"short","signed","sizeof","static","struct","switch","typedef","union","unsigned","void","volatile"
,"while","scanf","printf","include","define" };	//38个保留字(关键字)
char delimiter[][10] = { "(",")","[","]","{","}",".",",",";","'","#","?",'"', };//13个界符
char calculation[][10] = { "[+]","[-]","[*]","[/]","[%]","[++]","[--]","[==]","[!=]","[>]","[<]","[>=]"
,"[<=]","[&&]","[||]","[!]","[=]","[+=]","[-=]","[*=]","[/=]","[%=]","[&=]","[^=]","[|=]","[&]","[|]"
,"[^]","[~]","[<<]","[>>]"};//31个运算符
int nk = 38, nd = 13, nc = 31;//分别表示关键字、界符、运算符的个数
//下面分别是关键字、界符、运算符、整型、浮点数和标识符在单词表中的偏移量
int ck = 1, cd = 70, cc = 39, ci = 83, cf = 84, cn = 85;

//------函数声明------
bool pd_integer(char ch);	    //判断是否是整数
bool pd_character(char ch);		//判断是否是字母
int  pd_keyword(char s[]);		//判断字符串是否是保留字(关键字)是则返回下标,否则返回-1
int  pd_delimiter(char ch);     //判断字符是否是界符,是返回下标,否则返回-1
int  pd_calculation(char s[]);	//判断字符串是否是运算符,是返回下标,否则返回-1
char* pd_spcode(int n);         //根据种别码的范围判断类别
int search_spcode(char s[]);	//查询字符串s的种别码

//------主函数------
int main() {
	char test[1030] = { 0 };
	FILE* fp = fopen("test.txt", "r");
	if (fp == NULL) {
		printf("打开文件失败!\n");
		return 0;
	}
	while (fgets(test, Maxline, fp) != NULL) {
		int i = 0, j = 0;
		while (i < strlen(test)) {
			if (test[i] == ' ' || test[i] == '\n' || test[i] == '\t') {
				i++;
				continue;//遇到空格或换行符,跳过
			}
			bool flag = true;
			char str[100] = { 0 };
			j = 0;
			if (pd_integer(test[i])) {
				//如果是数字,循环读取,包括小数点,因为可能是浮点数
				while (pd_integer(test[i]) || (test[i] == '.' && flag)) {
					if (test[i] == '.')flag = false;//浮点型只允许出现一个小数点
					str[j++] = test[i++];
				}
				i--;
			}
			else if (pd_character(test[i]) || test[i] == '_') {
				//如果是字母或下划线或数字(标识符可以有数字)
				while (pd_character(test[i]) || test[i] == '_' || pd_integer(test[i]))str[j++] = test[i++];
				i--;
			}
			else if (test[i] == '+' || test[i] == '-' || test[i] == '*' || test[i] == '/'
				|| test[i] == '%' || test[i] == '=' || test[i] == '!' || test[i] == '>'
				|| test[i] == '<' || test[i] == '&' || test[i] == '|' || test[i] == '^') {

				if (test[i + 1] == '=' || test[i] == test[i + 1]) {
					str[0] = test[i], str[1] = test[i + 1];
					i++;
				}
				else {
					str[0] = test[i];
				}
			}
			else {
				str[0] = test[i];
			}
			i++;
			printf("( %s , %d )------%s\n", str, search_spcode(str), pd_spcode(search_spcode(str)));

		}
	}
	return 0;
}

//------函数实现------
bool pd_integer(char ch) {//判断是否是整数
	if (ch >= '0' && ch <= '9')return true;
	return false;
}

bool pd_character(char ch) {//判断是否是字母
	if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))return true;
	return false;
}

int pd_keyword(char s[]) {//判断字符串是否是保留字(关键字)是则返回下标,否则返回-1
	for (int i = 0; i < nk; i++)
		if (strcmp(s, keyword[i]) == 0)return i;
	return -1;
}

int pd_delimiter(char ch) {//判断字符是否是界符,是返回下标,否则返回-1
	for (int i = 0; i < nd; i++)
		if (ch == delimiter[i][0])return i;
	return -1;

}
int pd_calculation(char s[]) {//判断字符是否是运算符,是返回下标,否则返回-1
	for (int i = 0; i < nc; i++) {
		if (strlen(calculation[i]) - 2 == strlen(s)) {//如果长度相等
			bool flag = true;
			for (int j = 1, k = 0; j < strlen(calculation[i]) - 1 && k < strlen(s); j++, k++)
				if (calculation[i][j] != s[k]) {
					flag = false;//有一个元素不等,标记后直接退出
					break;
				}
			if (flag)return i;//返回下标
		}

	}
	return -1;
}

char* pd_spcode(int n) {    //根据种别码的范围判断类别
	static char name[20];//静态局部变量
	if (n >= 1 && n <= nk) strcpy(name, "关键字");
	else if (n >= cc && n < cd) strcpy(name, "运算符");
	else if (n >= cd && n < ci) strcpy(name, "界符");
	else if (n == ci) strcpy(name, "整型");
	else if (n == cf)strcpy(name, "浮点型");
	else if (n == cn) strcpy(name, "标识符");
	else strcpy(name, "未识别");
	return name;
}

int search_spcode(char s[]) {	//查询字符串s的种别码
	if (pd_character(s[0])) {	//如果第一个字符是字母,说明是关键字或标识符
		if (pd_keyword(s) != -1) //说明是关键字
			return pd_keyword(s) + ck;//下标从0开始,要+1
		else return cn;	//否则就是标识符(标识符可以有下划线)
	}

	if (s[0] == '_')return cn;//下划线开头一定是标识符

	if (pd_integer(s[0])) {//开头是数字说明是整数或者浮点数
		if (strstr(s, ".") != NULL)return cf;//如果有小数点说明是浮点型
		return ci;//否则就是整型
	}

	if (strlen(s) == 1) { //长度为1,说明是界符或者运算符
		char ch = s[0];
		if (pd_delimiter(ch) != -1)//判断是否是界符
			return pd_delimiter(ch) + cd;
	}

	if (pd_calculation(s) != -1)//如果是运算符
		return pd_calculation(s) + cc;

	return -1;//否则就是未标识符

}

运行结果展示

        运行后代码是使用文件进行输入的。

        代码中最好不要有中文哈,因为没有处理中文,会有一堆未识别出来的(一个中文站字符串数组的两个位置)然后头文件里面,stdio.h里面的点可以不用理会,拆开就拆开了,老师不会考察这个的。

#include<stdio.h>
#include<string.h>
int main()
{
	int n,_m,k=666;
	scanf("%d %d",&n,&_m);
	printf("%d+%d=%d",n,_m,n+_m);
	return 0;
} 

运行结果:

编译原理词法分析器(C/C++)

 实验验收的时候不会有带有头文件和函数的,就算有也是加几个关键字就行。

词法分析器验收

        我们老师的验收方式是当场给出题目,然后现场改代码,上完课改不完的估计是会扣分了。然后不需要写实验报告啥的,有好有坏吧。

        如果你的老师也是说要出题目现场改代码的话,可以借鉴一下这个。

        我也是今天验收了之后才来写这篇博客的。

题目:在源语言中,增加新的数据类型int36,请实现对下面代码段的词法分析

int36 a=A7,b=5TU,z=A+B;

int c=10;

for(int i=0;i<10;i++){

        if(c%2==0)z=z+10;

        else z=z+1Z;

        c=c+1;

}

说明:

1、int36类型的常量都是大写,可以是字母开头,也可以是数字开头;可以全是数字,也可以全是大写字母。

2、除了int36的常量会大写外,凡是带有字母的都是小写字母。

3、int36当作关键字输出

例如:上面的代码中:z=z+10;中10是int36类型的,同类型才能相加,需要进行输出说明。

         题目分析:

        1、问题主要是如何标记int36类型的常量和区分代码中的3个10。

        2、如果提取的字符串中带有大写字母,那么一定是int36类型的常量

        3、直接分析10这种整型是int36还是int不现实,所以需要将int36类型的变量名称进行标记,可以将变量复制语句里面的等号前面的字母/数字/下划线提取出来,放到一个数组里面,当遇到完全是数字的时候进行判断,看等号前面的变量名在不在数组里面,如果在的话,说明这个整型其实是int36类型的常量,进行标记方便后面进行输出(后面输出的时候要取消标记)(目前我只想到这个方法,有其他想法的可以评论交流)

        简单的几句分析,代码还是要进行挺大的改动的(只是在原有功能上面添加,原本的功能不变)。源代码就不进行解释了,相信大部分同学都是不用进行验收的。

验收后的源代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define Maxline  1024

//-----全局变量------
char keyword[][10] = { "auto","bool","break","case","char","const","continue","default","do"
,"double","else","enum","extern","float","for","goto","if","int","long","main","register","return"
,"short","signed","sizeof","static","struct","switch","typedef","union","unsigned","void","volatile"
,"while","scanf","printf","include","define","int36"};	//39个保留字(关键字)
char delimiter[][10] = {"(",")","[","]","{","}",".",",",";","'","#","?",'"',};//13个界符
char calculation[][10] = {"[+]","[-]","[*]","[/]","[%]","[++]","[--]","[==]","[!=]","[>]","[<]","[>=]"
,"[<=]","[&&]","[||]","[!]","[=]","[+=]","[-=]","[*=]","[/=]","[%=]","[&=]","[^=]","[|=]","[&]","[|]"
,"[^]","[~]","[<<]","[>>]"};//31个运算符
int nk = 39, nd = 13, nc = 31;//分别表示关键字、界符、运算符的个数
//下面分别是关键字、界符、运算符、整型、浮点数和标识符在单词表中的偏移量,int36类型为87;
int ck = 1, cd = 71, cc = 40, ci = 84, cf = 85, cn = 86, cint36 = 87;
char int36[100][100];	//int36类型的变量标识符
int p = 0;
bool flag3 = false, flag4 = false;//用于标记

//------函数声明------
bool pd_integer(char ch);	    //判断是否是数字
bool pd_character(char ch);		//判断是否是小写字母
bool pd_character2(char ch);	//判断是否是大写字母
int  pd_keyword(char s[]);		//判断字符串是否是保留字(关键字)是则返回下标,否则返回-1
int  pd_delimiter(char ch);     //判断字符是否是界符,是返回下标,否则返回-1
int  pd_calculation(char s[]);	//判断字符串是否是运算符,是返回下标,否则返回-1
char* pd_spcode(int n);         //根据种别码的范围判断类别
bool pd_int36(char s[]);		//判断是否是int36类型的变量
int search_spcode(char s[]);	//查询字符串s的种别码

//------主函数------
int main(int argc,void *argv) {
	char test[1030] = { 0 };
	FILE* fp = fopen("test.txt", "r");
	if (fp == NULL) {
		printf("打开文件失败!\n");
		return 0;
	}
	while (fgets(test, Maxline, fp) != NULL) {
		int i = 0, j = 0;
		while (i < strlen(test)) {
			if (test[i] == ' ' || test[i] == '\n' || test[i] == '\t') {
				i++;
				continue;//遇到空格或换行符,跳过
			}
			bool flag = true;
			char str[100] = { 0 };
			j = 0;
			if (test[i] == 'i' && test[i + 1] == 'n' && test[i + 2] == 't' && test[i + 3] == '3' && test[i + 4] == '6') {
				str[j++] = test[i];
				str[j++] = test[i + 1];
				str[j++] = test[i + 2];
				str[j++] = test[i + 3];
				str[j] = test[i + 4];
				i += 4;
				//printf("%s\n", str);

			}
			else if (pd_character2(test[i])) {
				while (pd_character2(test[i]) || pd_integer(test[i]))str[j++] = test[i++];
				i--;
			}
			else if (pd_integer(test[i])) {
				//如果是数字,循环读取,包括小数点,因为可能是浮点数
				int k = i;
				bool flag2 = false;
				while (pd_integer(test[k]) || pd_character2(test[k])) {
					if (pd_character2(test[k]))flag2 = true;
					k++;
				}
				if (flag2) {
					while (pd_integer(test[i]) || pd_character2(test[i])) {
						if (test[i] == '.')flag = false;//浮点型只允许出现一个小数点
						str[j++] = test[i++];
					}
				}
				else {
					while (pd_integer(test[i]) || (test[i] == '.' && flag)) {
						if (test[i] == '.')flag = false;//浮点型只允许出现一个小数点
						str[j++] = test[i++];
					}
				}
				i--;
				if (search_spcode(str) == ci) {//如果是整型,判断是否是int36类型
					k = i;
					int l = 0;
					char str1[20] = { 0 }, str2[20] = { 0 };//用一个新建的变量来保存变量
					while (test[k] != '=' || test[k] == ' ')k--;//test[k]=='=';
					k--;
					while (pd_integer(test[k]) || pd_character(test[k]) || test[k] == '_') {
						str1[l++] = test[k];
						k--;
					}
					//将变量名倒过来
					int jj = 0;
					for (int ii = 0; ii < l; ii++) {
						str2[jj++] = str1[l - ii - 1];
					}
					if (pd_int36(str2)) flag4 = true;
				}
			}
			else if (pd_character(test[i]) || test[i] == '_') {
				//如果是字母或下划线或数字(标识符可以有数字)
				while (pd_character(test[i]) || test[i] == '_'||pd_integer(test[i]))str[j++] = test[i++];
				i--;
			}
			else if (test[i] == '+' || test[i] == '-' || test[i] == '*' || test[i] == '/'
				|| test[i] == '%' || test[i] == '=' || test[i] == '!' || test[i] == '>'
				|| test[i] == '<' || test[i] == '&' || test[i] == '|' || test[i] == '^') {

				if (test[i + 1] == '=' || test[i] == test[i + 1]) {
					str[0] = test[i], str[1] = test[i+1];
					i++;
				}
				else {
					str[0] = test[i];
				}
			}
			else {
				str[0] = test[i];
			}
			i++;
			if (strcmp(str, "int36") == 0 && !flag3)flag3 = true;
			else if (str[0] == ';' && flag3)flag3 = false;
			if (flag3 && (str[0] == '_' || pd_character(str[0]))) {
				if (!pd_int36(str))strcpy(int36[p++], str);//如果变量不在数组里面,就放进去
			}
			int a = search_spcode(str);//用一个变量临时保存种别码
			printf("( %s , %d )------%s\n", str, a, pd_spcode(a));

		}
	}
	//for (int i = 0; i < p; i++)printf("%s\n", int36[i]);//测试用
	return 0;
}

//------函数实现------
bool pd_integer(char ch) {//判断是否是整数
	if (ch >= '0' && ch <= '9')return true;
	return false;
}

bool pd_character(char ch) {//判断是否是小写字母
	if ((ch >= 'a' && ch <= 'z'))return true;
	return false;
}

bool pd_character2(char ch) {//判断是否是大写字母
	if ((ch >= 'A' && ch <= 'Z'))return true;
	return false;

}

int pd_keyword(char s[]) {//判断字符串是否是保留字(关键字)是则返回下标,否则返回-1
	for (int i = 0; i < nk; i++)
		if (strcmp(s, keyword[i]) == 0)return i;
	return -1;
}

int pd_delimiter(char ch) {//判断字符是否是界符,是返回下标,否则返回-1
	for (int i = 0; i < nd; i++)
		if (ch == delimiter[i][0])return i;
	return -1;

}
int pd_calculation(char s[]) {//判断字符是否是运算符,是返回下标,否则返回-1
	for (int i = 0; i < nc; i++) {
		if (strlen(calculation[i]) - 2 == strlen(s)) {//如果长度相等
			bool flag = true;
			for(int j=1,k=0;j<strlen(calculation[i])-1&&k<strlen(s);j++,k++)
				if (calculation[i][j] != s[k]) {
					flag = false;//有一个元素不等,标记后直接退出
					break;
				}
			if (flag)return i;//返回下标
		}
		
	}
	return -1;
}

bool pd_int36(char s[]) {//判断是否是int36类型的变量
	for (int i = 1; i < p; i++)
		if (strcmp(int36[i], s) == 0) return true;
	return false;
}

char* pd_spcode(int n) {    //根据种别码的范围判断类别
	static char name[20];//静态局部变量
	if (n >= 1 && n <= nk) strcpy(name, "关键字");
	else if (n >= cc && n < cd) strcpy(name, "运算符");
	else if (n >= cd && n < ci) strcpy(name, "界符");
	else if (n == ci) strcpy(name, "整型");
	else if (n == cf)strcpy(name, "浮点型");
	else if (n == cn) strcpy(name, "标识符");
	else if (n == cint36) {
		strcpy(name, "int36");
		flag4 = false;//取消标记
	}
	else strcpy(name,"未识别");
	return name;
}

int search_spcode(char s[]) {	//查询字符串s的种别码
	if (pd_character2(s[0]))return cint36;
	for (int i = 0; i < strlen(s); i++)
		if (pd_character2(s[i])) return cint36;
	if (pd_character(s[0])) {	//如果第一个字符是小写字母,说明是关键字或标识符
		if (pd_keyword(s) != -1) //说明是关键字
			return pd_keyword(s) + ck;//下标从0开始,要+1
		else return cn;	//否则就是标识符(标识符可以有下划线)
	}

	if (s[0] == '_')return cn;//下划线开头一定是标识符
	
	if (pd_integer(s[0])) {//开头是数字说明是整数或者浮点数
		if (flag4) return cint36;//如果被做了标记,说明是int36类型
		if (strstr(s, ".") != NULL)return cf;//如果有小数点说明是浮点型
		return ci;//否则就是整型
	}

	if (strlen(s) == 1) { //长度为1,说明是界符或者运算符
		char ch = s[0];
		if (pd_delimiter(ch) != -1)//判断是否是界符
			return pd_delimiter(ch) + cd;
	}

	if (pd_calculation(s) != -1)//如果是运算符
		return pd_calculation(s) + cc;

	return -1;//否则就是未标识符

}

 验收后代码运行结果

编译原理词法分析器(C/C++)

        我加多了几条语句,测试结果都是正确的,应该没有什么问题了。

        有问题可以评论提问或者私信我。(担心代码有bug)

验收感想

        平时写代码还是太顺了,验收的时候竟然卡在了将局部变量当成全局变量来用,一直得不到想要的结果。果然一紧张就会犯错,还是需要进行更多的练习。要提高自身的抗压能力。文章来源地址https://www.toymoban.com/news/detail-459671.html

到了这里,关于编译原理词法分析器(C/C++)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 词法分析器(c++)

    个人觉得单纯是用来完成实验报告的话还行,但仅做参考,因为本人的编程水平有限,怕误人子弟。 本次代码支持以下操作: 单行注释 多行注释 文件形式输入 种别码可以在文件中自由修改 单词字符串识别支持: 部分(可手动在程序外部---reference.txt文件添加,),

    2024年02月04日
    浏览(48)
  • 词法分析器的设计与实现

    1.1、实验目的         加深对词法分析器的工作过程的理解;加强对词法分析方法的掌握;能够采用一种编程语言实现简单的词法分析程序;能够使用自己编写的分析程序对简单的程序段进行词法分析。 1.2、实验要求         1)对单词的构词规则有明确的定义;      

    2024年02月13日
    浏览(52)
  • Lex 生成一个词法分析器

     lex 通过输入一个.l 文件生成一个lex.yy.c 文件,然后通过c 编译器编译成一个可执行的词法分析器。 该词法分析器扫描输入源文件,生成一个token 符号流给后面语法分析器使用。   .l 文件的结构, 分成三个部分,声明, 转换规则, 自定义规则。 三个部分由%%分割 声明段,

    2024年02月19日
    浏览(48)
  • 编译原理-6-LR语法分析器

    自顶向下的、不断归约的、基于句柄识别自动机的、适用于LR(∗) 文法的、LR(∗) 语法分析器 只考虑无二义性的文法 自底向上 构建语法分析树 根节点 是文法的起始符号 S S S 每个中间 非终结符节点 表示 使用它的某条产生式进行归约 叶节点 是词法单元$w$$ 仅包含终结符号与

    2024年02月05日
    浏览(47)
  • 编译原理实验三:预测分析法语法分析器的设计

    ​ 根据文法编制预测分析法语法分析程序,以便对输入的符号串进行语法分析。通过编写预测分析法语法分析程序掌握预测分析法的基本原理、FIRST和FOLLOW集的计算、预测分析表的构造方法以及语法分析法主控程序的设计。 对于给定的上下文无关文法,编程完成以下功能:

    2024年02月05日
    浏览(55)
  • 编译原理——语法分析器(C/C++代码实现)

    编写一个简单的LL(1)语法分析器。(注意:此实验是简化版的LL(1)文法,已给出预测分析表,不需要求FIRST和FOLLOW集,直接根据预测分析表编写程序即可) 根据编译原理理论课中学习的算术表达式文法,以及该文法LL(1)分析表,用C语言编写接受算术表达式为输入的语法

    2023年04月26日
    浏览(40)
  • 编译原理语法分析器(C/C++)(LR1文法)

            来写语法分析器了,有可能是老师不一样也有可能是学校不一样,我要做的语法分析器复杂一点,额,现在想来也不复杂(可能)。         这一次的实验是要进行语法分析,是要用LL1或者递归下降分析法或LR分析法(LR0、LR1)设计语法分析程序。这次我也是先去百

    2024年02月07日
    浏览(34)
  • 编译原理——SLR(1)语法分析器(C/C++代码实现)

    设计、编制、实现并调试SLR(1)语法分析器,加深对语法分析的理解。 根据编译原理理论课中学习的算术表达式文法以及该文法的LR分析表,用C语言编写接受算术表达式为输入的语法分析器,以控制台(或文本文件,也可以结合词法分析器完成)为输入,控制台(或文件)

    2024年02月11日
    浏览(41)
  • 分析器:常见问题

    源生成器(增量生成器)由于它特殊的定位,关于它的调试十分困难。在这里分享一些调试它的经验。 另外经常有写类库,然后提供可以生成代码的Attribute给用户的需求,此时需要用到传递引用的知识点。 源生成器项目和普通的项目不同。 普通的会在你按下运行或调试后才

    2024年02月01日
    浏览(67)
  • Elasticsearch 文本分析器(下)

    注意:字符过滤器用于在将字符流传递给分词器之前对其进行预处理 此过滤器会替换掉HTML标签,且会转换HTML实体 如: 会被替换为 。 解析结果: 因为是 p 标签,所以有前后的换行符。如果使用span标签就不会有换行符了。 可配参数说明 escaped_tags (可选,字符串数组)不包

    2024年02月08日
    浏览(122)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包