【学习笔记】编译原理 第三章 词法分析

以下为参考课件与《编译技术》(张莉等著)的个人整理,若有错误欢迎指出

第三章 词法分析

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

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

一、词法分析程序的功能

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

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

2、实现方案

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

二、单词的种类

1、单词的种类

  • 保留字

  • 标识符(用户定义)

  • 常数(布尔常数、字符串常数等)

  • 分界符

2、内部形式

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

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

三、正则文法和状态图

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

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

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

2、设置一个开始状态S

3、若 Q : : = T , Q ∈ V n , T ∈ V t Q::=T,Q\in V_n,T\in V_t Q::=T,QVn,TVt,则画一条从S到Q的线,如下图:
请添加图片描述
4、若 Q : : = R T , Q 、 R ∈ V n , T ∈ V t Q::=RT,Q、R\in V_n,T\in V_t Q::=RT,QRVn,TVt,则画一条从R到Q的线,如下图:
请添加图片描述

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

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

注意:

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

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

整体步骤:词法 ⟶ \longrightarrow 状态图 ⟶ \longrightarrow 程序

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

1、词法

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

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

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

(2)文法
< 标 识 符 > : : = 字 母 ∣ < 标 识 符 > 字 母 ∣ < 标 识 符 > 数 字 < 无 符 号 整 数 > : : = 数 字 ∣ < 无 符 号 整 数 > 数 字 < 单 字 符 分 界 符 > : : = + ∣ − ∣ ∗ ∣ / ∣ ( ∣ ) ∣ : ∣ , ∣ ; < 双 字 符 分 界 符 > : : = < 冒 号 > = < 冒 号 > : : = : < 注 释 头 符 号 > : : = < 斜 竖 > ∗ < 斜 竖 > : : = / \begin{aligned} &<标识符>::= 字母 | <标识符>字母 | <标识符>数字\\ &<无符号整数>::=数字 | <无符号整数>数字\\ &<单字符分界符>::= +|-|*|/|(|)|:|,|;\\ &<双字符分界符>::= <冒号>=\\ &<冒号>::= :\\ &<注释头符号>::= <斜竖>*\\ & <斜竖>::=/ \end{aligned} <>::=<><><>::=<><>::=+/():,;<>::=<>=<>::=:<>::=<><>::=/
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;
}
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值