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实现字典去除重复的方法示例
Jul 31 Python
python实现数据预处理之填充缺失值的示例
Dec 22 Python
50行Python代码实现人脸检测功能
Jan 23 Python
python中的json总结
Oct 11 Python
python3.6使用pickle序列化class的方法
Oct 22 Python
使用Pandas对数据进行筛选和排序的实现
Jul 29 Python
python学生信息管理系统实现代码
Dec 17 Python
pycharm 激活码及使用方式的详细教程
May 12 Python
解决pyinstaller 打包exe文件太大,用pipenv 缩小exe的问题
Jul 13 Python
Python面向对象多态实现原理及代码实例
Sep 16 Python
利用python清除移动硬盘中的临时文件
Oct 28 Python
python3代码输出嵌套式对象实例详解
Dec 03 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
PR值查询 | PageRank 查询
2006/12/20 PHP
在php和MySql中计算时间差的方法
2011/04/22 PHP
PHP 字符串正则替换函数preg_replace使用说明
2011/07/15 PHP
PHP 处理TXT文件(打开/关闭/检查/读取)
2013/05/13 PHP
推荐25款php中非常有用的类库
2014/09/29 PHP
PHP易混淆函数的区别及用法汇总
2014/11/22 PHP
PHP实现生成模糊图片的方法示例
2017/12/21 PHP
PHP微信支付结果通知与回调策略分析
2019/01/10 PHP
java script编程起步(第三课)
2007/01/10 Javascript
Javascript YUI 读码日记之 YAHOO.util.Dom - Part.3
2008/03/22 Javascript
jQuery asp.net 用json格式返回自定义对象
2010/04/07 Javascript
jQuery学习笔记 获取jQuery对象
2012/09/19 Javascript
jquery 事件冒泡的介绍以及如何阻止事件冒泡
2012/12/25 Javascript
jquery中获取元素里某一特定子元素的代码
2014/12/02 Javascript
JS实现可自定义大小,可双击关闭的弹出层效果
2015/10/16 Javascript
jquery判断复选框是否被选中的方法
2015/10/16 Javascript
jQuery制作网页版选项卡
2016/07/28 Javascript
给easyui datebox扩展一个清空的实例
2016/11/09 Javascript
jquery获取input type=text中的值的各种方式(总结)
2016/12/02 Javascript
js实现百度搜索提示框
2017/02/05 Javascript
vue-resource 拦截器使用详解
2017/02/21 Javascript
jQuery实现百度登录框的动态切换效果
2017/04/21 jQuery
Vue如何实现响应式系统
2018/07/11 Javascript
如何在JavaScript中等分数组的实现
2020/12/13 Javascript
python3图片转换二进制存入mysql
2013/12/06 Python
用Python实现一个简单的线程池
2015/04/07 Python
探究python中open函数的使用
2016/03/01 Python
dataframe设置两个条件取值的实例
2018/04/12 Python
pyqt5 实现多窗口跳转的方法
2019/06/19 Python
nginx黑名单和django限速,最简单的防恶意请求方法分享
2019/08/09 Python
Python计算两个矩形重合面积代码实例
2019/09/16 Python
美术指导求职信
2014/03/17 职场文书
读书之星事迹材料
2014/05/12 职场文书
会议欢迎标语
2014/06/30 职场文书
我们的节日国庆活动方案
2014/08/19 职场文书
win10重装系统后上不了网怎么办 win10重装系统网络故障的解决办法
2022/07/23 数码科技