python实现文法左递归的消除方法


Posted in Python onMay 22, 2020

前言

  • 继词法分析后,又来到语法分析范畴。完成语法分析需要解决几个子问题,今天就完成文法左递归的消除。
  • 没借鉴任何博客,完全自己造轮子。

开始之前

  • 文法左递归消除程序的核心是对字符串的处理,输入的产生式作为字符串,对它的拆分、替换与合并操作贯穿始终,处理过程的逻辑和思路稍有错漏便会漏洞百出。
  • 采用直接改写法,不理解左递归消除方法很难读懂代码。

要求

  • CFG文法判断
  • 左递归的类型
  • 消除直接左递归和间接左递归
  • 界面

源码

import os
import tkinter as tk
import tkinter.messagebox
import tkinter.font as tf

zhuizhong = ""
wenfa = {"非左递归文法"}
xi_ = ""
huo = ""

window = tk.Tk()
window.title('消除左递归')
window.minsize(500,500)
#转换坐标显示形式为元组
def getIndex(text, pos):
  return tuple(map(int, str.split(text.index(pos), ".")))

def zhijie(x,y):
  if not len(y):
    pass
  else:
    if x == y[0]:
      wenfa.discard("非左递归文法")
      #处理直接左递归
      zuobian = y.split('|')
      feizhongjie = []
      zhongjie = []
      for item in zuobian:
        if x in item:
          item = item[1:]
          textt = str(item) + str(x) + "'"
          feizhongjie.append(textt)
        else:
          text = str(item) + str(x) + "'"
          zhongjie.append(text)
      if not zhongjie:#处理A -> Ax的情况
        zhongjie.append(str(x + "'"))
      cheng = str(x) + " -> " + "|".join(zhongjie)
      zi = str(x) + "'" + " -> " + "|".join(feizhongjie) + "|є"
      text_output.insert('insert','直接左递归文法','tag1')
      text_output.insert('insert','\n')
      text_output.insert('insert',cheng,'tag2')
      text_output.insert('insert','\n')
      text_output.insert('insert',zi,'tag2')
    '''
    加上会判断输出非递归产生式,但会导致间接左递归不能删除多余产生式
    else:
      h ="不变: " + x + " -> " + y
      text_output.insert('insert','非左递归文法','tag1')
      text_output.insert('insert','\n')
      text_output.insert('insert',h,'tag2')
    '''
    text_output.insert('insert','\n')

def zhijie2(x,y):
  if not len(y):
    pass
  else:
    if x == y[0]:
      wenfa.discard("非左递归文法")
      #处理直接左递归
      zuobian = y.split('|')
      feizhongjie = []
      zhongjie = []
      for item in zuobian:
        if x in item:
          item = item[1:]
          textt = str(item) + str(x) + "'"
          feizhongjie.append(textt)
        else:
          text = str(item) + str(x) + "'" 
          zhongjie.append(text)
      cheng = str(x) + " -> " + "|".join(zhongjie)
      zi = str(x) + "'" + " -> " + "|".join(feizhongjie) + "|є"
      text_output.insert('insert',"间接左递归文法",'tag1')
      text_output.insert('insert','\n')
      text_output.insert('insert',cheng,'tag2')
      text_output.insert('insert','\n')
      text_output.insert('insert',zi,'tag2')

    text_output.insert('insert','\n')

def tihuan(xk,yi,yk):
  yi_you = []
  yi_wu =[]
  yi_he = ""
  yi_wuhe = ""
  yi_zhong = ""
  yi_feizhong = []
  if xk in yi:
    yk_replace = yk.split('|')
    yi_fenjie = yi.split('|')#将含非终结与不含分开
    for ba in yi_fenjie:
      if xk in ba:
        yi_you.append(ba)
      else:
        yi_wu.append(ba)

    yi_he = "|".join(yi_you)

    for item in yk_replace:
      yi_zhong = yi_he.replace(xk,item)#替换
      yi_feizhong.append(yi_zhong)
    yi_wuhe = "|".join(yi_wu)#再合并
    global zhuizhong
    zhuizhong = "|".join(yi_feizhong) + "|" + yi_wuhe

#点击按钮后执行的函数
def changeString():
  text_output.delete('1.0','end')
  text = text_input.get('1.0','end')
  text_list = list(text.split('\n'))#一行一行的拿文法
  text_list.pop()
  if not text_list[0]:
    print(tkinter.messagebox.showerror(title = '出错了!',message='输入不能为空'))
  else:
    for cfg in text_list:
      
      x,y = cfg.split('->')#将文法左右分开
      x = ''.join(x.split())#消除空格
      y = ''.join(y.split())
      if not (len(x) == 1 and x >= 'A' and x <= 'Z'):
        pos = text_input.search(x, '1.0', stopindex="end")
        result = tkinter.messagebox.showerror(title = '出错了!',
        message='非上下文无关文法!坐标%s'%(getIndex(text_input, pos),))
        # 返回值为:ok
        print(result)
        return 0
      else:
        zhijie(x,y)
      
    for i in range(len(text_list)):
      for k in range(i):
        xi,yi = text_list[i].split('->')
        xi = ''.join(xi.split())#消除空格
        yi = ''.join(yi.split())
        
        xk,yk = text_list[k].split('->')
        xk = ''.join(xk.split())#消除空格
        yk = ''.join(yk.split())

        tihuan(xk,yi,yk)
        tihuan(xk,zhuizhong,yk)
        global xi_
        xi_ = xi
    zhijie2(xi_,zhuizhong)

    for item in wenfa:
      text_output.insert('insert',item,'tag1')  

    
#创建文本输入框和按钮
text_input = tk.Text(window, width=80, height=16)
text_output = tk.Text(window, width=80, height=20)
#简单样式
ft = tf.Font(family='微软雅黑',size=12)
text_output.tag_config("tag1",background="yellow",foreground="red",font=ft)
text_output.tag_config('tag2',font = ft)
#按钮
button = tk.Button(window,text="消除左递归",command=changeString,padx=32,pady=4,bd=4)
 
text_input.pack()
text_output.pack()
button.pack()
window.mainloop()

是不是很难懂,看看半吊子流程图主要流程

python实现文法左递归的消除方法

直接左递归

python实现文法左递归的消除方法

间接左递归合并

python实现文法左递归的消除方法

运行截图

python实现文法左递归的消除方法
python实现文法左递归的消除方法

总结

(1)确定方向

做一件事并不难,最难的是没有方向,不知道要做什么;只是感觉时光流逝自己却一点东西都没产出。幸好有具体的题目可供选择,这一次我稍有纠结之后,果断选择文法左递归消除,说实话,我认为这个最简单。

(2)开始实现

首先将消除左递归的方法理解透彻,找到了程序的本质就是对字符串的操作。
完成直接左递归算法非常顺利,我思路严谨步步为营,几乎没有bug,后续测试仅仅加上一些边缘情况的判断,比如空值,让程序面对复杂产生式也游刃有余。
将间接左递归的产生式合并的算法也很顺利,因为我在草稿纸上已经勾勒好了每一步需要得到什么,写代码时,一步一个输出,看是否符合预期,后续测试稍微小补增强健壮性。真正难点在于构思思路,就连最外层两个迭代都考虑了很久。
这两个算法的逻辑和思路是很复杂的,字符串的分分合合,分别存储,使用列表和字符串数据类型不下十个,再加上几个全局变量,我对自己清晰的思路略感自豪。

(3)不足之处
1、我希望能够实现,非左递归文法,左递归和间接左递归的一起输入一起识别一起消除,碰到非左递归文法就输出“非左递归文法”,然后将其不做任何修改输出。如果实现这个,如何让间接左递归不被当做非左递归文法处理呢?我没想到解决方案。
2、我对非终结符的判断采用的是是否包含,没有更进一步判断位置,比如消除 D -> Dh|sD|h,D在s后,这就不能很好的处理。
3、对于间接左递归文法产生式的输入顺序是有要求的,还没能做到随意输入。
(4)遇到的问题
我遇到的问题都是关于整体结构和取舍妥协,比如我最终选择将输入使用两个循环,一个是对一个个产生式进行迭代,消除直接左递归,第二个再从头采用下标嵌套两层循环来合并间接左递归。
在解决不足之处1时,我花了不少时间,用尽了方法,比如全局变量,集合,甚至还将代码备份,进行较大改动,最后还是妥协了。
在写两个核心算法的时候,我每一步拿到什么数据类型,拿到什么内容,都很小心的确认,一步一步推进,没出现“bug找一天”的情况。每到一步需要一个新的变量存储,我就在方法最开始加一个,tihuan()这个方法就有六个变量,现在想来,空间复杂度挺高。
(5)总结
这次的设计完全自主,没有借鉴任何博客,我也知道可能有些我认为很难的东西在大牛面前都不值一提,或许程序整体架构就差之甚远。无论如何,题目要求的东西我做到了,而且花的时间不算长,还是挺有成就感。但是,我绝对不会骄傲,根本没有骄傲的资本。
从画出界面,接收文本输入,取到产生式,判断类型,消除直接左递归,合并间接左递归再到消除间接左递归。有条有理,一步一个脚印,方能万丈高楼平地起。

到此这篇关于python实现文法左递归的消除方法的文章就介绍到这了,更多相关python文法左递归消除内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
解读! Python在人工智能中的作用
Nov 14 Python
python如何压缩新文件到已有ZIP文件
Mar 14 Python
python opencv实现图片旋转矩形分割
Jul 26 Python
解决Mac下首次安装pycharm无project interpreter的问题
Oct 29 Python
pytz格式化北京时间多出6分钟问题的解决方法
Jun 21 Python
python把ipynb文件转换成pdf文件过程详解
Jul 09 Python
django的ORM操作 增加和查询
Jul 26 Python
python中几种自动微分库解析
Aug 29 Python
在Django中实现添加user到group并查看
Nov 18 Python
django restframework serializer 增加自定义字段操作
Jul 15 Python
详细分析Python collections工具库
Jul 16 Python
Python爬虫之App爬虫视频下载的实现
Dec 08 Python
使用Django搭建网站实现商品分页功能
May 22 #Python
Tensorflow卷积实现原理+手写python代码实现卷积教程
May 22 #Python
Python实现发票自动校核微信机器人的方法
May 22 #Python
基于django micro搭建网站实现加水印功能
May 22 #Python
基于Tensorflow一维卷积用法详解
May 22 #Python
Python参数传递机制传值和传引用原理详解
May 22 #Python
python filecmp.dircmp实现递归比对两个目录的方法
May 22 #Python
You might like
PHP伪造来源HTTP_REFERER的方法实例详解
2015/07/06 PHP
分享50个提高PHP执行效率的技巧
2015/12/26 PHP
PHP实现的分解质因数操作示例
2018/08/01 PHP
PHP Beanstalkd消息队列的安装与使用方法实例详解
2020/02/21 PHP
PHP7 参数处理机制修改
2021/03/09 PHP
点图片上一页下一页翻页效果
2008/07/09 Javascript
Jquery实现视频播放页面的关灯开灯效果
2013/05/27 Javascript
文本框回车提交与禁止提交示例
2013/09/27 Javascript
javascript 函数声明与函数表达式的区别介绍
2013/10/05 Javascript
js实现照片墙功能实例
2015/02/05 Javascript
jquery.map()方法的使用详解
2015/07/09 Javascript
jQuery实现图片左右滚动特效
2020/04/20 Javascript
JavaScript常用基础知识强化学习
2015/12/09 Javascript
jquery遍历table的tr获取td的值实现方法
2016/05/19 Javascript
jQuery stop()用法实例详解
2016/07/28 Javascript
webpack+vue.js快速入门教程
2016/10/12 Javascript
javascript基本数据类型及类型检测常用方法小结
2016/12/14 Javascript
JS之if语句对接事件动作逻辑(详解)
2017/06/28 Javascript
jQuery选择器_动力节点Java学院整理
2017/07/05 jQuery
微信小程序 授权登录详解(附完整源码)
2019/08/23 Javascript
[02:22:36]《加油!DOTA》总决赛
2014/09/19 DOTA
Python自动化测试工具Splinter简介和使用实例
2014/05/13 Python
python通过imaplib模块读取gmail里邮件的方法
2015/05/08 Python
使用K.function()调试keras操作
2020/06/17 Python
html5 的a标签 Href 拨电话的写法
2013/11/04 HTML / CSS
店长职务说明书
2014/02/04 职场文书
学校班班通实施方案
2014/06/11 职场文书
个人四风问题对照检查材料
2014/09/26 职场文书
党员民主评议自我评价
2014/10/20 职场文书
2014年信息中心工作总结
2014/12/17 职场文书
灵山大佛导游词
2015/02/04 职场文书
中标通知书
2015/04/17 职场文书
研讨会致辞
2015/07/31 职场文书
解析:创业计划书和商业计划书二者之间到底有什么区别
2019/08/14 职场文书
Win11 Beta 22621.601 和 22622.601今日发布 KB5017384修复内容汇总
2022/09/23 数码科技
Win10本地连接不见了怎么恢复? win10系统电脑本地连接不见了解决方法
2023/01/09 数码科技