国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

編譯原理詞法分析器(C/C++)

這篇具有很好參考價值的文章主要介紹了編譯原理詞法分析器(C/C++)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

前言&思路

? ? ? ? 詞法分析器不用多說,一開始我還不知道是什么樣的,看了下別人的博客,再看看書,原來是輸出二元組,這不就是字符串操作嘛。然后細(xì)看幾篇博客,發(fā)現(xiàn)大都是用暴力判斷來寫的。我對代碼重復(fù)性比較高的方法不太感冒,不是說我編程有多好,就是單純的不喜歡。

????????于是我就想到了用偏移量的方法,先弄好單詞分類器,再用幾個數(shù)組將關(guān)鍵字、運(yùn)算符、界符的所有定義的字符串保存為全局變量,順序要按單詞分類器的順序,然后根據(jù)這三種字符串在表中的位置,定一個偏移量。當(dāng)輸入的時候,將字符串進(jìn)行切割提取,然后放到全局?jǐn)?shù)組里面判斷,返回下標(biāo)加上偏移量,這樣就可以得到這一個字符串在單詞表中的位置(種別碼)了,最后根據(jù)種別碼的范圍可以知道數(shù)據(jù)類型。

? ? ? ? 上面的思路說起來比較復(fù)雜,主要是我表達(dá)能力不太好,其實(shí)一看代碼就明白了。

????????哦對了,補(bǔ)充一句,我要分析的語言是C語言,然后也是用C語言來寫。但是因?yàn)橛惺褂貌紶栴愋?,所以需要C++的運(yùn)行環(huán)境。另外,我的代碼沒有代碼檢錯。(老師沒有要求)

NFA和DFA圖

? ? ? ? 這兩個圖不是我畫的,看看就好。????????

? ? ? ? 我要寫的詞法分析器有六個類型:關(guān)鍵字、界符、運(yùn)算符、標(biāo)識符、整型和浮點(diǎn)型。

編譯原理詞法分析器(C/C++)? ? ? ?編譯原理詞法分析器(C/C++)

?單詞分類表

? ? ? ? 關(guān)鍵字在網(wǎng)上找了32個,然后自己加了幾個,運(yùn)算符和界符都是百度找的,其中,運(yùn)算符有>>=這種三個字符的,因?yàn)椴皇潜匾奈揖蛣h去了,這樣方便寫代碼

單詞符號

種類

種別碼

auto

關(guān)鍵字

1

bool

關(guān)鍵字

2

break

關(guān)鍵字

3

case

關(guān)鍵字

4

char

關(guān)鍵字

5

const

關(guān)鍵字

6

continue

關(guān)鍵字

7

default

關(guān)鍵字

8

do

關(guān)鍵字

9

double

關(guān)鍵字

10

else

關(guān)鍵字

11

enum

關(guān)鍵字

12

extern

關(guān)鍵字

13

float

關(guān)鍵字

14

for

關(guān)鍵字

15

goto

關(guān)鍵字

16

if

關(guān)鍵字

17

int

關(guān)鍵字

18

long

關(guān)鍵字

19

main

關(guān)鍵字

20

register

關(guān)鍵字

21

return

關(guān)鍵字

22

short

關(guān)鍵字

23

signed

關(guān)鍵字

24

sizeof

關(guān)鍵字

25

static

關(guān)鍵字

26

struct

關(guān)鍵字

27

switch

關(guān)鍵字

28

typedef

關(guān)鍵字

29

union

關(guān)鍵字

30

unsigned

關(guān)鍵字

31

void

關(guān)鍵字

32

volatile

關(guān)鍵字

33

while

關(guān)鍵字

34

scanf

關(guān)鍵字

35

printf

關(guān)鍵字

36

include

關(guān)鍵字

37

define

關(guān)鍵字

38

+

運(yùn)算符

39

-

運(yùn)算符

40

*

運(yùn)算符

41

/

運(yùn)算符

42

%

運(yùn)算符

43

++

運(yùn)算符

44

--

運(yùn)算符

45

==

運(yùn)算符

46

!=

運(yùn)算符

47

>

運(yùn)算符

48

<

運(yùn)算符

49

>=

運(yùn)算符

50

<=

運(yùn)算符

51

&&

運(yùn)算符

52

||

運(yùn)算符

53

!

運(yùn)算符

54

=

運(yùn)算符

55

+=

運(yùn)算符

56

-=

運(yùn)算符

57

*=

運(yùn)算符

58

/=

運(yùn)算符

59

%=

運(yùn)算符

60

&=

運(yùn)算符

61

^=

運(yùn)算符

62

|=

運(yùn)算符

63

&

運(yùn)算符

64

|

運(yùn)算符

65

^

運(yùn)算符

66

~

運(yùn)算符

67

<<

運(yùn)算符

68

>>

運(yùn)算符

69

(

界符

70

)

界符

71

[

界符

72

]

界符

73

{

界符

74

}

界符

75

.

界符

76

,

界符

77

;

界符

78

界符

79

#

界符

80

?

界符

81

’’

界符

82

整型

整型

83

浮點(diǎn)型

浮點(diǎn)型

84

標(biāo)識符

標(biāo)識符

85

?具體代碼解釋

? ? ? ? 下面是定義的全局變量,因?yàn)?-*/這些符號比較特殊,在VS里面運(yùn)行會報錯,所以我使用[]將它括起來,主要看報不報錯吧,不報錯可以直接寫。

? ? ? ? 我這樣用全局變量寫的好處就是,當(dāng)我需要添加關(guān)鍵字或者其他什么的時候,只需要修改下面這一部分的代碼就好。編譯原理詞法分析器(C/C++)

? ? ? ? 然后下面是函數(shù)的聲明,具體就放在后面的源代碼中了,看注釋也可以很清楚的知道是做什么的。編譯原理詞法分析器(C/C++)

? ? ? ? ?其他都沒什么好說的,還有一點(diǎn)就是下面,因?yàn)橐祷匾粋€字符串?dāng)?shù)組,所以我用靜態(tài)局部變量來返回。編譯原理詞法分析器(C/C++)

2023.3.26日補(bǔ)充:

? ? ? ? 有一個很關(guān)鍵的點(diǎn)忘記說了,這個思路還是挺重要的,就是如何不用暴力判斷的方法提取出運(yùn)算符。運(yùn)算符的提取是在這個位置:

編譯原理詞法分析器(C/C++)

? ? ? ?看一下代碼,是不是特別簡單?原本30個運(yùn)算符只需要這十來行代碼就可以從字符串中提取出來。這個思路我是覺得很好的,下面來講一下我的思路。

????????因?yàn)檫\(yùn)算符只有兩種長度,1或者2(之前是有長度為3的,因?yàn)闆]必要我刪掉了)。所以一開始我也是想直接暴力判斷的,就是看第一位是什么,再看下一位是什么,能不能湊出和運(yùn)算符里面一樣的,然后差不多寫完的時候發(fā)現(xiàn),代碼太多了,而且重復(fù)量很大,所以我就想能不能簡單一點(diǎn)呢?然后我就簡單列了個表。

+? ? 后綴:+,=

-? ? ?后綴:-,=

*? ? ?后綴:=

/? ? ?后綴:=

%? ?后綴:=

=? ? 后綴:=

!? ? ?后綴:=

>? ? 后綴:>,=

<? ? 后綴:<,=

&? ? 后綴:&,=

|? ? ?后綴:|,=

^? ? 后綴:=

~? ? 后綴:無

? ? ? ? ?列完了我就發(fā)現(xiàn),除了一個單獨(dú)會出現(xiàn)的~運(yùn)算符外,其他運(yùn)算符都是由單個運(yùn)算符組合起來的,而且組合的話,要么第一個字符和第二個字符相等,要么就是第二個字符就是=(等號),按照這個思路,寫出來的代碼不就簡單多了?解釋完畢,應(yīng)該很好理解哈哈。

????????更多的不進(jìn)行分析,自行看代碼注釋。

源代碼

? ? ? ? 用dev-c++或者vs、vsc都可以運(yùn)行。(要是報錯自己解決不了的可以找我)代碼大概是160行,比其他博客少挺多的了,當(dāng)然,我們老師沒有要求我們進(jìn)行代碼的檢錯,所以我這就是很簡單的字符串操作。(注意使用VS運(yùn)行代碼的話需要創(chuàng)建項目,然后關(guān)閉SDL檢查,很多人不常用VS不知道,關(guān)閉步驟:打開項目后,點(diǎn)擊項目->屬性->->C/C++->常規(guī)->SDL檢查->將是改為否->點(diǎn)擊應(yīng)用后確定,不關(guān)掉SDL檢查的話很多常用的函數(shù)都會報錯說不安全

#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個保留字(關(guān)鍵字)
char delimiter[][10] = { "(",")","[","]","{","}",".",",",";","'","#","?",'"', };//13個界符
char calculation[][10] = { "[+]","[-]","[*]","[/]","[%]","[++]","[--]","[==]","[!=]","[>]","[<]","[>=]"
,"[<=]","[&&]","[||]","[!]","[=]","[+=]","[-=]","[*=]","[/=]","[%=]","[&=]","[^=]","[|=]","[&]","[|]"
,"[^]","[~]","[<<]","[>>]"};//31個運(yùn)算符
int nk = 38, nd = 13, nc = 31;//分別表示關(guān)鍵字、界符、運(yùn)算符的個數(shù)
//下面分別是關(guān)鍵字、界符、運(yùn)算符、整型、浮點(diǎn)數(shù)和標(biāo)識符在單詞表中的偏移量
int ck = 1, cd = 70, cc = 39, ci = 83, cf = 84, cn = 85;

//------函數(shù)聲明------
bool pd_integer(char ch);	    //判斷是否是整數(shù)
bool pd_character(char ch);		//判斷是否是字母
int  pd_keyword(char s[]);		//判斷字符串是否是保留字(關(guān)鍵字)是則返回下標(biāo),否則返回-1
int  pd_delimiter(char ch);     //判斷字符是否是界符,是返回下標(biāo),否則返回-1
int  pd_calculation(char s[]);	//判斷字符串是否是運(yùn)算符,是返回下標(biāo),否則返回-1
char* pd_spcode(int n);         //根據(jù)種別碼的范圍判斷類別
int search_spcode(char s[]);	//查詢字符串s的種別碼

//------主函數(shù)------
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])) {
				//如果是數(shù)字,循環(huán)讀取,包括小數(shù)點(diǎn),因?yàn)榭赡苁歉↑c(diǎn)數(shù)
				while (pd_integer(test[i]) || (test[i] == '.' && flag)) {
					if (test[i] == '.')flag = false;//浮點(diǎn)型只允許出現(xiàn)一個小數(shù)點(diǎn)
					str[j++] = test[i++];
				}
				i--;
			}
			else if (pd_character(test[i]) || test[i] == '_') {
				//如果是字母或下劃線或數(shù)字(標(biāo)識符可以有數(shù)字)
				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;
}

//------函數(shù)實(shí)現(xiàn)------
bool pd_integer(char ch) {//判斷是否是整數(shù)
	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[]) {//判斷字符串是否是保留字(關(guān)鍵字)是則返回下標(biāo),否則返回-1
	for (int i = 0; i < nk; i++)
		if (strcmp(s, keyword[i]) == 0)return i;
	return -1;
}

int pd_delimiter(char ch) {//判斷字符是否是界符,是返回下標(biāo),否則返回-1
	for (int i = 0; i < nd; i++)
		if (ch == delimiter[i][0])return i;
	return -1;

}
int pd_calculation(char s[]) {//判斷字符是否是運(yùn)算符,是返回下標(biāo),否則返回-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;//有一個元素不等,標(biāo)記后直接退出
					break;
				}
			if (flag)return i;//返回下標(biāo)
		}

	}
	return -1;
}

char* pd_spcode(int n) {    //根據(jù)種別碼的范圍判斷類別
	static char name[20];//靜態(tài)局部變量
	if (n >= 1 && n <= nk) strcpy(name, "關(guān)鍵字");
	else if (n >= cc && n < cd) strcpy(name, "運(yùn)算符");
	else if (n >= cd && n < ci) strcpy(name, "界符");
	else if (n == ci) strcpy(name, "整型");
	else if (n == cf)strcpy(name, "浮點(diǎn)型");
	else if (n == cn) strcpy(name, "標(biāo)識符");
	else strcpy(name, "未識別");
	return name;
}

int search_spcode(char s[]) {	//查詢字符串s的種別碼
	if (pd_character(s[0])) {	//如果第一個字符是字母,說明是關(guān)鍵字或標(biāo)識符
		if (pd_keyword(s) != -1) //說明是關(guān)鍵字
			return pd_keyword(s) + ck;//下標(biāo)從0開始,要+1
		else return cn;	//否則就是標(biāo)識符(標(biāo)識符可以有下劃線)
	}

	if (s[0] == '_')return cn;//下劃線開頭一定是標(biāo)識符

	if (pd_integer(s[0])) {//開頭是數(shù)字說明是整數(shù)或者浮點(diǎn)數(shù)
		if (strstr(s, ".") != NULL)return cf;//如果有小數(shù)點(diǎn)說明是浮點(diǎn)型
		return ci;//否則就是整型
	}

	if (strlen(s) == 1) { //長度為1,說明是界符或者運(yùn)算符
		char ch = s[0];
		if (pd_delimiter(ch) != -1)//判斷是否是界符
			return pd_delimiter(ch) + cd;
	}

	if (pd_calculation(s) != -1)//如果是運(yùn)算符
		return pd_calculation(s) + cc;

	return -1;//否則就是未標(biāo)識符

}

運(yùn)行結(jié)果展示

????????運(yùn)行后代碼是使用文件進(jìn)行輸入的。

????????代碼中最好不要有中文哈,因?yàn)闆]有處理中文,會有一堆未識別出來的(一個中文站字符串?dāng)?shù)組的兩個位置)然后頭文件里面,stdio.h里面的點(diǎn)可以不用理會,拆開就拆開了,老師不會考察這個的。

#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;
} 

運(yùn)行結(jié)果:

編譯原理詞法分析器(C/C++)

?實(shí)驗(yàn)驗(yàn)收的時候不會有帶有頭文件和函數(shù)的,就算有也是加幾個關(guān)鍵字就行。

詞法分析器驗(yàn)收

? ? ? ? 我們老師的驗(yàn)收方式是當(dāng)場給出題目,然后現(xiàn)場改代碼,上完課改不完的估計是會扣分了。然后不需要寫實(shí)驗(yàn)報告啥的,有好有壞吧。

? ? ? ? 如果你的老師也是說要出題目現(xiàn)場改代碼的話,可以借鑒一下這個。

? ? ? ? 我也是今天驗(yàn)收了之后才來寫這篇博客的。

題目:在源語言中,增加新的數(shù)據(jù)類型int36,請實(shí)現(xiàn)對下面代碼段的詞法分析

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類型的常量都是大寫,可以是字母開頭,也可以是數(shù)字開頭;可以全是數(shù)字,也可以全是大寫字母。

2、除了int36的常量會大寫外,凡是帶有字母的都是小寫字母。

3、int36當(dāng)作關(guān)鍵字輸出

例如:上面的代碼中:z=z+10;中10是int36類型的,同類型才能相加,需要進(jìn)行輸出說明。

? ? ? ? ?題目分析:

? ? ? ? 1、問題主要是如何標(biāo)記int36類型的常量和區(qū)分代碼中的3個10。

? ? ? ? 2、如果提取的字符串中帶有大寫字母,那么一定是int36類型的常量

? ? ? ? 3、直接分析10這種整型是int36還是int不現(xiàn)實(shí),所以需要將int36類型的變量名稱進(jìn)行標(biāo)記,可以將變量復(fù)制語句里面的等號前面的字母/數(shù)字/下劃線提取出來,放到一個數(shù)組里面,當(dāng)遇到完全是數(shù)字的時候進(jìn)行判斷,看等號前面的變量名在不在數(shù)組里面,如果在的話,說明這個整型其實(shí)是int36類型的常量,進(jìn)行標(biāo)記方便后面進(jìn)行輸出(后面輸出的時候要取消標(biāo)記)(目前我只想到這個方法,有其他想法的可以評論交流)

? ? ? ? 簡單的幾句分析,代碼還是要進(jìn)行挺大的改動的(只是在原有功能上面添加,原本的功能不變)。源代碼就不進(jìn)行解釋了,相信大部分同學(xué)都是不用進(jìn)行驗(yàn)收的。

驗(yàn)收后的源代碼

#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個保留字(關(guān)鍵字)
char delimiter[][10] = {"(",")","[","]","{","}",".",",",";","'","#","?",'"',};//13個界符
char calculation[][10] = {"[+]","[-]","[*]","[/]","[%]","[++]","[--]","[==]","[!=]","[>]","[<]","[>=]"
,"[<=]","[&&]","[||]","[!]","[=]","[+=]","[-=]","[*=]","[/=]","[%=]","[&=]","[^=]","[|=]","[&]","[|]"
,"[^]","[~]","[<<]","[>>]"};//31個運(yùn)算符
int nk = 39, nd = 13, nc = 31;//分別表示關(guān)鍵字、界符、運(yùn)算符的個數(shù)
//下面分別是關(guān)鍵字、界符、運(yùn)算符、整型、浮點(diǎn)數(shù)和標(biāo)識符在單詞表中的偏移量,int36類型為87;
int ck = 1, cd = 71, cc = 40, ci = 84, cf = 85, cn = 86, cint36 = 87;
char int36[100][100];	//int36類型的變量標(biāo)識符
int p = 0;
bool flag3 = false, flag4 = false;//用于標(biāo)記

//------函數(shù)聲明------
bool pd_integer(char ch);	    //判斷是否是數(shù)字
bool pd_character(char ch);		//判斷是否是小寫字母
bool pd_character2(char ch);	//判斷是否是大寫字母
int  pd_keyword(char s[]);		//判斷字符串是否是保留字(關(guān)鍵字)是則返回下標(biāo),否則返回-1
int  pd_delimiter(char ch);     //判斷字符是否是界符,是返回下標(biāo),否則返回-1
int  pd_calculation(char s[]);	//判斷字符串是否是運(yùn)算符,是返回下標(biāo),否則返回-1
char* pd_spcode(int n);         //根據(jù)種別碼的范圍判斷類別
bool pd_int36(char s[]);		//判斷是否是int36類型的變量
int search_spcode(char s[]);	//查詢字符串s的種別碼

//------主函數(shù)------
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])) {
				//如果是數(shù)字,循環(huán)讀取,包括小數(shù)點(diǎn),因?yàn)榭赡苁歉↑c(diǎn)數(shù)
				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;//浮點(diǎn)型只允許出現(xiàn)一個小數(shù)點(diǎn)
						str[j++] = test[i++];
					}
				}
				else {
					while (pd_integer(test[i]) || (test[i] == '.' && flag)) {
						if (test[i] == '.')flag = false;//浮點(diǎn)型只允許出現(xiàn)一個小數(shù)點(diǎn)
						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] == '_') {
				//如果是字母或下劃線或數(shù)字(標(biāo)識符可以有數(shù)字)
				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);//如果變量不在數(shù)組里面,就放進(jìn)去
			}
			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;
}

//------函數(shù)實(shí)現(xiàn)------
bool pd_integer(char ch) {//判斷是否是整數(shù)
	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[]) {//判斷字符串是否是保留字(關(guān)鍵字)是則返回下標(biāo),否則返回-1
	for (int i = 0; i < nk; i++)
		if (strcmp(s, keyword[i]) == 0)return i;
	return -1;
}

int pd_delimiter(char ch) {//判斷字符是否是界符,是返回下標(biāo),否則返回-1
	for (int i = 0; i < nd; i++)
		if (ch == delimiter[i][0])return i;
	return -1;

}
int pd_calculation(char s[]) {//判斷字符是否是運(yùn)算符,是返回下標(biāo),否則返回-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;//有一個元素不等,標(biāo)記后直接退出
					break;
				}
			if (flag)return i;//返回下標(biāo)
		}
		
	}
	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) {    //根據(jù)種別碼的范圍判斷類別
	static char name[20];//靜態(tài)局部變量
	if (n >= 1 && n <= nk) strcpy(name, "關(guān)鍵字");
	else if (n >= cc && n < cd) strcpy(name, "運(yùn)算符");
	else if (n >= cd && n < ci) strcpy(name, "界符");
	else if (n == ci) strcpy(name, "整型");
	else if (n == cf)strcpy(name, "浮點(diǎn)型");
	else if (n == cn) strcpy(name, "標(biāo)識符");
	else if (n == cint36) {
		strcpy(name, "int36");
		flag4 = false;//取消標(biāo)記
	}
	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])) {	//如果第一個字符是小寫字母,說明是關(guān)鍵字或標(biāo)識符
		if (pd_keyword(s) != -1) //說明是關(guān)鍵字
			return pd_keyword(s) + ck;//下標(biāo)從0開始,要+1
		else return cn;	//否則就是標(biāo)識符(標(biāo)識符可以有下劃線)
	}

	if (s[0] == '_')return cn;//下劃線開頭一定是標(biāo)識符
	
	if (pd_integer(s[0])) {//開頭是數(shù)字說明是整數(shù)或者浮點(diǎn)數(shù)
		if (flag4) return cint36;//如果被做了標(biāo)記,說明是int36類型
		if (strstr(s, ".") != NULL)return cf;//如果有小數(shù)點(diǎn)說明是浮點(diǎn)型
		return ci;//否則就是整型
	}

	if (strlen(s) == 1) { //長度為1,說明是界符或者運(yùn)算符
		char ch = s[0];
		if (pd_delimiter(ch) != -1)//判斷是否是界符
			return pd_delimiter(ch) + cd;
	}

	if (pd_calculation(s) != -1)//如果是運(yùn)算符
		return pd_calculation(s) + cc;

	return -1;//否則就是未標(biāo)識符

}

?驗(yàn)收后代碼運(yùn)行結(jié)果

編譯原理詞法分析器(C/C++)

? ? ? ? 我加多了幾條語句,測試結(jié)果都是正確的,應(yīng)該沒有什么問題了。

? ? ? ? 有問題可以評論提問或者私信我。(擔(dān)心代碼有bug)

驗(yàn)收感想

? ? ? ? 平時寫代碼還是太順了,驗(yàn)收的時候竟然卡在了將局部變量當(dāng)成全局變量來用,一直得不到想要的結(jié)果。果然一緊張就會犯錯,還是需要進(jìn)行更多的練習(xí)。要提高自身的抗壓能力。文章來源地址http://www.zghlxwxcb.cn/news/detail-459671.html

到了這里,關(guān)于編譯原理詞法分析器(C/C++)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 詞法分析器(c++)

    詞法分析器(c++)

    個人覺得單純是用來完成實(shí)驗(yàn)報告的話還行,但僅做參考,因?yàn)楸救说木幊趟接邢?,怕誤人子弟。 本次代碼支持以下操作: 單行注釋 多行注釋 文件形式輸入 種別碼可以在文件中自由修改 單詞字符串識別支持: 部分(可手動在程序外部---reference.txt文件添加,),

    2024年02月04日
    瀏覽(19)
  • Lex 生成一個詞法分析器

    Lex 生成一個詞法分析器

    ?lex 通過輸入一個.l 文件生成一個lex.yy.c 文件,然后通過c 編譯器編譯成一個可執(zhí)行的詞法分析器。 該詞法分析器掃描輸入源文件,生成一個token 符號流給后面語法分析器使用。 ? .l 文件的結(jié)構(gòu), 分成三個部分,聲明, 轉(zhuǎn)換規(guī)則, 自定義規(guī)則。 三個部分由%%分割 聲明段,

    2024年02月19日
    瀏覽(21)
  • 詞法分析器的設(shè)計與實(shí)現(xiàn)

    詞法分析器的設(shè)計與實(shí)現(xiàn)

    1.1、實(shí)驗(yàn)?zāi)康?????????加深對詞法分析器的工作過程的理解;加強(qiáng)對詞法分析方法的掌握;能夠采用一種編程語言實(shí)現(xiàn)簡單的詞法分析程序;能夠使用自己編寫的分析程序?qū)唵蔚某绦蚨芜M(jìn)行詞法分析。 1.2、實(shí)驗(yàn)要求 ? ? ? ? 1)對單詞的構(gòu)詞規(guī)則有明確的定義; ? ? ?

    2024年02月13日
    瀏覽(17)
  • 編譯原理-6-LR語法分析器

    編譯原理-6-LR語法分析器

    自頂向下的、不斷歸約的、基于句柄識別自動機(jī)的、適用于LR(?) 文法的、LR(?) 語法分析器 只考慮無二義性的文法 自底向上 構(gòu)建語法分析樹 根節(jié)點(diǎn) 是文法的起始符號 S S S 每個中間 非終結(jié)符節(jié)點(diǎn) 表示 使用它的某條產(chǎn)生式進(jìn)行歸約 葉節(jié)點(diǎn) 是詞法單元$w$$ 僅包含終結(jié)符號與

    2024年02月05日
    瀏覽(52)
  • 編譯原理實(shí)驗(yàn)三:預(yù)測分析法語法分析器的設(shè)計

    編譯原理實(shí)驗(yàn)三:預(yù)測分析法語法分析器的設(shè)計

    ? 根據(jù)文法編制預(yù)測分析法語法分析程序,以便對輸入的符號串進(jìn)行語法分析。通過編寫預(yù)測分析法語法分析程序掌握預(yù)測分析法的基本原理、FIRST和FOLLOW集的計算、預(yù)測分析表的構(gòu)造方法以及語法分析法主控程序的設(shè)計。 對于給定的上下文無關(guān)文法,編程完成以下功能:

    2024年02月05日
    瀏覽(92)
  • 編譯原理——語法分析器(C/C++代碼實(shí)現(xiàn))

    編譯原理——語法分析器(C/C++代碼實(shí)現(xiàn))

    編寫一個簡單的LL(1)語法分析器。(注意:此實(shí)驗(yàn)是簡化版的LL(1)文法,已給出預(yù)測分析表,不需要求FIRST和FOLLOW集,直接根據(jù)預(yù)測分析表編寫程序即可) 根據(jù)編譯原理理論課中學(xué)習(xí)的算術(shù)表達(dá)式文法,以及該文法LL(1)分析表,用C語言編寫接受算術(shù)表達(dá)式為輸入的語法

    2023年04月26日
    瀏覽(65)
  • 編譯原理——SLR(1)語法分析器(C/C++代碼實(shí)現(xiàn))

    編譯原理——SLR(1)語法分析器(C/C++代碼實(shí)現(xiàn))

    設(shè)計、編制、實(shí)現(xiàn)并調(diào)試SLR(1)語法分析器,加深對語法分析的理解。 根據(jù)編譯原理理論課中學(xué)習(xí)的算術(shù)表達(dá)式文法以及該文法的LR分析表,用C語言編寫接受算術(shù)表達(dá)式為輸入的語法分析器,以控制臺(或文本文件,也可以結(jié)合詞法分析器完成)為輸入,控制臺(或文件)

    2024年02月11日
    瀏覽(24)
  • 編譯原理語法分析器(C/C++)(LR1文法)

    編譯原理語法分析器(C/C++)(LR1文法)

    ? ? ? ? 來寫語法分析器了,有可能是老師不一樣也有可能是學(xué)校不一樣,我要做的語法分析器復(fù)雜一點(diǎn),額,現(xiàn)在想來也不復(fù)雜(可能)。 ? ? ? ? 這一次的實(shí)驗(yàn)是要進(jìn)行語法分析,是要用LL1或者遞歸下降分析法或LR分析法(LR0、LR1)設(shè)計語法分析程序。這次我也是先去百

    2024年02月07日
    瀏覽(21)
  • 分析器:常見問題

    分析器:常見問題

    源生成器(增量生成器)由于它特殊的定位,關(guān)于它的調(diào)試十分困難。在這里分享一些調(diào)試它的經(jīng)驗(yàn)。 另外經(jīng)常有寫類庫,然后提供可以生成代碼的Attribute給用戶的需求,此時需要用到傳遞引用的知識點(diǎn)。 源生成器項目和普通的項目不同。 普通的會在你按下運(yùn)行或調(diào)試后才

    2024年02月01日
    瀏覽(15)
  • Elasticsearch 文本分析器(下)

    注意:字符過濾器用于在將字符流傳遞給分詞器之前對其進(jìn)行預(yù)處理 此過濾器會替換掉HTML標(biāo)簽,且會轉(zhuǎn)換HTML實(shí)體 如: 會被替換為 。 解析結(jié)果: 因?yàn)槭?p 標(biāo)簽,所以有前后的換行符。如果使用span標(biāo)簽就不會有換行符了。 可配參數(shù)說明 escaped_tags (可選,字符串?dāng)?shù)組)不包

    2024年02月08日
    瀏覽(47)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包