编译原理-学习记录7

ch3.词法分析(2)——词法分析程序实现

词法分析程序简介

词法分析程序的工作

  对由字符组成的源程序进行分析,将其识别为“单词”(具有独立意义的最小语法单位),再识别出与单词相关的属性(标识符、界限符、数等),最后再转换成长度上统一的标准形式——属性字,以供其他部分使用

  词法分析时,注解、空格等非必要信息会被删除,而标识符会被录入符号表

  例如,源程序:

begin M := 3.1415 / 4 * (d1 * d1 - d2 * d2) end

  按顺序先后被识别为:
  属性1,begin
  属性2,M
  属性5,:=
  属性3,3.1415
  ……

  词法分析输出结果为一个单词或单词串

词法分析程序的地位

  将词法分析独立出来的好处(词法分析严格来讲是语法分析的一部分):针对词的特征单独研究这个方法

  为每一个单词做一个结构,既关注属性,又关注属性的值

单词符号

  单词形式表示为:<单词类别编码,单词自身值>

单词种别有两种标识方式:
  1、一类一码:一个类别一个编码。例如,保留字一律编码为1,标识符一律编码为2,常数一律编码为3……
  2、一符一码:一个单词符号一个编码。例如,if编码为3,then编码为4,else编码为5……

  因为标识符和常数是有无穷多种的,所以即便是使用了一符一码的方式,在对标识符和常数进行编码时,也只能单独对其使用一类一码

  单词符号的属性值是反映单词符号特征或特征的值,例如:标识符的符号表指针,常数的常数表指针等

  单词的自身值可以存放索引:指向值的指针,可以保证所有单词都是同样大小的

  标识符的语义信息可用一个机器字(机内符)来存放,如果信息过多,一个机内符存放不下,可在此机内符中存放部分语义信息,其余语义信息则存放在一个信息表区中。(https://wenku.baidu.com/view/0486459f51e79b89680226f3.html)

  <单词机内符,单词自身值>

  单词自身值可以为指向信息表的地址

符号表

  符号表用于存放在程序中出现的各种单词符号及其语义属性,是编译程序进行各种语义检查(即语义分析)的重要依据,也是进行内存地址分配的依据

  例如,<id, 1>中的1是位置信息,指向符号表的相应位置。符号表中可以找到详细信息

  主程序开始时建立符号表,随着工作的深入,不断地向符号表加入信息/取出信息

  符号表的内容包括:
  1、标识符的名字
  2、与标识符有关的信息:例如数组的信息向量表,过程或函数的参数的个数、类型、次序、是否允许递归等
  3、基本内容:类型信息、存储类别(static、regist等)、地址码、层次信息(标识符所属分程序(过程)的静态层次)、行号信息(标识符在源程序中的行号(说明行与引用行))等

  符号表可以使用线性符号表、树结构等各种数据结构实现

  符号表的条目一般由名字栏、信息栏、连续的存储字(相应的指针或序号)组成

词法分析程序的设计

预处理

  例如:删除注释、空格、回车换行符之类非必要信息

  源程序不能一次性被读入时,会带来问题。例如定义了一个标识符name_of_student,但缓冲区大小正好只允许读到这个标识符的中间。
  针对上述问题,可以使用双缓冲区进行解决:当对一个缓存区的扫描已经到底,而标识符还没有被读完的时候,可以将接下来的内容读入到另一个缓冲区中,并从那里开始继续向后扫描,直至识别出正在识别的标识符

单词符号的识别

  因为如果只看当前扫描到了哪个位置,并不一定能准确判断正在扫描出来的是哪一个单词符号。例如,在扫描<=的第一个符号<时,可以认为这是<=的第一个字符,也可以认为这就是“小于”。这个时候,就需要提前向后看(超前搜索/预读),以此准确地判断出正在扫描的单词符号
  要做到准确判断一个单词符号,至少需要超前搜索一位,超前搜索后,需要回退指针到上一个词结束的位置,以能够完整地识别这个单词(而不是多一个字符)

利用有穷自动机识别单词

  最直接的思路:为每一个单词符号构建一个有穷自动机。但如果对if,while等关键字都单独构建DFA,则会导致工作量过于庞大,因此可以对有穷自动机进行合并,以精简程序

  对于标识符和关键字这样的类型的区分:读出完整的单词后,去查关键字表,以判断其具体类型(例如:查到是关键字,查不到则是标识符)

  DFA的选取问题:根据上述思路构造的DFA必然不止一个,在识别单词时,该选用哪一个DFA来处理下一个单词,就成为了一个问题。——解决方法:将开始状态合并为同一个,即得到了一个完整的自动机。这个FA可能是NFA,只需转换为DFA即可

  状态转换图的实现
  1、从输入串中读一个字符
  2、判明读入的字符与由此状态出发的哪条弧上的标记相匹配,便转至相匹配的那条弧所指向的状态
  3、均不匹配时则失败(不能到达正常出口)

  DFA的程序实现

  如图1所示,在开始状态时,单词name初始化为空串,随后开始向后读取字符。跳过若干个空格后,读到合法首字符时,便开始将读取到的字符加到name后面,随后继续向后看,直到读取到非法字符时,则表明读取结束。此时就得到了一个单词(name),在符号表中对name进行查询,判断其类型,再在相应的标识符表中进行填写,最后回退指针、返回这个单词

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IfkVNkb9-1603624914654)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025190306706.png)]

图1

  图1所示的过程的伪代码可以表示为:

if peek in letter # 如果下一位字符是字母
then while peek in letter or digit do # 每当下一位字符时字母或数字时
    begin
        name = name + peek; # 将下一位字符追加到name的末尾
        read(peek) # 继续向后读一位
    end; # 读取到非字母、非数字的字符时,结束循环
retract; # 回退指针
i = lookup(name); # 在符号表中查询name
if i != 0 then return(1, name) # 如果查询到了,则属于关键字
else return(2, name); # 否则,属于标识符

  扫描程序构造方法
  1、对于无回路分叉结点,可以选用switch或if…else语句
  2、对于含有回路的结点,可以使用由while和if语句构成的程序段
  3、对于终态结点,使用return(code, value)语句,用于返回到调用者。其中,code为单词种别编码,value为单词属性值(或者无定义)

  需要注意回退指针:搜索指示器回调一个字符

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值