这次实验被“过来人”们定位很简单,实验内容如下:
-----------------------------------------------------------------------------------
对如下工作进行展开描述
(1) 给出语言的词法规则描述
· 标识符、关键字、整常数、字符常数、浮点常数
· 单界符:+,-,×,;,…
· 双界符:/*,:=,>=,<=,!=,…
· 注释
(2) 针对这种单词的状态转换图和程序框图
(3) 核心数据结构的设计
如符号表、关键字等
(4) 错误处理
错误的位置及类型等
-----------------------------------------------------------------------------------
这次实验我是用python写了一个简单的C语言的词法分析器,词法分析器的编写有很多种方式,比如可以用正则表达式编写,也可以用LEX工具自动生成,当然,也可以用比较朴素的方式——基于有穷自动机(Finite Automata,FA),也即基于有穷自动机的状态转移来编写程序。
说起这个有穷自动机(Finite Automata,FA),真心感觉是个好东西,分析问题简单清晰,而且很直观。记得对有穷自动机有感性认识是在上学期考试分数并不高的《计算机网络》课上,全龙哥讲那个RDT协议的不同版本的时候,用这个自动机来表明遇到不同情况时发送端和接收端要采取的行动。
自动机的形式化定义:
M=(Q,Σ,δ,q0,F)
„ Q→有穷状态集
„ Σ→有穷输入字母表
„ δ→从Q×Σ→2Q的映射函数(2Q是Q的幂集)
„ q0∈Q,是唯一的初态
„ F →终态集合,是Q的子集
这里说说我个人的理解。对有穷自动机的形式化定义的理解比较重要的是上述第三条说明的理解:δ→从Q×Σ→2Q的映射函数。也即这个δ定义了某个具体FA的状态间转移关系,或者说定义了某个FA的状态间转移的规则。所谓状态的幂集就是状态集Q的所有子集构成的集族。则这句话的字面意思是:状态集和字母表的笛卡尔乘积到状态集的幂集的映射函数。
比如:M1 = (Q,Σ,δ,q0,F),其中Q = {q,q0,q1,q2...,qn},又((q,a) , {q1,q2,q3})∈δ,也即δ((q,a)) = {q1,q2,q3}。则说明自动机M1有一个状态q,q在遇到字母a的时候,自动机状态可能跳转到q1,q2,q3三个状态。自动机又分为有穷自动机和无穷自动机两种,这里不再赘述。
有穷自动机可以用状态图直观表示,例子见下文中图。
至于词法分析的一些基本知识,简单叙述一下:
-----------------------------------------------------------------------------------
定义:
词法分析器的功能输入源程序,按照构词规则分解成一系列单词符号。单词是语言中具有独立意义的最小单位,包括关键字、标识符、运算符、界符和常量等
(1) 关键字 是由程序语言定义的具有固定意义的标识符。例如,Pascal 中的begin,end,if,while都是保留字。这些字通常不用作一般标识符。
(2) 标识符 用来表示各种名字,如变量名,数组名,过程名等等。
(3) 常数 常数的类型一般有整型、实型、布尔型、文字型等。
(4) 运算符 如+、-、*、/等等。
(5) 界符 如逗号、分号、括号、等等。
输出:
词法分析器所输出单词符号常常表示成如下的二元式:
(单词种别,单词符号的属性值)
单词种别通常用整数编码。标识符一般统归为一种。常数则宜按类型(整、实、布尔等)分种。关键字可将其全体视为一种。运算符可采用一符一种的方法。界符一般用一符一种的方法。对于每个单词符号,除了给出了种别编码之外,还应给出有关单词符号的属性信息。单词符号的属性是指单词符号的特性或特征。
示例:
比如如下的代码段:
while(i>=j) i--;
经词法分析器处理后,它将被转为如下的单词符号序列:
<while, _>
<(, _>
<id, 指向i的符号表项的指针>
<>=, _>
<id, 指向j的符号表项的指针>
<), _>
<id, 指向i的符号表项的指针>
<--, _>
<;, _>
词法分析分析器作为一个独立子程序:
词法分析是编译过程中的一个阶段,在语法分析前进行。词法分析作为一遍,可以简化设计,改进编译效率,增加编译系统的可移植性。也可以和语法分析结合在一起作为一遍,由语法分析程序调用词法分析程序来获得当前单词供语法分析使用。
-----------------------------------------------------------------------------------
我写的这个词法分析器,不是很健全,尤其是错误处理机制,像在字符串识别中,'ab'是C语言中不合法的char变量,但是我的词法分析器不能判断出错误,会死循环;此外,只能识别出有限的关键字、有限形式的字符串(相信读者看懂我的状态机就知道哪里有限了),由于时间不够了,我不想再改了,下面贴出代码,供大家参考。
对了,贴代码之前,先说说我的词法分析器的状态机的设计。
我对“数字”的词法分析用了一个状态机,包括浮点数、整形数,状态机如下:
对“字符(串)”的识别用了一个状态机,包括关键字、char、以及char *,如下:
当然,对C语言的注释的识别也用了一个状态机,必须先把源码中的注释cut掉才能进行分析,如下:
我对运算符的识别(包括双目和单目)没有采用明显的状态机,都是直接分析判断的,实际从某种意义上来讲对它们的分析也是采用了状态机的原理,只是状态机结构比较简单,就没再显式用state表示,它们的状态机实际上如下:
下面上代码:
Scanner.py,作为主模块来执行:
'''
Created on 2012-10-18
@author: liushuai
'''
import string
import Category
import FileAccess
_currentIndex = 0
_Tokens = []
_prog = ""
_categoryNo = -1
_stateNumber = 0
_stateString = 0
_potentialNumber = ""
_potentialString = ""
def readComments(prog):
'''Read the comments of a program'''
state = 0
currentIndex, beginIndex, endIndex = (0, 0, 0)
commentsIndexs = []
for c in prog:
if state == 0:
if c =