用python手工编写一个词法分析器

用python手工编写一个词法分析器

@author:x1Nge.

  • 编译原理基础实验

实验目的

通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解,这里我使用python作为开发语言。

过程分析

为了简化设计,降低难度,这里设计的词法分析器识别以下内容:

类别 举例 输出举例(种别编码,自身值)
保留字 if 、int、while (1,“int”)
标识符 a、b、c (2,“a”)
整常数 6、16、36 (3,“0110”)
运算符 +、-、*、/、**、>= (4,"+")
分隔符 ;、{、} (5,";")

基本流程图如下:

Created with Raphaël 2.2.0开始初始化读入字符忽略空格字母_$?读入字符字母数字_$?指针回退查询保留字表结束数字?读入字符数字?指针回退运算符?分隔符?yesnoyesnoyesnoyesnoyesnoyes

内容一:编写子功能函数

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;
}

运行:
p1
源码:

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()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章