写在实验之前
首先感谢有缘点进来的同道们,本文将介绍使用Python语言来构建一个比较简单的词法分析程序的构建思路和过程,希望能带来一些启发和借鉴。
这个程序不算长,如果精简一下关键词等词表,不到100行。但无论程序是长是短,核心的思路都是不能忘记的。
我在自己尝试写这个程序的过程中,好几次沉浸在细节的实现上调试,以至于逐渐模糊了核心思路,极大地影响了编写程序的进度,希望大家引以为戒。
实验目标
掌握词法分析程序的工作流程
实验内容
编写一个面向高级程序设计语言的简单词法分析程序,能够识别出标识符、关键字、十进制整数和运算符
实验要求
一、在一个txt文件中输入一段有意义的高级程序设计语言(用例为C语言)的源程序,要求:
1.不少于50字符(不计空格)
2.程序中需包括合法的标识符、关键字、十进制整数和运算符
3.必须有回车换行和注释,允许/…/和//…两种注释,且前者可跨行
4.至少含有一个非法的标识符
二、词法分析器读入程序,并进行预处理:删除回车换行和注释,要求:
1.将预处理后的源程序以字符流的形式显示出来
2.写入新的txt中
三、词法分析器扫描预处理后的源程序,识别各单词,要求:
1.识别出的单词以<序号,类型,值>显示
2.对非法标识符,跳过不予显示,但在最后给出出错信息
对实验的分析——核心思路
我们来看一看需要用到哪些知识点:
1.文件读写操作
2.字符串操作
3.循环控制
想要自己动手写程序可以先温习一下相关方法
我们可以先从产出的角度来分析:
程序需要实现哪些功能?
输出删除注释&换行的字符流
输出识别出的单词表
提示非法标识符
不难发现,首当其冲的就是要让计算机认识需要用到的标识符、关键字、十进制整数和运算符
因此先建立一些字符串表,以备识别时使用
注意!在分析实验的时候不建议立刻去实现字符串表的代码,以防偏离重点
之后我们需要打开文件并逐行进行处理,删去回车换行
再对每一行逐字符遍历,找到注释内容并删去
此时就能够得到第一项产出——删除了注释&换行的字符流
接下来,遍历字符流,结合字符串表去识别标识符、关键字、十进制整数和运算符,同时收集可能的错误信息
最后输出单词表和错误提示信息
程序实现
字符串表
# 创建运算符表
dict_op = [
'+',
'-',
'*',
'/',
'=',
'<',
'>',
'<=',
'>=',
'<>'
]
# 创建关键字表
dict_key = [
'int',
'if',
'then',
'else',
'for',
'return',
'void'
]
# 创建界符表
dict_dl = [
'(',
')',
'"',
';',
",",
'{',
'}'
]
涉及文件读写的操作
txt = open('D:\Projects\LATXT\TXT.txt', 'r+')
result = open('D:\Projects\LATXT\RESULT.txt', 'w+')
result.write(string)
txt.close()
result.close()
不要忘记文件有开就要有关哦
判断方法
# 判断当前char是否是数字
def IsNum(char):
if(char >= '0') and (char <= '9'):
return True
else:
return False
# 判断当前char是否是大小写字母
def IsChr(char):
if((char >= 'A') and (char <= 'Z')) or ((char >= 'a') and (char <= 'z')):
return True
else:
return False
# 判断当前char是否是空格
def IsSp(char):
if char == ' ':
return True
else:
return False
预处理
# 预处理文件,删去注释内容,在RESULT文件中写入单行程序流
result = open('D:\Projects\LATXT\RESULT.txt', 'w+')
string = ''
temp = ''
s = False # s真表示现在在注释中
ss = False # ss表示重置s标志
for line in txt.readlines():
index = 0
temp = ''
if ss:
s = False
for char in line.strip():
if index < len(line.strip()) - 1:
index += 1
if not s and char == '/' and line.strip()[index] == '/':
s = True
ss = True
elif not s and char == '/' and line.strip()[index] == '*':
s = True
if s and index >= 2 and line.strip()[index-2] == '/' and line.strip()[index-3] == '*':
s = False
if not s:
temp += char
string += temp
result.write(string)
遍历字符流并输出单词表、错误提示信息
# 逐字扫描string,输出单词
print("单词识别如下:")
Word = ''
index = 0
count = 1
ErrorStr = ''
for char in string:
if index < len(string) - 1:
index += 1
if IsSp(char):
continue
elif char in dict_dl:
print("< No.{} 界符 ".format(count) + char + " >")
count += 1
elif char in dict_op:
Word += char
if string[index] in dict_op:
continue
else:
print("< No.{} 运算符 ".format(count) + Word + " >")
count += 1
Word = ''
elif IsNum(char) or IsChr(char):
Word += char
if not(IsNum(string[index]) or IsChr(string[index])):
if Word in dict_key:
print("< No.{} 关键字 ".format(count) + Word + " >")
count += 1
elif Word[0].isalpha() or Word.isdigit():
print("< No.{} 标识符 " .format(count) + Word + " >")
count += 1
else:
ErrorStr += "第" + str(count) + "个单词" + Word + "是非法标识符!\n"
count += 1
Word = ''
print(ErrorStr)
判别逻辑
对于这道实验来说,for指针只会遇到这四种类型的字符:字母、数字、界符、运算符,因此我们可以特别地构建判别逻辑:

总结
一、核心思路是至关重要的
就像词法分析器的转换图一样,编程时一定要牢记核心思路,紧跟思路去铺开程序。
二、分清主次
编程时要先写好框架主干,后完善细节,不要急着去实现一些细枝末节的小函数,以防扰乱了思路,因小失大。
三、小单元检错
如果等到全部代码写完再调试用例,一旦出错,很难厘清出错位置。因此需要在编程时对每个函数、每个功能都要进行检错,从底层排除错误,扼杀在萌芽阶段。
四、勤写注释
本次实验的代码只有100行左右,但在后续调试中已经出现遗忘程序段实现功能的情况;在以后越来越复杂的代码中,更需要详尽的注释,提高程序的可读性。
本文详细介绍了如何使用Python构建一个简单的词法分析器,涉及文件读写、字符串操作、循环控制和逻辑判断。实验要求包括处理源程序、删除注释和换行、识别单词及错误提示。通过创建运算符、关键字和界符表,遍历字符流以输出单词表和错误信息,强调了编程时保持核心思路的重要性。
916





