用python手工编写一个词法分析器
@author:x1Nge.
- 编译原理基础实验
实验目的
通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解,这里我使用python作为开发语言。
过程分析
为了简化设计,降低难度,这里设计的词法分析器识别以下内容:
类别 | 举例 | 输出举例(种别编码,自身值) |
---|---|---|
保留字 | if 、int、while | (1,“int”) |
标识符 | a、b、c | (2,“a”) |
整常数 | 6、16、36 | (3,“0110”) |
运算符 | +、-、*、/、**、>= | (4,"+") |
分隔符 | ;、{、} | (5,";") |
基本流程图如下:
内容一:编写子功能函数
1.读入下一个字符
# 把下一个字符读入到new_ch中
def get_char():
global p
temp_ch = res_lst[p]
p += 1
return temp_ch
注意:实际工作中并不常用在函数内部用global来使用全局变量
2.跳过空白符直至ch读入一个非空白符
# 跳过空白符直至ch读入一个非空白符
def get_blank_ch(temp_ch_1):
if temp_ch_1 == ' ':
temp_ch_2 = get_char()
return temp_ch_2
return temp_ch_1
3.把ch中的字符连接到str_get之后
# 把ch中的字符连接到str_get之后
def ch_append():
#直接调用python函数
return
有话说:刚开始考虑写词法分析器并未考虑具体语言,于是有一些函数在这里并不需要实现
3.查找保留字表中是否有str_get,若存在则返回1,否则返回0
# 查找保留字表中是否有str_get,若存在则返回1,否则返回0
def is_reserved_word( str_result ):
check_client = pymongo.MongoClient("mongodb://localhost:27017/")
check_db = check_client["PrincipleOfCompiler"]
check_col = check_db["ReservedWord"]
check_query = {"content" : str_result}
for get_text in check_col.find(check_query):
# 判断匹配到的get_text是否为空,若不为空则要匹配的字符串在保留字表中找到
if any(get_text):
check_client.close()
return 1
check_client.close()
return 0
有话说:这里我把保留字表放在了数据库里,使用的是mongodb,当然也可以用My SQL或者其他数据库,python使用的时候需要导入包,mongodb是pymongo
pip install pymongo
import pymongo
4.将搜索指针回调一个字符位置
# 将搜索指针回调一个字符位置
def retract_pointer():
global p
p -= 1
return
5.若识别为标识符,将str_result中的标识符插入符号表并返回符号表指针
# 若识别为标识符,将str_result中的标识符插入符号表并返回符号表指针
def insert_identifier( str_result ):
return str_result
6.若识别为常数,将str_result中的常数插入常数表并返回参数表指针
# 若识别为常数,将str_result中的常数插入常数表并返回参数表指针
def insert_constant( str_result ):
return str(bin(int(str_result)))
有话说:为了简化这里我直接返回了其自身值(整常数返回二进制数)
内容二:编写主功能函数
接下来分析主功能函数的编写,我们按照流程图的框架进行分析:
注意:主功能我都写在一个函数里了,以下部分均为函数内代码,作分析之用,全部源码见下文
初始化
# 初始化
result = []
str_get = []
ch = get_char()
new_ch = get_blank_ch(ch)
识别标识符
# 识别标识符
if new_ch.isalpha() or new_ch == '_' or new_ch == '$':
str_get.append(new_ch)
new_ch = get_char()
while new_ch.isalpha() or new_ch.isdigit() or new_ch == '_' or new_ch == '$':
str_get.append(new_ch)
new_ch = get_char()
retract_pointer()
str_result = ''.join(str_get)
code = is_reserved_word(str_result)
if code == 0 :
value = insert_identifier(str_result)
result.append('2') # 这里使用2作为非保留字的标识符的种别编码
result.append(value)
return result
else:
result.append('1') # 这里使用1作为保留字的种别编码
result.append(str_result) # 实验例子中value值为保留字本身
"""
result.append('-') # 保留字无自身值
"""
return result
识别整常数
# 识别整常数
elif new_ch.isdigit():
str_get.append(new_ch)
new_ch = get_char()
while new_ch.isdigit():
str_get.append(new_ch)
new_ch = get_char()
retract_pointer()
str_result = ''.join(str_get)
value = insert_constant(str_result)
result.append('3') # 这里使用3作为整常数的种别编码
result.append(value)
return result
识别运算符
#识别运算符
elif new_ch == '=' or new_ch == '+' or new_ch == '-' or new_ch == '*' or new_ch == '/' or new_ch == '>'\
or new_ch == '<' or new_ch == '!' or new_ch == '%':
if new_ch == '>' or new_ch == '<' or new_ch == '!':
str_get.append(new_ch)
value = ''.join(new_ch)
new_ch = get_char()
if new_ch == '=':
str_get.append(new_ch)
str_result = ''.join(str_get)
result.append('4') # 这里使用4作为运算符的种别编码
result.append(str_result)
return result
else:
retract_pointer()
result.append('4')
result.append(value)
return result
elif new_ch == '*':
str_get.append(new_ch)
value = ''.join(new_ch)
new_ch = get_char()
if new_ch == '*':
str_get.append(new_ch)
str_result = ''.join(str_get)
result.append('4')
result.append(str_result)
return result
else:
retract_pointer()
result.append('4')
result.append(value)
return result
else:
value = ''.join(new_ch)
result.append('4')
result.append(value)
return result
识别分隔符
# 识别分隔符
elif new_ch == ',' or new_ch == ';' or new_ch == '{' or new_ch == '}' or new_ch == '(' or new_ch == ')':
value = ''.join(new_ch)
result.append('5') # 这里使用5作为分隔符的种别编码
result.append(value)
return result
其他
else:
result.append("Error.")
return result
注意:这里我只是检查了几个主要的分隔符、运算符,若要全部检查,则查询一张完整的表即可
内容三:其他功能代码
文件读入及预处理。这里我 主要将换行和\t去掉,并把两个空格替换为一个空格,如果要去掉全部空格,则记得保留诸如int a这种代码间的空格
f = open('codeTest.txt','r')
res = f.read().replace('\n','').replace('\t','').replace(' ',' ')
res_lst = list(res)
print(res)
p = 0 # 初始化位置指针
运行
while p in range(len(res_lst)):
print(check_code())
f.close()
运行截图及源码
- 个人能力有限,程序有许多考虑不周的地方,欢迎提出修改意见
- 同步更新至CSDN,仅作实验记录之用。
例:
main()
{
int a,b;
a = 10;
b = a + 20;
}
运行:
源码:
import pymongo
"""
code,value 暂不进行初始化
"""
f = open('codeTest.txt','r')
res = f.read().replace('\n','').replace('\t','').replace(' ',' ')
res_lst = list(res)
print(res)
p = 0 # 初始化位置指针
def check_code():
# 初始化
result = []
str_get = []
ch = get_char()
new_ch = get_blank_ch(ch)
# 识别标识符
if new_ch.isalpha() or new_ch == '_' or new_ch == '$':
str_get.append(new_ch)
new_ch = get_char()
while new_ch.isalpha() or new_ch.isdigit() or new_ch == '_' or new_ch == '$':
str_get.append(new_ch)
new_ch = get_char()
retract_pointer()
str_result = ''.join(str_get)
code = is_reserved_word(str_result)
if code == 0 :
value = insert_identifier(str_result)
result.append('2') # 这里使用2作为非保留字的标识符的种别编码
result.append(value)
return result
else:
result.append('1') # 这里使用1作为保留字的种别编码
result.append(str_result) # 实验例子中value值为保留字本身
"""
result.append('-') # 保留字无自身值
"""
return result
# 识别整常数
elif new_ch.isdigit():
str_get.append(new_ch)
new_ch = get_char()
while new_ch.isdigit():
str_get.append(new_ch)
new_ch = get_char()
retract_pointer()
str_result = ''.join(str_get)
value = insert_constant(str_result)
result.append('3') # 这里使用3作为整常数的种别编码
result.append(value)
return result
#识别运算符
elif new_ch == '=' or new_ch == '+' or new_ch == '-' or new_ch == '*' or new_ch == '/' or new_ch == '>'\
or new_ch == '<' or new_ch == '!' or new_ch == '%':
if new_ch == '>' or new_ch == '<' or new_ch == '!':
str_get.append(new_ch)
value = ''.join(new_ch)
new_ch = get_char()
if new_ch == '=':
str_get.append(new_ch)
str_result = ''.join(str_get)
result.append('4') # 这里使用4作为运算符的种别编码
result.append(str_result)
return result
else:
retract_pointer()
result.append('4')
result.append(value)
return result
elif new_ch == '*':
str_get.append(new_ch)
value = ''.join(new_ch)
new_ch = get_char()
if new_ch == '*':
str_get.append(new_ch)
str_result = ''.join(str_get)
result.append('4')
result.append(str_result)
return result
else:
retract_pointer()
result.append('4')
result.append(value)
return result
else:
value = ''.join(new_ch)
result.append('4')
result.append(value)
return result
# 识别分隔符
elif new_ch == ',' or new_ch == ';' or new_ch == '{' or new_ch == '}' or new_ch == '(' or new_ch == ')':
value = ''.join(new_ch)
result.append('5') # 这里使用5作为分隔符的种别编码
result.append(value)
return result
else:
result.append("Error.")
return result
# 把下一个字符读入到new_ch中
def get_char():
global p
temp_ch = res_lst[p]
p += 1
return temp_ch
# 跳过空白符直至ch读入一个非空白符
def get_blank_ch(temp_ch_1):
if temp_ch_1 == ' ':
temp_ch_2 = get_char()
return temp_ch_2
return temp_ch_1
# 把ch中的字符连接到str_get之后
def ch_append():
#直接调用python函数
return
# 查找保留字表中是否有str_get,若存在则返回1,否则返回0
def is_reserved_word( str_result ):
check_client = pymongo.MongoClient("mongodb://localhost:27017/")
check_db = check_client["PrincipleOfCompiler"]
check_col = check_db["ReservedWord"]
check_query = {"content" : str_result}
for get_text in check_col.find(check_query):
# 判断匹配到的get_text是否为空,若不为空则要匹配的字符串在保留字表中找到
if any(get_text):
check_client.close()
return 1
"""
check_doc = check_col.find(check_query)
print(check_doc)
for res in check_doc:
print(res)
"""
check_client.close()
return 0
# 将搜索指针回调一个字符位置
def retract_pointer():
global p
p -= 1
return
# 若识别为标识符,将str_result中的标识符插入符号表并返回符号表指针
def insert_identifier( str_result ):
return str_result
# 若识别为常数,将str_result中的常数插入常数表并返回参数表指针
def insert_constant( str_result ):
return str(bin(int(str_result)))
while p in range(len(res_lst)):
print(check_code())
f.close()