实验目的及要求
实验目的
通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的类型码及单词符号的自身值。(遇到错误时可显示“Error”,然后跳过错误部分继续显示)
实验要求
用C或C++或其他程序设计语言写一个简单的词法分析程序,程序可以满足下列要求:
1、能分析如下几种简单的语言词法
(1) 标识符: ID=letter(letter|digit)*
(2) 关键字(全部小写)
main int float double char if then else switch case break continue while do for
(3)整型常量:NUM=digit digit*
(4)运算符
= + - * / < <= == != > >= ; ( )? :
(5)空格由空白、制表符和换行符组成,用以分隔ID、NUM、运算符等,字符分析时被忽略。
2、单词符号和相应的类别码
假定单词符号和相应的类别码如下:
单词符号 | 种别码 | 单词符号 | 种别码 | 单词符号 | 种别码 |
---|---|---|---|---|---|
int | 1 | while | 5 | + | 13 |
= | 17 | != | 23 | ( | 27 |
float | 2 | do | 6 | - | 14 |
< | 20 | > | 24 | ) | 28 |
if | 3 | 标识符 | 10 | * | 15 |
<= | 21 | >= | 25 | ? | 29 |
switch | 4 | 整型常量 | 11 | / | 16 |
== | 22 | ; | 26 | : | 30 |
3、词法分析程序实现的功能
输入:单词序列(以文件形式提供),输出识别的单词的二元组序列到文件和屏幕
输出:二元组构成: (syn,token或sum)
其中: syn 为单词的种别码
token 为存放的单词自身符号串
sum 为整型常数
例:
源程序: int ab; float ef=20;
ab=10+ef;
输出:
(保留字–1,int)
(标识符–10,ab)
(分号–26,;)
(保留字–2,float)
(标识符–10,ef)
(等号–17,=)
(整数–11,20)
(分号–26,;)
(标识符–10,ab)
(等号–17,=)
(整数–11,10)
(加号–13,+)
(标识符–10,ef)
(分号–26,;)
实验思路
实验选择python3进行编程
根据要求,不难想到我们需要建立存储单词和其识别码的字典(分为保留字字典、运算符字典),通过py的文件读写功能,获取输入文件的内容,再进行分析。
这里分析采取逐字符分析的办法(相比使用正则理解和实现更容易)。可能出现的字符有空白符、字母符、数字符以及符号符4类。
其中遇到空白符我们直接跳过即可;遇到字母时需要进行单词挖掘,即循环判断下一个字符的内容(遇到非字母和数字时停止),将单词保存到临时的token变量,再判断token是保留字还是标识符,进行输出;遇到数字与符号同理,挖掘完整内容,判断输出。
流程图
源代码
#!/usr/bin/python3
# 关键字字典<关键字名 : 种别码>
key_words = {
'int': 1,
'float': 2,
'if': 3,
'switch': 4,
'while': 5,
'do': 6
}
# 整型常量种别码
int_code = 11
# 标识符种别码
id_code = 10
# 运算符字典<运算符 : 种别码>
operator = {
'=': 17,
'<': 20,
'<=': 21,
'==': 22,
'!=': 23,
'>': 24,
'>=': 25,
';': 26,
'+': 13,
'(': 27,
')': 28,
'-': 14,
'*': 15,
'?': 29,
'/': 16,
':': 30
}
# 运算符名称
operator_name = {
'=': '等号',
'<': '小于号',
'<=': '小于等于号',
'==': '判断等于号',
'!=': '不等于号',
'>': '大于号',
'>=': '大于等于号',
';': '分号',
'+': '加号',
'(': '左括号',
')': '右括号',
'-': '减号',
'*': '星号',
'?': '问号',
'/': '斜杠号',
':': '冒号'
}
# 存储分析结果
result = ''
# 打印token, 同时也会保存到result
def print_token(token: str, code: int, prefix: str):
tmp = '({}--{}, {})'.format(prefix, str(code), token)
global result
result += tmp + '\n'
print(tmp)
# 读取文件
def get_input_file():
with open('TestData.txt', 'r') as f:
return f.read()
# 写入文件
def write_output_file():
with open('Result.txt', 'w') as f:
f.write(result)
def analyse_str(content: str):
print("待分析的字符串:\n" + content + "\n开始分析...\n")
n = 0
while n < len(content):
# 空白符跳过
if content[n].isspace():
n = n + 1
continue
# 开头为字母
if content[n].isalpha():
token = content[n]
n = n + 1
while content[n].isalnum():
token = token + content[n]
n = n + 1
if token in key_words:
print_token(token, key_words.get(token), '保留字')
else:
print_token(token, id_code, '标识符')
continue
# 开头为数字
if content[n].isdigit():
token = content[n]
n = n + 1
while content[n].isdigit():
token = token + content[n]
n = n + 1
print_token(token, int_code, '整数')
continue
# 其他
else:
token = content[n]
n = n + 1
while not content[n].isalnum() and not content[n].isspace():
token = token + content[n]
n = n + 1
if token in operator:
print_token(token, operator.get(token), operator_name.get(token))
else:
print('error: 发现无法识别的字符--' + token)
continue
file_str = get_input_file()
analyse_str(file_str)
write_output_file()
思考题和小结
词法分析中如何识别单词?请具体描述识别过程。
单词由不包含特殊字符(既不是字母、数字也不是运算符)的连续字符或单个字符组成,由此我们便能够很容易的进行判断,以识别标识符或保留字为例,将输入串逐字符进行分析,传入的第一个字符空白则跳过,非空字符我们就进行判断,如果是字母我们就继续接受传入字符直到出现非字母或数字字符(部分语言可以包含”_”)出现,这里我们就获得了标识符或保留字(依据保留字字典进行判断);