词法分析的任务:
首先,从阶段上来看,编译器可分为若干个中间阶段:
典型的,可以包含为一个前端,一个后端。前端接收源程序产生一个中间表示,后端接收中间表示继续生成一个目标程序。所以,前端处理的是跟源语言有关的属性,后端处理跟目标机器有关的属性。
更细节的,前端可以划分为若干个阶段:
下面我们看看词法分析器的任务:
词法分析器读入程序员写的程序,然后对字符流做切分成记号流。举个例子:
这是一个程序员看到的字符流
词法分析器将字符流读入,根据关键字、标识符、标点、字符串、整形数等进行划分,形成记号流(单词):
那么就会有两个问题:1.记号的数据结构如何定义? 2.如何实现从字符流到记号流转换的算法?
首先看第一个问题,如何定义记号的数据结构,假如用C语言实现数据结构的定义,可以这样实现:
举个例子:假如源语句if(x>5),则词法分析器返回token{k=IF,lexeme=0};token{k=IPAREN,lexeme=0};token{k=ID,lexeme="X"};……
【此处小结】:词法分析器的任务:字符流到记号流。
字符流:和被编译语言密切相关(ASCII,Unicode,or……)
记号流:编译器内部定义的数据结构,编码所识别出的词法单元
再看第二个问题,词法分析器怎么实现呢?目前来说一般有两种方案:
1.手工编码实现法。这种方法相对复杂,容易出错,但是非常流行的方法,如GCC,LLVM等。
2.词法分析器的生成器。这种方法可快速原型,代码量少,但较难控制细节。
(1)我们先看第一种方案,手工编码法。如何识别语言中的各种符号呢?假设我们分析一种语言,包含以下关系运算符:<=、>=、<>、=、>、<,我们可以用转移图对其进行识别,转移图如下所示:
那么怎么用算法实现这个转移图呢?如下所示:
同理,语言中其他标识符的识别也类似实现:
实际上这两张转移图(包括代码)是结合在一起的。
那么问题来了,如何区别关键字和标识符呢?因为在很多语言中关键字和标识符是有交集的,但从词法分析上看,关键字是标识符的一部分。以C语言为例,标识符是:以字母或下划线开头,后跟0个或多个字母、下划线或数字。关键字:if、while、else……
怎么识别关键字呢?这里介绍两种方法。
先看第一种,我们需要将上面的转移图稍加修改:(以识别if为例)
此处还应注意一个问题,假如输入ifxy呢?并不是关键字,因此这里还需判断。
再看第二种,使用关键字表,即Hash表。对语言中所有的关键字构建哈希表,对所有的关键字和标识符,先统一按标识符的转移表进行识别,识别完成后,再查哈希表看是否为关键字。通过构造合理的哈希表,可以再O(1)时间内完成。
(2)再看第二种方案,词法分析器的生成器。那么怎样自动生成呢?
这种方案不需要像第一种方案那么繁琐,只需要用正则表达式写出程序语言中的词法规则,然后通过自动生成工具lex,flex,jlex等,自动产生出词法分析器,生成的词法分析器跟第一种方案的图转移算法是类似的,但是,程序员只需要写一个声明式规范,工作量就显著减小了。
如何写这种声明式规范呢?首先我们要先学正则表达式。什么是正则表达式,其定义如下:
举个例子,对于字符集Σ={a,b},可以写出哪些正则表达式? ε、a、b、ε|a,ε|b……εε、εa、εb、ab、a(ε|a)……ε*、a(ε|a)*……
知道正则表达式了,那么如何用正则表达式表示程序语言的词法规则呢?再看个例子:C语言中的关键字if如何用正则表达式表示?if中i∈Σ,f∈Σ,根据定义则if∈Σ。再看个复杂点的,如何用正则表达式表示C语言的标识符?可将标识符写成两部分,第一部分只能以字母或下划线开头,后连接零个或多个字母、下划线、数字(闭包),则正则表达式为(a|b|c……A|B|C……|_)(a|b|c……A|B|C……|0|1|2……|_)*。但是这样表达显然比较繁琐,可以引入更多的语法糖来构造正则表达式,来简化构造:
来源:http://www.cnblogs.com/anthony007/p/4241189.html