用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 开始 初始化 读入字符 忽略空格 字母_$? 读入字符 字母数字_$? 指针回退 查询保留字表 结束 数字? 读入字符 数字? 指针回退 运算符? 分隔符? yes no yes no yes no yes no yes no yes

内容一:编写子功能函数

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()
  • 3
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

x1Nge.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值