Example #1
0
class Window(QMainWindow):
    def __init__(self):
        super(Window, self).__init__()

        self.setWindowTitle('MIPS')  # 窗口标题

        # 设置各项菜单
        self.setupFileMenu()
        self.setupAssembleMenu()
        self.setupDebugMenu()
        self.setupHelpMenu()

        self.setupEditor()  # 设置编辑器
        self.setCentralWidget(self.editor)

        self.setupDock()  # 设置Dock栏

    def setupEditor(self):
        self.editor = Editor()  # 创建编辑器对象

    def setupFileMenu(self):
        fileMenu = QMenu('文件(&F)', self)
        self.menuBar().addMenu(fileMenu)

        self.currentFile = ''  # 设置当前文件路径为空值

        fileMenu.addAction('新建(&N)', self.newFile, 'Ctrl+N')  # 新建立一个文件
        fileMenu.addAction('打开(&O)...', self.openFile, 'Ctrl+O')  # 打开已有的文件
        fileMenu.addAction('保存(&S)', self.saveFile, 'Ctrl+S')  # 将当前文件保存
        fileMenu.addAction('另存为(&A)...', self.saveAnotherFile,
                           'Ctrl+Alt+S')  # 将当前文件保存到指定路径
        fileMenu.addAction('退出(&X)', self.close, 'Ctrl+F4')  # 退出MIPS汇编器

    def setupAssembleMenu(self):
        assembleMenu = QMenu('汇编(&A)', self)
        self.menuBar().addMenu(assembleMenu)

        self.assembler = Assembler()  # 创建汇编器对象

        assembleMenu.addAction('汇编(&A)', self.assemble, 'F10')  # 对当前代码实行汇编操作
        assembleMenu.addAction('反汇编(&D)', self.disassemble,
                               'F11')  # 对当前代码实行反汇编操作

    def setupDebugMenu(self):
        assembleMenu = QMenu('调试(&D)', self)
        self.menuBar().addMenu(assembleMenu)

        self.isStart = False  # 设置是否开始调试布尔值为否

        assembleMenu.addAction('启动调试(&S)', self.startDebug, 'F5')  # 启动调试
        assembleMenu.addAction('继续调试(&C)', self.contiuneDebug,
                               'F5')  # 将调试进行到最后一步
        assembleMenu.addAction('单步执行(&I)', self.nextDebug, 'F11')  # 单步进行调试
        assembleMenu.addAction('停止调试(&S)', self.stopDebug,
                               'Shift+F5')  # 停止调试过程
        assembleMenu.addAction('重启调试(&R)', self.resetDebug,
                               'Ctrl+Shift+F5')  # 重新启动调试过程

    def setupHelpMenu(self):
        helpMenu = QMenu("帮助(&H)", self)
        self.menuBar().addMenu(helpMenu)

        helpMenu.addAction('关于(&A)', self.about)  # 本程序的小介绍

    def setupDock(self):
        # 建立输出运行结果的窗口
        self.rightBrowser = Browser()  # 建立在窗口右端
        self.rightDock = QDockWidget('运行结果/内存', self)
        self.rightDock.setFeatures(QDockWidget.DockWidgetClosable)
        self.rightDock.setWidget(self.rightBrowser)
        self.addDockWidget(Qt.RightDockWidgetArea, self.rightDock)
        self.rightDock.hide()  # 窗口自动隐藏

        # 建立输出调试过程的窗口
        self.bottomBrowser = Browser()  # 建立在窗口底端
        self.bottomDock = QDockWidget('调试窗口', self)
        self.bottomDock.setFeatures(QDockWidget.DockWidgetClosable)
        self.bottomDock.setWidget(self.bottomBrowser)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.bottomDock)
        self.bottomDock.hide()

    def newFile(self):
        self.editor.clear()  # 清空当前屏幕
        self.rightDock.hide()  # 隐藏Dock栏
        self.bottomDock.hide()
        self.currentFile = ''
        return True

    def openFile(self):
        # 打开汇编文件或二进制文件
        path, _ = QFileDialog.getOpenFileName(
            self, '打开', '', '汇编文件 (*.asm);;二进制文件(*.coe *.bin)')

        if path:
            file = open(path, 'r')
            self.editor.setPlainText(file.read())
            file.close()

            self.rightDock.hide()
            self.bottomDock.hide()

            self.currentFile = path
            return True

        return False

    def saveFile(self):
        # 如果没有文件名则跳转到另存为
        if not self.currentFile:
            return self.saveAnotherFile()

        # 将编辑器内容写入到当前路径文件
        file = open(self.currentFile, 'w')
        file.write(self.editor.toPlainText())
        file.close()

        return True

    def saveAnotherFile(self):
        # 选择存入文件路径
        path, _ = QFileDialog.getSaveFileName(
            self, '另存为', self.currentFile if self.currentFile else '',
            '汇编文件 (*.asm);;二进制文件(*.coe *.bin)')

        # 路径存在则将编辑器内容写入
        if path:
            file = open(path, 'w')
            file.write(self.editor.toPlainText())
            file.close()

            self.currentFile = path
            return True

        return False

    def assemble(self):
        self.saveFile()  # 执行前保存文件

        try:
            self.rightBrowser.setText(self.assembler.assembly(
                self.currentFile))  # 执行汇编并在右侧输出结果
        except:
            self.rightBrowser.setText(
                'error!!! \ncheck your code!!!')  # 代码有误不能正确汇编
        return self.rightDock.show()

    def disassemble(self):
        self.saveFile()

        try:
            self.rightBrowser.setText(
                self.assembler.disassembly(self.currentFile))  # 执行反汇编并在右侧输出结果
        except:
            self.rightBrowser.setText(
                'error!!! \ncheck your code!!!')  # 代码有误不能正确反汇编
        return self.rightDock.show()

    def startDebug(self):
        self.saveFile()

        self.assembler.step = 0  # 初始化执行步数
        self.debugStr = ''  # 初始化结果字符
        self.isStart = True  # 设定已经开始

        # 初始化寄存器内容
        for k in self.assembler.registers:
            self.assembler.registers[k] = '00000000'
        self.assembler.memory = {}  # 初始化内存

        try:
            self.assembler.debug(self.currentFile)
            self.debugStr = str(self.assembler.memory).strip("{}").replace(
                "'", '').replace(':', ' ').replace(',', ' ')  # 执行单步模拟操作
        except:
            self.debugStr += '\nthe debug is over\nnow check your code'  # 模拟完成或代码有误则停止
            return False

        # 将寄存器内容展示在底部,结果展示在右部
        self.bottomBrowser.setText(' ' + str(self.assembler.registers).strip(
            "{},").replace(':', '\t').replace(',', '\t').replace("'", ''))
        self.rightBrowser.setText(self.debugStr)
        self.rightDock.show()
        self.bottomDock.show()
        return True

    def contiuneDebug(self):
        # 如果没有开始则开始调试
        if not self.isStart:
            self.startDebug()

        # 模拟进行到最后一步
        while self.nextDebug():
            continue

        self.bottomBrowser.setText(
            str(self.assembler.registers).strip("{},").replace(
                ':', '\t').replace(',', '\t').replace("'", ''))
        self.rightBrowser.setText(self.debugStr)
        self.rightDock.show()
        self.bottomDock.show()
        return True

    def nextDebug(self):
        if not self.isStart:
            return self.startDebug()

        try:
            self.assembler.debug(self.currentFile)
            self.debugStr = str(self.assembler.memory).strip("{}").replace(
                "'", '').replace(':', ' ').replace(',', ' ')
        except:
            self.debugStr += '\nthe debug is over\nnow check your code'
            self.rightBrowser.setText(self.debugStr)
            self.rightDock.show()
            return False

        self.bottomBrowser.setText(
            str(self.assembler.registers).strip("{},").replace(
                ':', '\t').replace(',', '\t').replace("'", ''))
        self.rightBrowser.setText(self.debugStr)
        self.rightDock.show()
        self.bottomDock.show()
        return True

    def stopDebug(self):
        self.isStart = False  # 结束调试并将开始置否
        self.bottomDock.hide()
        self.rightDock.hide()
        return True

    def resetDebug(self):
        self.stopDebug()
        return self.startDebug()

    def about(self):
        # 简短介绍本程序
        QMessageBox.about(
            self, '关于本MIPS汇编器', '<p style="font-size: 16px;">Made By Aaron</p>'
            '<p style="font-size: 16px;">可实现MIPS汇编器(支持伪码),反汇编器,调试器</p>'
            '<p style="font-size: 16px;">介绍请见README.md</p>'
            '<p style="font-size: 16px;">具体细节请参考实验报告')