编译原理四元式实验_记一次编译原理实验——词法+语法&语义分析(Python实现)...

记一次编译原理实验——词法+语法&语义分析(Python实现)

编译原理是每个CS学子的必修课。编译原理的实验课对提高我们对编译过程的理解很重要。

本文章写于实验结束后,所有代码已上传至Github : https://github.com/kabu1204/compilation。

建议拉到底下点击阅读原文,微信排版不行,表格内的公式加载不出来,而且LATEX的换行符失效。

水平有限,如有问题还望指正。

环境:Python 3.6.9

  • 词法分析器

    • 预处理

    • DFA

  • 语法分析——LR(1)的强大

    • LR(1)文法

    • 自动求FIRST集

    • 自动推导LR(1)项目集族和生成ACTION & GOTO表

  • 语义分析

    • 文法改写

    • 预先定义的一些东西

    • 真链 假链 回填

    • 语义动作

    • 运行结果

词法分析器

一个编程语言的词法通常用正规文法描述,由正则表达式表示,使用DFA进行识别,三者在描述能力/识别能力上是等价的。

事实上,正则表达式的匹配就是使用DFA作为引擎的,当然也有NFA引擎。

在这一部分,我们要设计并实现SAMPLE语言的词法分析器,自然,设计的重点是其识别工具:DFA.

当然我们也可以直接使用正则表达式进行匹配,但这对我们理解DFA的原理并无裨益,不过我还是用到了RE库来实现源程序文本的切分。

下面介绍一下我实现词法分析器的过程。

预处理

读入的源程序实际上是一个字符串,而词法分析的对象是一个个单词(包括界符)。显然,能将其分为一个一个具有独立意义的单词,更便于我们的处理。

为了实现切分,我们先介绍一个函数re.split()

re.split()

re.split(pattern:AntStr, string:AnyStr)

第一个参数pattern是划分依据的正则表达式,第二个参数string是要进行划分的字符串。

  • 按一个单字符切分:
>>> s="var A;B;C:integer;"
>>> re.split(r";",s)
['var A', 'B', 'C:integer', '']

如果字符串最后一个字符是被切分字符,则切分时还会产生一个''字符

  • 按多个单字符切分(用[]框住):
>>>re.split(r"[;:]",s)
['var A', 'B', 'C', 'integer', '']
  • 分组:
>>>re.split(r"(;)",s)
['var A', ';', 'B', ';', 'C:integer', ';', '']

此时默认保留切分符

  • 分组不保留:
>>>re.split(r"(?:;)",s)
['var A', 'B', 'C:integer', '']
  • 多字符切分:
>>>re.split(r“(in)",s)
['var A;B;C:', 'in', 'teger;']
  • 组合情况:
>>>re.split(r"(in|er|[A-C]|[;:])",s)
['var ', 'A', '', ';', '', 'B', '', ';', '', 'C', '', ':', '', 'in', 'teg', 'er', '', ';', '']

那么对于源程序,我们切分的依据又是什么呢?

  • 首先想到的肯定是各种空白字符:”\n“,"\t","\n"等。由于本实验所分析的文法对缩进是不敏感的,因此在使用这些空白字符进行划分时,我们无需保留它们。

使用\s匹配所有单个空白字符,等价于[\f\n\r\t\v]

import re

with open(file_path,'r') as f:
    raw=f.read()
print(raw)
print(re.split(r"\s",raw))

运行结果

program example2;
var  A,B,C:integer;
     X,Y:bool;
begin  /*  this  is  an  example  */
  A:=B*C+37;
  X:='ABC'
end.

['program', 'example2;', 'var', '', 'A,B,C:integer;', '', '', '', '', '', 'X,Y:bool;', 'begin', '', '/*', '', 'this', '', 'is', '', 'an', '', 'example', '', '*/', '', '', 'A:=B*C+37;', '', '', "X:='ABC'", 'end.', '']

可以看到,很多保留字、标识符等还和;:,:=这些界符黏在一起,我们还要进一步切分

但是请注意,我们不能直接把所有界符当作切分符,因为双界符通常由两个单界符构成,放在一起切分会拆开双界符。

  • 因此我们需要先根据双界符进行切分。
import re

with open(file_path,'r') as f:
    raw = f.read()
PreSplit = re.split(r'(<>|<=|>=|:=|/\*.*\*/|\.\.|\s)', raw)
print(PreSplit)

运行结果

['program', ' ', 'example2;', '\n', 'var', ' ', '', ' ', 'A,B,C:integer;', '\n', '', ' ', '', ' ', '', ' ', '', ' ', '', ' ', 'X,Y:bool;', '\n', 'begin', ' ', '', ' ', '', '/*  this  is  an  example  */', '', '\n', '', ' ', '', ' ', 'A', ':=', 'B*C+37;', '\n', '', ' ', '', ' ', 'X', ':=', "'ABC'", '\n', 'end.', '\n', '']
  • 然后我们还可以把一些不参与构成双界符的单界符(如+,-,(,']'等)也加入:
import re

with open(file_path,'r') as f:
    raw = f.read()
PreSplit = re.split(r'(<>|<=|>=|:=|/\*.*\*/|\.\.|[\+\-\(\)\[\];,\s])', raw)
print(PreSplit)

运行结果

['program', ' ', 'example2', ';', '', '\n', 'var', ' ', '', ' ', 'A', ',', 'B', ',', 'C:integer', ';', '', '\n', '', ' ', '', ' ', '', ' ', '', ' ', '', ' ', 'X', ',', 'Y:bool', ';', '', '\n', 'begin', ' ', '', ' ', '', '/*  this  is  an  example  */', '', '\n', '', ' ', '', ' ', 'A', ':=', 'B*C', '+', '37', ';', '', '\n', '', ' ', '', ' ', 'X', ':=', "'ABC'", '\n'
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值