编译原理——Python实现C语言词法分析器

编译原理——Python实现C语言词法分析器

程序采用pyside2进行交互界面设计,需要下载相应的库

  1. 运行效果
    在这里插入图片描述
  2. 代码
from PySide2.QtWidgets import QApplication, QMessageBox, QFileDialog
from PySide2.QtUiTools import QUiLoader
import os
class Main:
    #c语言关键字,运算符,界符
    key_word=['auto','break','case','char','const','continue','default','do',
              'double','else','enum','extern','float','for','goto','if',
              'int','long','register','return','short','signed','sizeof','static',
              'struct','switch','typedef','union','unsigned','void','volatile','while']
    delimiters = ['{', '}', '[', ']', '(', ')', '.', ',', ':', ';']
    operator = ['+', '-', '*', '/',':=', '<', '<>', '<=', '>', '>=', '=', '==','&','++','--']
    #词法错误计数
    error_count = 0
    len_key = len(key_word)
    len_del = len(delimiters)
    len_ope = len(operator)
    #存放分析所有结果
    all_list = []
    def __init__(self):
        # 从文件中加载UI定义
        # 从 UI 定义中动态 创建一个相应的窗口对象
        # 注意:里面的控件对象也成为窗口对象的属性了
        # 比如 self.ui.button , self.ui.textEdit

        self.ui = QUiLoader().load('main.ui')
        #多行文本框提示内容
        self.ui.starttxt.setPlaceholderText('请在这里输入代码')
        # 为菜单创建链接
        self.ui.open.triggered.connect(self.openFile)
        self.ui.save.triggered.connect(self.saveFile)
        self.ui.exit.triggered.connect(self.exitFile)
        self.ui.allow_ed.triggered.connect(self.allow_ed)
        self.ui.refuse_ed.triggered.connect(self.refuse_ed)
        self.ui.words_an.triggered.connect(self.words_an)
     #   self.ui.nfa.triggered.connect(self.NFA)
    def openFile(self):#打开文件
        # 选中文件,返回路径
        filePath = QFileDialog.getOpenFileName(self.ui, "选择文件路径")
        #若打开文件位置为空,返回
        if filePath[0]=='':
            return
        else:
            f = open(filePath[0], 'r', encoding='utf8')
            message=f.read()
            f.close()
        # 将读取文件内容放入多行文本框
        self.ui.starttxt.setPlainText(message)
    def saveFile(self):#保存文件
        ans1= self.ui.end1.toPlainText()
        ans2= self.ui.end2.toPlainText()
        # 返回文件存储路径
        dirpath = QFileDialog.getSaveFileName(self.ui,'文件存储路径')
        #若存储文件位置为空
        if dirpath[0]=="":
            return
        else:
            f =open(dirpath[0],'w+',encoding='utf8')
            f.write(ans1)
            f.write('\n'+ans2)
            f.close()
    def exitFile(self):
        exit(app.exec_())
    def allow_ed(self):
        self.ui.starttxt.setEnabled(True)
    def refuse_ed(self):
        self.ui.starttxt.setEnabled(False)
    # def NFA(self):
    #     os.system("python NFA.py")
    def words_an(self):
        #读取内容到text
        text = self.ui.starttxt.toPlainText()
        #在词法分析之前将上次词法分析的内容清空
        self.all_list.clear()
        self.ui.end1.clear()
        self.ui.end2.clear()
        for line in text.splitlines():
            word = ''
            word_line = []
            i = 0
            #循环将字符串读入word,遇到界符或者运算符停下开始判断
            while i < len(line):
                word += line[i]
                if line[i] == ' ' or line[i] in self.delimiters or line[i] in self.operator:
                    #当word以英文字母,‘$’,‘_’开头时,判断是关键字还是标识符
                    if word[0].isalpha() or word[0] == '$' or word[0] == '_':
                        word = word[:-1]
                        if word in self.key_word:
                            # 关键字
                            # 将关键字及关键字在关键字列表中的位置以字典形式存放在word_line列表中
                            word_line.append({word: self.key_word.index(word)})
                        else:
                            # 标识符
                            # 标识符位置置零同样以字典形式存放在word_line中
                            word_line.append({word: 0})
                    # 常数
                    elif word[:-1].isdigit():
                        #常数中出现小数点,进行小数的判断
                        sign =0
                        if line[i]=='.':
                            i =i+1
                            word2 =''
                            #从小数点后循环读入,直至遇到空格,运算符或界符停止,小数部分读完
                            while True:
                                word2+=line[i]
                                #当小数点后仍然出现小数点时,此时应该出现错误
                                if line[i]=='.':
                                    sign =1
                                    i=i+1
                                    continue
                                if line[i] == ' ' or line[i] in self.delimiters or line[i] in self.operator:
                                    word =word+word2
                                    break
                                i =i+1
                            if sign==0:
                                #将小数以字典形式加入列表
                                word_line.append({word[:-1]: -1})
                            else:
                                word_line.append({word[:-1]: -3})#错误的小数
                        else:
                            word_line.append({word[:-1]: -1})
                    # 不合法标识符
                    elif word[:-1]!='':
                        word_line.append({word[:-1]:-2})
                        self.error_count = self.error_count+1
                    # 字符是界符
                    if line[i] in self.delimiters:
                        word_line.append({line[i]: self.len_key + self.delimiters.index(line[i])})
                    # 字符是运算符
                    elif line[i] in self.operator:
                        s = line[i] + line[i + 1]
                        #两位运算符
                        if s in self.operator:
                            word_line.append({s: self.len_key + self.len_del + self.operator.index(s)})
                            i += 1
                        #单位运算符
                        else:
                            word_line.append({line[i]: self.len_key + self.len_del + self.operator.index(line[i])})
                    #每判断一个单词,word置为空
                    word = ''
                i += 1
            self.all_list.append(word_line)#将单词信息存放在word_line列表中
        #将判断的信息打印在控制台
        for i in range(len(self.all_list)):
            print(self.all_list[i])
        self.show()
    def circle(self):
        pass
    def show(self):
        self.ui.end1.append('-----------------------------------------------')
        self.ui.end1.append('行号'+'  '+'单词'+'   '+'类型'+'   '+'是否合法'+'   '+'单词码'+'  ')
        self.ui.end1.append('-----------------------------------------------')
        self.ui.end2.append(str(self.error_count)+'  errors')
        #显示完毕后,错误计数归零
        self.error_count = 0
        self.ui.end2.append('-----------------------------------------------')
        #循环遍历列表,判断每个单词的类型和是否合法
        for i in range(len(self.all_list)):
            l = len(self.all_list[i])
            for j in range(l):
                leixing = ''
                hefa = ''
                #number为存储单词的单词码,words为该单词
                number =list(self.all_list[i][j].values())[0]
                words =list(self.all_list[i][j].keys())[0]
                if 0< number <=self.len_key:
                    leixing = '保留字'
                    hefa ='合法'
                elif self.len_key< number <=self.len_key+self.len_del:
                    leixing = '界符'
                    hefa = '合法'
                elif self.len_key+self.len_del< number <=self.len_key+self.len_del+self.len_ope:
                    leixing = '运算符'
                    hefa = '合法'
                elif number==0:
                    leixing ='标识符'
                    hefa = '合法'
                elif number==-1:
                    leixing = '常数'
                    hefa = '合法'
                elif number==-2:
                    leixing ='标识符'
                    hefa ='不合法'
                elif number==-3:
                    leixing ='常数'
                    hefa ='不合法'
                if hefa =='合法':
                    self.ui.end1.append("{:<6}{:<6}{:<8}{:<7}{:<5}".format(i+1,words,leixing,hefa,number))
                else:
                    self.ui.end1.append("{:<6}{:<6}{:<8}{:<7}{:<5}{}".format(i+1, words, leixing, hefa, number,'<-错误行'))
                    if number==-2:
                        self.ui.end2.append("{:<6}{:<6}{:<10}".format(i+1,words,'标识符命名错误'))
                    elif number==-3:
                        self.ui.end2.append("{:<6}{:<6}{:<10}".format(i + 1, words, '常数命名错误'))
app = QApplication([])
start = Main()
start.ui.show()
app.exec_()
  • 5
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值