第三章 词法分析


文章目录

  • 第三章 词法分析
  • 一、词法分析程序的功能
  • 二、单词的种类
  • 三、正则文法和状态图
  • 四、词法分析程序的设计与实现


词法分析:断词,给出词性(分类)

语法分析:断句,给出句的结构和分类

一、词法分析程序的功能

1、词法分析:根据此法规则识别及组合单词,并进行词法检查

  • 对数字常数从字符串转化位二进制数值
  • 删去空格和注释

2、实现方案

最简单的想法是先进行词法分析获得所有单词,存成中间文件,但是效率低。一般做法是把词法分析程序作为语法分析程序的子程序,当需要一个新的符号时调用。

hostapd Association过程分析did not acknowledge association response 过程分析法英语_状态图

二、单词的种类

1、单词的种类

  • 保留字
  • 标识符(用户定义)
  • 常数(布尔常数、字符串常数等)
  • 分界符

2、内部形式

类别编码/记忆符+单词值(词法程序输出以需求为准)

一般按照单词种类分类,或保留字和分界符采用一符一类,等。

三、正则文法和状态图

正则文法是第二章(四-4)中提到得3型文法,即非终结符推出一个终结符 或者 一个非终结符+一个终结符

(左线性 3型文法)状态图画法

1、令文法中的每个非终结符都是一个状态(包括识别符号Z)

2、设置一个开始状态S

3、若hostapd Association过程分析did not acknowledge association response 过程分析法英语_编译器_02,则画一条从S到Q的线,如下图:

hostapd Association过程分析did not acknowledge association response 过程分析法英语_词法分析_03


4、若hostapd Association过程分析did not acknowledge association response 过程分析法英语_标识符_04,则画一条从R到Q的线,如下图:

hostapd Association过程分析did not acknowledge association response 过程分析法英语_标识符_05

5、(按照自动机)可以加上开始和终止状态标志。

结果:状态图中从S到Z的都是该文法的语言,否则不是

注意:

  • 这里的终止状态是指自己设置的出口(比如读到下一个不满足的字符后退出)/出错处理,不是Z
  • 这是一个自底向上的分析过程,而且每次规约的都是句柄(便于理解为什么是从右部的非终结符指向左部)

四、词法分析程序的设计与实现

整体步骤:词法hostapd Association过程分析did not acknowledge association response 过程分析法英语_标识符_06状态图hostapd Association过程分析did not acknowledge association response 过程分析法英语_标识符_06程序

一个例子(《编译技术》P65的示例)

1、词法

(1)语言的单词符号如下:

  • 标识符
  • 保留字(标识符的子集)
  • 无符号整数
  • 单分界符 + * : , ( )
  • 双分界符 :=

注意:不输出注释(/*...*/);跳过空白符

(2)文法
hostapd Association过程分析did not acknowledge association response 过程分析法英语_编译器_08
2、状态图

针对上述文法,可以(针对不同单词符号)先分解画图:

hostapd Association过程分析did not acknowledge association response 过程分析法英语_编译器_09


再合成一张图:

hostapd Association过程分析did not acknowledge association response 过程分析法英语_编译器_10


注:上述图中还没有与注释相关的

3、词法分析程序的构造

在状态图的基础上,增加语义动作(就是程序怎么处理的具体细节),并且加上对注释、空格的处理,得到算法框图:

hostapd Association过程分析did not acknowledge association response 过程分析法英语_状态图_11


注:

(1)组合标识符、组数是指按照状态图一直读完整个单词

(2)图中的R指退回字符,是因为有时为了读完整个单词,需要多读一个字符,所以要回退

4、词法分析程序的实现

(1)输出形式

设计单词的类别编号与记忆符,这里采用下表(前七个是保留字):

hostapd Association过程分析did not acknowledge association response 过程分析法英语_编译器_12


输出为二元式,即记忆符+单词值(可以存在全局变量中)

(2)全局变量

  • ch:当前读入的字符
  • token:存放单词的字符串
  • num:存放当前读入的整数数值
  • symbol:当前所识别单词的记忆符

(3)C代码实现(仅供参考)

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
#define MAXLEN 256

char ch; //present charactor
char token[MAXLEN];//store string
int num;//store numbers
enum {BEGINSY, ENDSY, IFSY,THENSY, ELSESY,
	 IDSY, INTSY, PLUSSY, MINUSSY, STARSY,
	DIVISY, LPARSY, RPARSY, COMMASY, SEMISY,
	 COLONSY, ASSIGNSY
	 } symbol;//symbol of all kinds of words(according to textbook)
char marks[MAXLEN] = "+-*/(),;:";


void skip() {
	while(ch==' ' || ch=='\n' || ch=='	') {
		ch = getchar();
	}
	return;
}

int checkReserver() {
	if (strcmp(token, "BEGIN")==0) {
		symbol = BEGINSY;
	}else if (strcmp(token, "END")==0) {
		symbol = ENDSY;
	}else if (strcmp(token, "IF")==0) {
		symbol = IFSY;
	}else if (strcmp(token, "THEN")==0) {
		symbol = THENSY;
	}else if (strcmp(token, "ELSE")==0) {
		symbol = ELSESY;
	}else {
		return -1;
	}
	return 0;
}

void readAnotation() {
	do {
		do {
			ch = getchar();
            if (ch == EOF) {
                printf("Anotation missing ending symbol */ \n");
                ungetc(ch, stdin);
                return;
            }
		}while(ch != '*');
		do {
			ch = getchar();
			if (ch == '/') {
				return;//anotation end
			}else if (ch == EOF) {
                printf("Anotation missing ending symbol */ \n");
                ungetc(ch, stdin);
                return;
            }
		}while(ch=='*');
	}while(ch != '*');
}

void error() {
	printf("error! read unvalidated char:%c\n", ch);
	return;
}

//get words 
int getsym() {
	char *p=token;
	
	skip();//skip all space, \n, tab
	token[0] = '\0';// clear token
	if (isalpha(ch)) {
		while(isalpha(ch) || isdigit(ch)) {
			(*p++) = ch;
			ch = getchar();
		}
		*p = '\0';
		ungetc(ch, stdin);
		
		//check if is reserver
		if (checkReserver() == -1) {
			symbol = IDSY;
		}
	}else if(isdigit(ch)) {
		num = 0;
		while(isdigit(ch)) {
			(*p++) = ch;
			num = num*10 + ch -'0';//change char to int
			ch = getchar();
		}
		*p = '\0';
		ungetc(ch, stdin);
		
		//num=atoi(token);//change string to int	
		symbol = INTSY;
	}else if (ch=='+') {
		symbol = PLUSSY;
	}else if (ch=='-') {
		symbol = MINUSSY;
	}else if (ch=='*') {
		symbol = STARSY;
	}else if (ch=='(') {
		symbol = LPARSY;
	}else if (ch==')') {
		symbol = RPARSY;
	}else if (ch==',') {
		symbol = COMMASY;
	}else if (ch==';') {
		symbol = SEMISY;
	}else if (ch==':') {
		if ((ch=getchar())=='=') {
			symbol = ASSIGNSY;
		}else {
			ungetc(ch, stdin);
			symbol = COLONSY;	
		}
	}else if (ch=='/') {
		if ((ch = getchar())=='*') {
			readAnotation();//skip anotation
			return 1;	
		}
		ungetc(ch, stdin);
		symbol = DIVISY;		
	} else {
		if (ch!=EOF) {
			error();
		}
		return -1;
	}

	return 0;
}


int main() {
	printf("please input:\n");
	while ((ch=getchar())!=EOF) {
		//output format:symbol(index)  string
		//for numbers, the first string is the original string
        //the second is in the form of int(for checking the transform) 
		if(getsym()==0) {
			if (symbol <= 5) {
				printf("%d  %s\n", symbol, token);
			}else if (symbol == INTSY) {
				printf("%d  %s  %d\n", symbol, token, num);
			}else if (symbol <= 15) {
				printf("%d  %c\n", symbol, marks[symbol-7]);
			}else{
				printf("%d  :=\n", symbol);
			}
		}else if (getsym()==-1){
			break;//once finish all or error happens, break
		}
	}
	return 0;
}