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操作json数据的一个简单例子
Apr 17 Python
跟老齐学Python之集成开发环境(IDE)
Sep 12 Python
在Python的Django框架中创建和使用模版
Jul 15 Python
Python中的集合类型知识讲解
Aug 19 Python
Python实现堆排序的方法详解
May 03 Python
基于Django filter中用contains和icontains的区别(详解)
Dec 12 Python
Python方法的延迟加载的示例代码
Dec 18 Python
Python遍历pandas数据方法总结
Feb 09 Python
将python字符串转化成长表达式的函数eval实例
May 11 Python
关于keras.layers.Conv1D的kernel_size参数使用介绍
May 22 Python
分享PyCharm最新激活码(真永久激活方法)不用每月找安装参数或最新激活码了
Dec 27 Python
python 模块导入问题汇总
Feb 01 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生成条形图的方法
2014/12/10 PHP
php实现的操作excel类详解
2016/01/15 PHP
CI框架中redis缓存相关操作文件示例代码
2016/05/17 PHP
分享PHP-pcntl 实现多进程代码
2016/09/30 PHP
Thinkphp5+plupload实现的图片上传功能示例【支持实时预览】
2019/05/08 PHP
laravel框架使用极光推送消息操作示例
2020/02/15 PHP
动态加载script文件的两种方法
2013/08/15 Javascript
javascript实现获取cookie过期时间的变通方法
2014/08/14 Javascript
javascript中setAttribute()函数使用方法及兼容性
2015/07/19 Javascript
jQuery+html5+css3实现圆角无刷新表单带输入验证功能代码
2015/08/21 Javascript
JavaScript实现上下浮动的窗口效果代码
2015/10/12 Javascript
jsp 自动编译机制详细介绍
2016/12/01 Javascript
jQuery扇形定时器插件pietimer使用方法详解
2017/07/18 jQuery
js 事件的传播机制(实例讲解)
2017/07/20 Javascript
es6在react中的应用代码解析
2017/11/08 Javascript
jquery点击回车键实现登录效果并默认焦点的方法
2018/03/09 jQuery
使用Vue.observable()进行状态管理的实例代码详解
2019/05/26 Javascript
小程序组件之自定义顶部导航实例
2019/06/12 Javascript
vue+element使用动态加载路由方式实现三级菜单页面显示的操作
2020/08/04 Javascript
Python 随机生成中文验证码的实例代码
2013/03/20 Python
Python采用raw_input读取输入值的方法
2014/08/18 Python
python中self原理实例分析
2015/04/30 Python
Python中的日期时间处理详解
2016/11/17 Python
Python requests模块实例用法
2019/02/11 Python
Python弹出输入框并获取输入值的实例
2019/06/18 Python
python安装本地whl的实例步骤
2019/10/12 Python
python 实现快速生成连续、随机字母列表
2019/11/28 Python
Python爬虫Scrapy框架CrawlSpider原理及使用案例
2020/11/20 Python
使用HTML5做个画图板的方法介绍
2013/05/03 HTML / CSS
结构工程研究生求职信
2013/10/13 职场文书
女儿十岁生日答谢词
2014/01/27 职场文书
班主任工作实习计划
2015/01/16 职场文书
公司行政主管岗位职责
2015/04/09 职场文书
个人承诺书格式范文
2015/04/29 职场文书
2015年清剿火患专项行动工作总结
2015/07/27 职场文书
Spring Boot 整合 Apache Dubbo的示例代码
2021/07/04 Java/Android