第三章 词法分析
文章目录
- 第三章 词法分析
- 一、词法分析程序的功能
- 二、单词的种类
- 三、正则文法和状态图
- 四、词法分析程序的设计与实现
词法分析:断词,给出词性(分类)
语法分析:断句,给出句的结构和分类
一、词法分析程序的功能
1、词法分析:根据此法规则识别及组合单词,并进行词法检查
- 对数字常数从字符串转化位二进制数值
- 删去空格和注释
2、实现方案
最简单的想法是先进行词法分析获得所有单词,存成中间文件,但是效率低。一般做法是把词法分析程序作为语法分析程序的子程序,当需要一个新的符号时调用。
二、单词的种类
1、单词的种类
- 保留字
- 标识符(用户定义)
- 常数(布尔常数、字符串常数等)
- 分界符
2、内部形式
类别编码/记忆符+单词值(词法程序输出以需求为准)
一般按照单词种类分类,或保留字和分界符采用一符一类,等。
三、正则文法和状态图
正则文法是第二章(四-4)中提到得3型文法,即非终结符推出一个终结符 或者 一个非终结符+一个终结符
(左线性 3型文法)状态图画法
1、令文法中的每个非终结符都是一个状态(包括识别符号Z)
2、设置一个开始状态S
3、若,则画一条从S到Q的线,如下图:
4、若,则画一条从R到Q的线,如下图:
5、(按照自动机)可以加上开始和终止状态标志。
结果:状态图中从S到Z的都是该文法的语言,否则不是
注意:
- 这里的终止状态是指自己设置的出口(比如读到下一个不满足的字符后退出)/出错处理,不是Z
- 这是一个自底向上的分析过程,而且每次规约的都是句柄(便于理解为什么是从右部的非终结符指向左部)
四、词法分析程序的设计与实现
整体步骤:词法状态图程序
一个例子(《编译技术》P65的示例)
1、词法
(1)语言的单词符号如下:
- 标识符
- 保留字(标识符的子集)
- 无符号整数
- 单分界符 + * : , ( )
- 双分界符 :=
注意:不输出注释(/*...*/
);跳过空白符
(2)文法
2、状态图
针对上述文法,可以(针对不同单词符号)先分解画图:
再合成一张图:
注:上述图中还没有与注释相关的
3、词法分析程序的构造
在状态图的基础上,增加语义动作(就是程序怎么处理的具体细节),并且加上对注释、空格的处理,得到算法框图:
注:
(1)组合标识符、组数是指按照状态图一直读完整个单词
(2)图中的R指退回字符,是因为有时为了读完整个单词,需要多读一个字符,所以要回退
4、词法分析程序的实现
(1)输出形式
设计单词的类别编号与记忆符,这里采用下表(前七个是保留字):
输出为二元式,即记忆符+单词值(可以存在全局变量中)
(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;
}