前言
在这一系列文章中,我们将会使用Python语言来实现PL0编译器。
首先我们来实现编译器中的词法分析的功能。我们使用正则表达式来对源程序的程序语句筛选为:关键字Keywords,数字Numbers,变量Variables,分隔符Separatores和运算符Operatores五种类别。
词法分析器的输出是源程序中的单词和它所对应的类别组成的二元组。
正则表达式
表达式的定义:
例如:
'a.':表示匹配以a开头,后面为除换行符之外任意字符的字符串,小点表示任意字符
'a*':表示匹配零个,一个或者多个a的字符串
'a+':表示匹配一个或者多个a的字符串
'a{2}':表示匹配两个a的字符串
'a{2,3}':表示匹配两个到三个a的字符串
'a[a-z]':表示匹配以a开头,a到z结尾的字符串
' a[a-z] ':表示匹配以空格开头,结尾的字符串,中间为上述字符串的格式
' (a[a-z]) ':表示匹配括号内部的字符串,括号表示优先级
' ([Aa][a-z]) ':表示匹配以A或者a开头的字符串
' *([Aa][a-z]) ':表示以零个或者多个空格开头的字符串,a*表示包含零个,一个或者多个a的字符串
'^0':匹配仅仅在行首的字符0
'0$':匹配仅仅在行末的字符0
'r':表示匹配仅仅以c开头的,后面跟r的字符串
参考链接:正则---re模块的基础用法(re.match() /单个字符匹配/ 多个字符匹配)blog.csdn.netPython中正则表达式 - 二十四长夜明 - 博客园www.cnblogs.com
正则表达式相关函数
compile函数:根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
match函数:
match函数的属性:string:匹配时使用的文本
re:匹配时使用的pattren对象
pos:文本中正则表达式开始搜索的索引。值与 Pattern.match()和 Pattern.seach()方法的同名参数相同。
endpos: 文本中正则表达式结束搜索的索引。值与 Pattern.match()和 Pattern.seach()方法的同名参数相同。
lastindex: 最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为 None。
lastgroup: 最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为 None。
math函数的方法:group 函数,获取一个或多个分组的字符串。
start 函数,返回指定的组截获的子串在 string 中的起始索引。
end 函数,返回指定的组截获的子串在 string 中的结束索引。
span 函数,返回指定的组截获的子串在 string 中的结束索引。
expand 函数,将匹配到的分组代入 template 中然后返回。
注:search方法用来匹配字符串中间的数据,而match方法只能从头开始检索。
编程实现
#引入正则表达式库
import re
#定义表达式
lines = 0
Keywords = r'(?P((const){1}|(var){1}|(procedure){1}|(begin){1}|(end){1}|(odd){1}|(if){1}' \
r'|(then){1}|(call){1}|(while){1}|(do){1}|(read){1}|(write){1}))'
Numbers = r'(?P([0-9]+))'
Variables = r'(?P([a-zA-Z][a-zA-Z0-9]*))'
Operatores = r'(?P(\+|\-|\*|\/|\=|\#|\|>=|:=))'
Separatores = r'(?P([,;.)(]))'
#生成一个正则表达式对象
patterns =re.compile('|'.join([Keywords,Numbers,Variables,Operatores,Separatores]))
def get_token(text):
for match in re.finditer(patterns, text):
yield(match.lastgroup, match.group())
def token_print(text):
for token in get_token(text):
print("line",lines,":",token)
if __name__ == '__main__':
text = "const a=10;var b='a'"
token_print(text)
yield函数用来返回一个可迭代对象,在上述例子中,源程序定义为text变量。
lines变量表示为源程序的行数,此处只对一句源程序进行词法分析。