编译原理:词法分析器设计与实现(C语言)

词法分析器设计与实现

待分析的简单的词法

(1)关键字:

 begin  if  then  while  do  end

所有的关键字都是小写。

(2)运算符和界符

: =  +  -  *  /  <  <=  <>  >  >=  =  ; (  )  #

(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:

ID = letter (letter | digit)*

NUM = digit digit*

(4)空白由空格、制表符和换行符组成。空格一般用来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。

各种单词符号对应的种别码

单词符号

种别码

单词符号

种别码

bgin

1

17

If

2

:=

18

Then

3

<

20

wile

4

<>

21

do

5

<=

22

end

6

>

23

lettet(letter|digit)*

10

>=

24

dight dight*

11

=

25

+

13

26

14

(

27

*

15

)

28

/

16

#

0

词法分析程序的功能:

输入:所给文法的源程序字符串。

输出:二元组(syn,token或sum)构成的序列。

其中:syn为单词种别码;

      token为存放的单词自身字符串;

      sum为整型常数。

例如:对源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件,经过词法分析后输出如下序列:

(1,begin) (10,x) (18,:=) (11,9) (26,;) (2,if)……

原理、方法和手段

算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。

主程序示意图:

主程序示意图如图3-1所示。其中初始包括以下两个方面:

⑴ 关键字表的初值。

关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。如能查到匹配的单词,则该单词为关键字,否则为一般标识符。关键字表为一个字符串数组,其描述如下:

Char *rwtab[6] = {“begin”, “if”, “then”, “while”, “do”, “end”,};

(2)程序中需要用到的主要变量为syn,token和sum

扫描子程序的算法思想:

首先设置3个变量:①token用来存放构成单词符号的字符串;②sum用来整型单词;③syn用来存放单词符号的种别码。扫描子程序主要部分流程如图3-2所示。

补充内容

ch: 字符变量、存放最新读入的源程序字符
strToken: 字符数组,存放构成单词符号的字符串
GetChar: 子程序过程,把下一个字符读入到ch中
GetBC: 子程序过程,跳过空白符,直至ch读入一个非空白字符
IsLetter和IsDigit:判断ch字符是否为字母或数字

Retract: 子程序,把搜索指针回调一个字符位置

code:

#include <stdio.h>
#include <string.h>

#define MaxSize 100007

char *rwtab[6] = {"begin", "if", "then", "while", "do", "end"}; // 关键字表 
char ch;
char chStream[MaxSize]; // 缓存输入的字符流 
char strToken[MaxSize]; // 字符数组,存放构成单词符号的字符串 
int p, syn, sum;	// 搜索指针 种别码和整型常数 

// 子程序过程,把下一个字符读入ch中 
char GetChar(int *p) 
{
	return chStream[(*p)++];
}

// 跳过空白符,直至读入一个非空字符
char GetBC(int *p)
{
	while(chStream[*p] == ' '){
		(*p)++;
	}
	return chStream[(*p)++];
}

// 判断是否为字母 
int IsLetter(char c)
{
	if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')){
		return 1;
	}
	return 0;
}

// 判断是否为数字
int IsDigit(char c) 
{
	if(c >= '0' && c <= '9'){
		return 1;
	}
	return 0;
}

// 搜索指针回调一个字符位置 
void Retract(int *p)
{
	(*p)--;
}

// 运算符和界符的判断
 

void solve(int *p) 
{
	memset(strToken, 0, sizeof(strToken));
	ch = GetBC(p); // 跳过空白符,直至读入一个非空字符
	if(IsLetter(ch)){ // 第一个是字母,则可能是关键字也可能是标识符 
		int idx = 0;
		while(IsLetter(ch) || IsDigit(ch)){
			strToken[idx++] = ch;
			ch = GetChar(p);
		} 
//		strToken[idx] = '\0';
		Retract(p); // 搜索指针回调一个字符位置 
		syn = 10; // 先默认是标识符,接下来再判断是否为关键字
		for(int i = 0; i < 6; i++){
			if(strcmp(strToken, rwtab[i]) == 0){ // 与关键字相比较 
				syn = i+1; // 获取对应关键字的种别 
				break;
			} 
		}
	}
	else if(IsDigit(ch)){ // 第一个是数字 
		sum = 0;
		while(IsDigit(ch)){
			sum = sum * 10 + (ch - '0');
			ch = GetChar(p);
		} 
		Retract(p);
		syn = 11;
	}
	else{
		switch(ch){
			case '+': syn = 13; strToken[0] = ch; break;
			case '-': syn = 14; strToken[0] = ch; break;
			case '*': syn = 15; strToken[0] = ch; break;
			case '/': syn = 16; strToken[0] = ch; break;
			case ':':
				syn = 17;
				strToken[0] = ch;
				ch = GetChar(p); // 超前搜索一个字符 
				if(ch == '='){
					strToken[1] = ch;
					syn = 18;
				}
				else{
					// 如果超前搜索到的字符不能与当前字符相结合,则需要回退 
					Retract(p);  
				} 
				break;
			case '<':
				syn = 20;
				strToken[0] = ch;
				ch = GetChar(p);
				if(ch == '>'){
					strToken[1] = ch;
					syn = 21;
				}
				else if(ch == '='){
					strToken[1] = ch;
					syn = 22;
				}
				else{
					Retract(p);
				}
				break;
			case '>':
				syn = 23;
				strToken[0] = ch;
				ch = GetChar(p);
				if(ch == '='){
					strToken[1] = ch;
					syn = 24;
				}
				else{
					Retract(p);
				}
				break;
			case '=': syn = 25; strToken[0] = ch; break;
			case ';': syn = 26; strToken[0] = ch; break;
			case '(': syn = 27; strToken[0] = ch; break;
			case ')': syn = 28; strToken[0] = ch; break;
			case '#': syn = 0 ; strToken[0] = ch; break;
			default : syn = -1; break;
		}
	}
}

int main()
{
	int idx = 0;
	do{
		ch = getchar();
		chStream[idx++] = ch;
	}while(ch != '#');
	chStream[idx] = '\0'; // 标记字符串结束
	
	p = 0;
	do{
		solve(&p);
		switch(syn){
			case -1: printf("error!\n"); break;
			case 11: printf("<%d, %d>\n", syn, sum); break;
			default:
				printf("<%d, %s>\n", syn, strToken);
				break;
		}
	}while(p < idx && syn != 0);
	
	
	return 0;
}

 

  • 39
    点赞
  • 343
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值