编译原理学习--词法分析(1)

∥☆過路亽.° 提交于 2019-11-29 20:34:07

词法分析的任务:

  首先,从阶段上来看,编译器可分为若干个中间阶段:

    

  典型的,可以包含为一个前端,一个后端。前端接收源程序产生一个中间表示,后端接收中间表示继续生成一个目标程序。所以,前端处理的是跟源语言有关的属性,后端处理跟目标机器有关的属性。

  更细节的,前端可以划分为若干个阶段:

    

  下面我们看看词法分析器的任务:

    

  词法分析器读入程序员写的程序,然后对字符流做切分成记号流。举个例子:

    这是一个程序员看到的字符流

  词法分析器将字符流读入,根据关键字、标识符、标点、字符串、整形数等进行划分,形成记号流(单词):

    

  那么就会有两个问题: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……|_)*。但是这样表达显然比较繁琐,可以引入更多的语法糖来构造正则表达式,来简化构造:

    

 

 

  

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!