【编译原理】词法分析器

【编译原理】词法分析器

实验要求:

设置一个名字表NameL和常数表ConstL,当遇到标识符时,将其字符串送入名字表NameL,并把其名字表地址作为标识符的语义Seman值。常数情形也一样,不要求翻译成二进制数。要求在NameL和ConstL表中没有相同元素,同时具有简单的错误处理功能(找出源程序中所有存在的词法错误并指出错误所在的行数)。试用高级程序设计语言编写一个针对下述单词集的词法分析器。

token表

在这里插入图片描述

评分标准

①是否使用文件输入、输出;
②是否可以查找多个错误;
③每个错误是否有错误提示,包括错误所在行、错误信息;
④错误提示信息是否区分不同类别;
⑤同名标识符或常数是否重复存放;
⑥是否正确建立单词表和名字表、常量表的链接;
⑦是否处理注释。

词法分析器

import re


class MyToken:
    def __init__(self, MyType, seman, MyStr):
        self.MyType = MyType
        self.seman = seman
        self.MyStr = MyStr

    def __str__(self):
        s = self.MyStr.replace('\n','')
        return "token.class:  {:5}\t\tstr:  {:10}\tseman:\t{} \t".format(self.MyType, s, self.seman)


# 单词集状态列表
states = ['if', 'else', 'for', 'while', 'break', 'return', 'continue', 'float', 'int', 'char', '标识符',
          '正整数、正实数、零', '+', '-',
          '*', '/', '%', '>', '>=', '<', '<=', '!=', '==', '!', '&', '|', ',', '=', '[', ']', '(', ')', '{', '}', ';',
          '.', '\\', '#']
choiceStatec = [13, 14, 15, 16, 17, 18, 20, 24, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36]  # 用于防止while循环中出现多次elif
inputs = []  # 输入的字符


tokens = []  # 单词表
NameL = []  # 名字表
ConstL = []  # 常数表



i = 0
line = 1



# 将文件内容提取到inputs
def codeToInputs(sourceCodes):
    for line in sourceCodes:
        for char in line:
            inputs.append(char)
            if char == '#':
                return


# 判断是否为字母
def isLetter(char):
    pattern = r"[a-zA-Z]"
    return bool(re.match(pattern, char))


# 判断是否为数字
def isDigit(char):
    pattern = r"[0-9]"
    return bool(re.match(pattern, char))


# 普通的字符识别
def isC(char, state):
    tokens.append(MyToken(state, "^", char))


def choiceState(char):  # 选择单字符对应状态
    state = 0
    if char in states:
        for k in range(len(states)):
            if states[k] == char:  # 判断单个字符
                if char in ['>', '<', '!', '=', '&', '|', '\\'] and inputs[i] in ['=', '&', '|', 'n']:  # 如果是双字符
                    state = 19
                else:
                    state = k + 1
    else:
        state = 0
    return state


def error():
    print(f"第{line}行---未知字符错误")


# 词法分析
def nextToken():
    global i
    global line
    name = ""
    char = inputs[i]
    i += 1
    while char == ' ' or char == '\n' or char == '\t':  # 如果是空就跳过
        if char == '\n':
            line += 1
        char = inputs[i]
        i += 1
        if char == '#':
            i -= 1
    global state
    state = 0
    while True:

        if state == 0:  # 选择
            if char == '#':
                i -= 1
                state = 38
                continue
            if char == '/' and (inputs[i] == '/' or inputs[i] == '*'):  # 注释
                state = 42
                continue
            if choiceState(char) != 0:  # 判断后面的单字符,获取状态
                state = choiceState(char)
                i -= 1
                continue
            if char == "i":
                state = 1
            elif char == "e":
                state = 2
            elif char == 'f':
                state = 3
            elif char == 'w':
                state = 4
            elif char == 'b':
                state = 5
            elif char == 'r':
                state = 6
            elif char == 'c':
                state = 7
            elif isDigit(char):  # 数字
                state = 12
            elif isLetter(char):  # 字符串
                i -= 1
                state = 11

            else:
                error()  # 非法字符报错
                i -= 1
                state = 38
        elif state == 1:  # if

            if inputs[i] == 'f':  # 判断第二个是否为f
                if isDigit(inputs[i + 1]) or isLetter(inputs[i + 1]):  # 标识符
                    i -= 1
                    state = 11
                else:
                    m = MyToken(1, "^", "if")  # 在单词表和名字表加入
                    tokens.append(m)
                    state = 38

            elif inputs[i] == 'n':  # 判断第二个是否为n
                i += 1
                if inputs[i] == 't':
                    if isDigit(inputs[i + 1]) or isLetter(inputs[i + 1]):  # 标识符
                        i -= 2
                        state = 11
                    else:
                        m = MyToken(9, "^", "int")  # 在单词表和名字表加入
                        tokens.append(m)
                        state = 38
                else:
                    if isDigit(inputs[i]) or isLetter(inputs[i]):  # 标识符
                        i -= 2
                        state = 11
                    else:
                        m = MyToken(11, "^", "in")  # 在单词表和名字表加入
                        tokens.append(m)
                        state = 38
                        i -= 1
            else:  # 以i开头的标识符
                i -= 1
                state = 11

        elif state == 2:  # else
            if ''.join(inputs[i:i + 3]) == 'lse':
                if isDigit(inputs[i + 3]) or isLetter(inputs[i + 3]):
                    i -= 1
                    state = 11
                else:
                    m = MyToken(2, "^", "else")  # 在单词表和名字表加入
                    tokens.append(m)
                    state = 38
                    i += 2
            else:
                i -= 1
                state = 11

        elif state == 3:  # for

            if inputs[i] == 'o':
                if inputs[i + 1] == 'r':
                    if isDigit(inputs[i + 2]) or isLetter(inputs[i + 2]):
                        i -= 1
                        state = 11
                    else:
                        m = MyToken(3, "^", "for")  # 在单词表和名字表加入
                        tokens.append(m)
                        state = 38
                        i += 1
                else:
                    i -= 1
                    state = 11
            elif inputs[i] == 'l':
                if "".join(inputs[i:i + 4]) == 'loat':
                    if isDigit(inputs[i + 4]) or isLetter(inputs[i + 4]):
                        i -= 1
                        state = 11
                    else:
                        m = MyToken(8, "^", "float")  # 在单词表和名字表加入
                        tokens.append(m)
                        state = 38
                        i += 3
                else:
                    i -= 1
                    state = 11
            else:
                i -= 1
                state = 11

        elif state == 4:  # while
            if "".join(inputs[i:i + 4]) == 'hile':
                if isDigit(inputs[i + 4]) or isLetter(inputs[i + 4]):
                    i -= 1
                    state = 11
                else:
                    m = MyToken(4, "^", "while")  # 在单词表和名字表加入
                    tokens.append(m)
                    state = 38
                    i += 3
            else:
                i -= 1
                state = 11


        elif state == 5:  # break
            if "".join(inputs[i:i + 4]) == 'reak':
                if isDigit(inputs[i + 4]) or isLetter(inputs[i + 4]):
                    i -= 1
                    state = 11
                else:
                    m = MyToken(5, "^", "break")  # 在单词表和名字表加入
                    tokens.append(m)
                    state = 38
                    i += 3
            else:
                i -= 1
                state = 11

        elif state == 6:  # return
            if "".join(inputs[i:i + 5]) == 'eturn':
                if isDigit(inputs[i + 5]) or isLetter(inputs[i + 5]):
                    i -= 1
                    state = 11
                else:
                    m = MyToken(6, "^", "return")  # 在单词表和名字表加入
                    tokens.append(m)
                    state = 38
                    i += 4
            else:
                i -= 1
                state = 11

        elif state == 7:  # continue
            if inputs[i] == 'o':
                if "".join(inputs[i + 1:i + 7]) == 'ntinue':
                    if isDigit(inputs[i + 7]) or isLetter(inputs[i + 7]):
                        i -= 1
                        state = 11
                    else:
                        m = MyToken(7, "^", "continue")  # 在单词表和名字表加入
                        tokens.append(m)
                        state = 38
                        i += 6
                else:
                    i -= 1
                    state = 11

            elif inputs[i] == 'h':
                if "".join(inputs[i + 1:i + 3]) == 'ar':
                    if isDigit(inputs[i + 3]) or isLetter(inputs[i + 3]):
                        i -= 1
                        state = 11
                    else:
                        m = MyToken(10, "^", "char")  # 在单词表和名字表加入
                        tokens.append(m)
                        state = 38
                        i += 2
                else:
                    state = 11
                    i -= 1
            else:
                i -= 1
                state = 11
        elif state == 11:  # 标识符
            char = inputs[i]
            i += 1
            name += char
            if isLetter(char):
                state = 39
            else:
                state = 40

        elif state == 12:

            name += char
            char = inputs[i]
            if isDigit(inputs[i]):  # 判断数字
                i += 1
                state = 12
            else:
                if inputs[i] == ' ' or inputs[i] == '\n' or inputs[i] == '\t' or inputs[i] == '#':

                    flag = 0
                    index = -1
                    for ii in range(len(ConstL)):
                        if ConstL[ii].MyStr == name:
                            flag = 1
                            index = ii
                    if flag == 1:
                        tokens.append(MyToken(12, index, name))

                    else:
                        ConstL.append(MyToken(12, len(ConstL), name))
                        tokens.append(MyToken(12, len(ConstL)-1, name))

                else:
                    print(f"第{line}行---标识符错误")
                    char = inputs[i]
                    while char != ' ' and char != '\t' and char != '\n' and char != '#':
                        i += 1
                        char = inputs[i]
                state = 38
                i -= 1

        elif state == 19:  # 处理双字符
            m = ""
            if inputs[i] == '>' and inputs[i + 1] == '=':
                m = MyToken(19, "^", ">=")
            if inputs[i] == '<' and inputs[i + 1] == '=':
                m = MyToken(21, "^", "<=")
            if inputs[i] == '!' and inputs[i + 1] == '=':
                m = MyToken(22, "^", "!=")
            if inputs[i] == '=' and inputs[i + 1] == '=':
                m = MyToken(23, "^", "==")
            if inputs[i] == '&' and inputs[i + 1] == '&':
                m = MyToken(25, "^", "&&")
            if inputs[i] == '|' and inputs[i + 1] == '|':
                m = MyToken(26, "^", "||")
            if inputs[i] == '\\' and inputs[i + 1] == 'n':
                m = MyToken(37, "^", "\\n")
            tokens.append(m)
            i += 1
            return

        elif state == 38:  # 文件结束
            return
        elif state == 39:  # 处理标识符
            char = inputs[i]
            i += 1
            if char == '#':
                i -= 1
                state = 40
                continue

            if isDigit(char) or isLetter(char):
                state = 39
                if char != '\n':
                    name += char
                else:
                    line += 1

            else:  # 不是字母和数字,就不是标识符了
                state = 40
        elif state == 40:
            flag = 0
            index = -1
            for ii in range(len(NameL)):
                if NameL[ii].MyStr == name:
                    flag = 1
                    index = ii
            if flag == 1:
                tokens.append(MyToken(11, index, name))

            else:
                NameL.append(MyToken(11, len(NameL), name))
                tokens.append(MyToken(11, len(NameL)-1, name))


            i -= 2  # 外面的while+1,所以这里要-1
            if char == '#':
                i += 1
            try:
                if states.index(char) and char != '#':  # 如果有字符
                    name = name[:-1]
                    state = 41

            except:
                pass
            return
        elif state == 41:
            st = states.index(char)
            isC(char, st)
            i -= 1
            return
        elif state == 42:  # 处理注释 // /**/
            if inputs[i] == '/':  # //注释
                i += 1
                char = inputs[i]
                while char != '\n':
                    i += 1
                    char = inputs[i]
                i += 1
                state = 0
            pass
        elif state in choiceStatec:
            isC(states[state - 1], state)  # 普通的字符识别
            return
        else:
            pass


# 从文件读取内容
def readSourceCode(read_path):
    with open(read_path, "r") as file:
        lines = file.readlines()
    return lines

# def sort_by_type(token):
#     return token.MyType


# 将单词表输出到文件
def writeTokens(tokens,Name,Const):
    with open("tokens.txt", "w") as file:
        for token in tokens:
            file.write(f"{token}\n")
    with open("NameL.txt","w") as file:
        for n in Name:
            file.write(str(n)+"\n")
    with open("ConstL.txt", "w") as file:
        for c in Const:
            file.write(str(c)+"\n")

if __name__ == '__main__':
    read_path = 'source_code.txt'
    sourceCodes = readSourceCode(read_path)
    codeToInputs(sourceCodes)
    while inputs[i] != '#':
        nextToken()
        i += 1
    tokens.append(MyToken(38, "^", "#"))  # 最后一个
    writeTokens(tokens,NameL,ConstL)




"""
设置一个名字表NameL和常数表ConstL,当遇到标识符时,将其字符串送入名字表NameL,并把其名字表地址作为标识符的语义Seman值。
常数情形也一样,不要求翻译成二进制数。
要求在NameL和ConstL表中没有相同元素,同时具有简单的错误处理功能(找出源程序中所有存在的词法错误并指出错误所在的行数)。
试用高级程序设计语言编写一个针对下述单词集的词法分析器
"""
# 单词       编码  语义
# if         1     空(^)
# else       2     空(^)
# for        3     空(^)
# while      4     空(^)
# break      5     空(^)
# return     6     空(^)
# continue   7     空(^)
# float      8     空(^)
# int        9     空(^)
# char       10    空(^)
# 标识符      11    名字表地址
# 正整数      12    常数表地址
# 正实数      12    常数表地址
# 零         12    常数表地址
# +          13    空(^)
# -          14    空(^)
# *          15    空(^)
# /          16    空(^)
# %          17    空(^)
# >          18    空(^)
# >=         19    空(^)
# <          20    空(^)
# <=         21    空(^)
# !=         22    空(^)
# ==         23    空(^)
# !          24    空(^)
# &&         25    空(^)
# ||         26    空(^)
# ,          27    空(^)
# =          28    空(^)
# [          29    空(^)
# ]          30    空(^)
# (          31    空(^)
# )          32    空(^)
# {          33    空(^)
# }          34    空(^)
# ;          35    空(^)
# .          36    空(^)
# 换行符      37    空(^)
# 文件结束    38    空(^)

运行

首先创建:source_code.txt

123 456 123
while ( i < 0 )
    if i > 1
        return
    else
        i += 1
for ( int i = 0 ; i <= 3 ; i += 1 )
    flag += 1
    if flag == 10
        continue
int j = 0 ;
#

执行后,会在同目录下生成三个文件:
tokens.txt、NameL.txt、ConstL.txt

token.txt内容如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/273280.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java八股 集合

常见集合篇-01-集合面试题-课程介绍_哔哩哔哩_bilibili 1.时间复杂度 ------List 2.ArrayList扩容机制1.5 2.1 List和数组互转 3.LinkedList链表 3.1 LinkedList和ArrayList区别 4.HashMap 4.1红黑树 红黑树会自平衡&#xff0c;所以是二叉排序树BST的plus自平衡版。 4.2 散列…

瞬态抑制二极管(TVS)的主要参数?|深圳比创达电子

一、最大反向漏电流IR&#xff08;Reverse Leakage Current&#xff09;和额定反向关断电压VRVRWM&#xff08;Stand-off Voltage&#xff09;&#xff1a;VR是TVS的最大直流工作电压&#xff0c;当TVS两极的电压小于VR时&#xff0c;TVS处于关断状态&#xff0c;此时流过的最大…

软件系统详细设计说明书(直接套用)

1引言 1.1编写目的 1.2项目背景 1.3参考材料 2系统总体设计 2.1整体架构 2.2整体功能架构 2.3整体技术架构 2.4设计目标 2.5.1总体原则 2.5.2实用性和先进性 2.5.3标准化、开放性、兼容性 2.5.4高可靠性、稳定性 2.5.5易用性 2.5.6灵活性和可扩展性 2.5.7经济性和投资保护 3系统…

LeetCode刷题--- N 皇后

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​​​​http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述递归…

实现高效、透明、公正的采购寻源——鸿鹄电子招投标系统

在数字化时代&#xff0c;企业需要借助先进的数字化技术来提高工程管理效率和质量。招投标管理系统作为企业内部业务项目管理的重要应用平台&#xff0c;涵盖了门户管理、立项管理、采购项目管理、采购公告管理、考核管理、报表管理、评审管理、企业管理、采购管理和系统管理等…

24款奔驰GLS450升级香氛负离子 车载香薰功能

相信大家都知道&#xff0c;奔驰自从研发出香氛负离子系统后&#xff0c;一直都受广大奔驰车主的追捧&#xff0c;香氛负离子不仅可以散发出清香淡雅的香气外&#xff0c;还可以对车内的空气进行过滤&#xff0c;使车内的有害气味通过负离子进行过滤&#xff0c;达到车内保持清…

侦探IP“去推理化”:《名侦探柯南》剧场版走过26年

2023年贺岁档&#xff0c;柯南剧场版的第26部《黑铁的鱼影》如期上映。 这部在日本狂卷票房128亿日元的作品&#xff0c;被誉为有史以来柯南剧场版在商业成绩上最好的一部。 但该作在4月份日本还未上映前&#xff0c;就于国内陷入了巨大的争议。 试映内容里&#xff0c;灰原…

计算机视觉基础(13)——深度估计

前言 本节是计算机视觉的最后一节&#xff0c;我们将学习深度估计。从深度的概念和度量入手&#xff0c;依次学习单目深度估计和双目/多目深度估计&#xff0c;需要知道深度估计的经典方法&#xff0c;掌握深度估计的评价标准&#xff0c;注意结合对极几何进行分析和思考。 一、…

Linux账号和权限管理

目录 前言 一、管理用户账号 1、Linux系统中用户账号类型 2、用户标识UID的分类 3、用户账号文件 4、用户账号的初始配置文件 5、用户账号的管理命令 5.1 useradd 5.2 usermod 5.3 passwd 5.4 userdel 二、管理组账号 1、Linux系统中组账号类型 2、组标识号GID的…

PointNet人工智能深度学习简明图解

PointNet 是一种深度网络架构&#xff0c;它使用点云来实现从对象分类、零件分割到场景语义解析等应用。 它于 2017 年实现&#xff0c;是第一个直接将点云作为 3D 识别任务输入的架构。 本文的想法是使用 Pytorch 实现 PointNet 的分类模型&#xff0c;并可视化其转换以了解模…

工程监测中振弦采集仪与其他监测技术的比较研究

工程监测中振弦采集仪与其他监测技术的比较研究 工程监测中常用的监测技术包括振弦采集仪、激光测距仪、全站仪、GPS等。下面是振弦采集仪与其他监测技术的比较研究&#xff1a; 1. 测量精度&#xff1a;振弦采集仪可以实现毫米级别的测量精度&#xff0c;对于振动、位移等参数…

用友U8CRM系统help2 任意文件读取漏洞复现

用友U8CRM系统的help2文件中接口存在任意文件读取漏洞&#xff0c;攻击者在未登录情况下即可进行漏洞利用。 1.1 漏洞级别 高危 1.2 快速检索 fofa语法&#xff1a; title"用友U8CRM"1.3 漏洞复现 该漏洞利用非常简单&#xff0c;只需构造get请求 访问该地址即可…

跨境电商速卖通、Lazada、Shopee为什么要自己做补单测评,看完就明白了

大家好&#xff0c;今天来跟大家聊一下速卖通补单的一些事项&#xff0c;首先要知道&#xff0c;国内补单跟跨境补单&#xff0c;其实核心是差不多的&#xff0c;只不过国内的补单可能要找一些团队补单。做国内电商的的卖家很多会自己建立鱼塘来给自己补单&#xff0c;这样也比…

C# 实现虚拟数字人

随着Ai技术的提升和应用&#xff0c;虚拟数字人被广泛应用到各行各业中。为我们的生活和工作提供了非常多的便利和色彩。 通过设置虚拟数字人的位置大小&#xff0c;可以让数字人可以在电脑屏幕各个位置显示&#xff1a; 虚拟数字人素材&#xff1a; 虚拟数字人(实际有语音&am…

idea利用JRebel插件,无需重启,实现Spring Boot项目热重载,节省开发时间和精力!

插件介绍 官方介绍 翻译过来的意思是&#xff1a; JRebel 是一款提高开发效率的工具&#xff0c;允许开发者立即重新加载代码更改。它跳过了在Java开发中常见的重新构建、重启和重新部署循环。JRebel 能够让开发者在相同的时间内完成更多工作&#xff0c;并且在编码时能够保持…

WPF 消息日志打印帮助类:HandyControl+NLog+彩色控制台打印

文章目录 前言相关文章Nlog配置HandyControl配置简单使用显示效果文本内容 前言 我将简单的HandyControl的消息打印系统和Nlog搭配使用&#xff0c;简化我们的代码书写 相关文章 .NET 控制台NLog 使用 WPF-UI HandyControl 控件简单实战 C#更改控制台文字输出颜色 Nlog配置 …

2024年3月电子学会青少年编程等级考试时间安排

1考试方式 1. 在线居家考试&#xff08;全国&#xff09;&#xff1b; 2. 对于符合线下考试要求的考试服务网点&#xff0c;经地方实地调研报学会总部批准后&#xff0c;可组织线下考试。 2报名时间 报名时间&#xff1a;2023年12月21日-2024年3月12日16:00&#xff1b; 考…

2024有什么好用的电脑录屏软件?TSC2024喀秋莎Camtasia中文版本新功能介绍

Camtasia2024最新版本是一款屏幕录制和视频剪辑软件&#xff0c;教授课程&#xff0c;培训他人&#xff0c;以更快的速度和更吸引人的方式进行沟通和屏幕分享。使您在Windows和Mac上进行录屏和剪辑创作专业外观的视频变得更为简单。 多轨编辑 支持多轨道编辑&#xff0c;方便对…

背道而驰的两家企业

写在前面 先给昨天的 推文 做个更新。 昨天说到&#xff0c;抖音官方辟谣了收购饿了么的事情。 当天&#xff0c;阿里发生较大的人事变动&#xff0c;然后再次传出「盒马」和「饿了么」摆上货架的事情&#xff0c;随后又被快速否认。 当一个假消息被反复而又密集地提起&#xf…

提升FTP上传速度的方法(提升FTP下载速度的技巧)

在企业日常经营中&#xff0c;快速上传和下载文件至关重要。然而&#xff0c;在使用FTP&#xff08;文件传输协议&#xff09;进行文件传输时&#xff0c;速度可能成为瓶颈。为了提升工作效率&#xff0c;以下是一些建议&#xff0c;可以帮助企业提高FTP上传下载速度。 1、确保…
最新文章