词法分析——词法分析器的作用

目录

综述

正文

 1 词法分析与语法分析

 2 词法单元、模式和词素

3 词法单元的属性 

4 词法错误


综述

        词法分析是编译的第一阶段。词法分析器的主要作用是读入源程序的输入字符、将它们组成词素,生成并输出一个词法单元序列,每个词法单元对应一个词素。这个词法单元序列被输出到语法分析器进行语法分析。词法分析器通常还要和符号表进行交互。当词法分析器发现了一个标识符的词素时,它要将这个词素添加到符号表中。在某些情况下,词法分析器会从符号表中读取有关标识符种类的信息,以确定向词法分析器传送那个词法单元。

        这种交互过程在图1-1中给出。通常,交互是语法分析器调用词法分析器来实现的。图中的命令 getNextToken 所指示的调用使得此法分析器从它的输入中不断读取字符,直到它识别出下一个词素为止。词法分析器根据这个词素生成下一个词法单元并返回给语法分析器。

图1-1 词法分析器与语法分析器之间的交互

         词法分析器在编译器中负责读取源程序,因此他还会完成一些识别词素之外的其他任务 。任务之一是过滤掉源程序中的注释和空白(空格、换行符、制表符以及在输入中用于分隔词法单元的其他字符);另一个任务是将编译器生成的错误信息与源程序的位置联系起来。例如,词法分析器可以负责记录遇到的换行符的个数,以便给每个出错消息赋予一个行号。在某些编译器中,词法分析器会建立源程序的一个拷贝,并将出错信息插入到适当位置。如果源程序使用了一个宏预处理器,则宏的扩展也可以由词法分析器完成。

        有时,词法分析器可以分成两个级联的处理阶段:

        1)扫描阶段主要负责完成一些不需要生成词法单元的简单处理,比如删除注释和将多个连续的空白字符压缩成一个字符。

        2)词法分析阶段是较为复杂的部分,他处理扫描阶段的输出并生成词法单元。

正文

 1 词法分析与语法分析

        把编译阶段的分析部分划分为词法分析和语法分析阶段有如下几个原因:

        1)最重要的是考虑简化编译器的设计。将词法分析器和语法分析器分离通常使我们至少可以简化其中的一项任务。例如,如果一个语法分析器必须把空白字符和注释当做语法单元进行处理,那么它就会比那些假设空白字符和注释已经被词法分析器过滤掉的处理器复杂得多。如果我们正在设计一个新语言,将词法和语法分开考虑有助于我们得到一个更加清晰地的语言设计方案。

        2)提高编译器的效率。把词法分析器独立出来使我们能够使用专用于词法分析任务、不进行语法分析的技术。此外,我们可以使用专门的用于读取输入字符的缓冲技术来显著提高编译器的速度。

        3)增强编译器的可移植性。输入设备相关的特殊性可以被限制在词法分析器中。

 2 词法单元、模式和词素

        在讨论词分析时,我们使用三个相关但有区别的术语:

  •  词法单元由一个词法单元名和一个可选的属性值组成。词法单元名是一个表示某种词法单位的抽象符号,比如一个特定的关键字,或者代表一个标识符的输入字符序列。词法单元名字是由语法分析器处理的输入符号。在后面内容中,我们约定通常使用黑体字给出词法单元名。我们将使用词法单元的名字来引用一个词法单元。
  • 模式描述了一个词法单元的词素可能具有的形式。当词法单元是一个关键字时,它的模式就是组成这个关键字的字符序列。对于标识符和其他词法单元,模式是一个更加复杂的结构,他可以和很多符号串匹配
  • 词素是源程序中的一个字符序列,他和某个词法单元的模式相匹配,并被词法分析器识别为该词法单元的一个实例。

 

3 词法单元的属性 

        如果有多个词素可以和一个模式匹配,那么词法分析器必须向编译器的后续阶段提供有关被匹配次数的附加信息,例如0和1,都能和词法单元number的模式匹配。但是对于代码生成器而言,至关重要的是知道在源程序中找到了哪个词数。因此在很多情况下,此法分析器不仅仅像语法分析器返回一个词法单元名字。还会返回一个描述该词法单元的词数的属性值。词法单元的名字将影响语法分析过程中的决定,而这个属性则会影响语法分析之后对这个词法单元的翻译。

      我假设一个词法单元至多有一个相关的属性值,当然这个属性值可能是一个组合了多种信息的结构化数据。最重要的例子是词法单元id,我们通常会将很多信息和他关联。一般来说,和一个标识符有关的信息——例如他的词素、类型、第一次出现的位置(在发出一个有关该标识符的错误信息时,需要使用这个信息)——都保存在符号表中。因此,一个标识符的属性值是一个指向符号表中该标识符对应条目的指针。

识别词法单元时的棘手问题

        如果给定一个描述了某词法单元的词素的模式,在与之匹配的词素出现在输入中时识别出匹配的词素是相对简单的。然而,在某些程序设计语言中,要判断是否识别到一个和某词法单元匹配的词素并不是一件轻而易举的事。下面的例子来自Fortran语言的固定格式(fixed-format)程序。Fortran 90中仍然支持固定格式。在语句

DO 5 I = 1.25

中,在我们看到以后的小数点之前,我们并不能确定DO5I第一个是一个标识符,即一个标识符词法单元的实例。注意,在Fortran语言的固定格式中,空格是被忽略的(这是一种过时惯例)。假如我们看到的是一个逗号,而不是小数点,那我们就得到了一个do语

DO 5 I = 1.25

在这个语句中,第一个词素是关键字DO。

4 词法错误

        如果没有其他组件的帮助,词法分析器很难发现源代码中的错误。当词法分析器在C程序片段

fi( a == f(x) )...

中第一次遇到时,他无法指出fi是关键字if的误写,还是一个未声明的函数标识符。由于fi是标识符id的一个合法词素。因此,词法分析器必须向语法分析器返回这个id词法单元,而让编译器的另一个阶段(在这个例子里是语法分析器)去处理这个因为字母颠倒而引起的错误。

        然而,假设出现所有词法单元的模式都无法和剩余输入的某个前缀相匹配的情况,此时,词法分析器就不能继续处理输入。当出现这种情况时,最简单的错误恢复策略是“恐慌模式”恢复。我们从剩余的输入中不断删除字符,直到词法分析器能够在剩余输入的开头发现一个正确的词法单元为止。这个恢复技术可能会给语法分析器带来混乱,但是在交互计算环境中,这个技术已经足够了。

        可能采取的其他错误恢复动作包括:

  1. 从剩余的输入中删除一个字符。
  2. 向剩余的输入中插入一个遗漏的字符。
  3. 用一个字符来替换另一个字符。
  4. 交换两个相邻的字符。

        这些交换可以在试图修复错误输入时进行。最简单的策略是看一下是否可以通过一次变换将剩余输入的某个前缀变成一个合法的词素。这种策略还是有道理的,因为在实践中,大多数词法错误只涉及一个字符,另外一种更加通用的改正策略是计算出最少需要多少次变换才能够把一个源程序转换成为一个只包含合法词素的程序。但是在实践中发现这种方法的代价太高。不值得使用。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈士奇谭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值