转换器4:手写PHP转Python编译器,语法解析部分
写完词法部分,又有很多杂事,周末终于有空来实现伟大的语法解析部分了。
撸完代码之后发现,程序太短了,不算上状态机,才186行(含注释),关键代码不到100行。运行调试过后,发现还行。居然可以解析OneThink里面的function.php。这个文件堪称Php程序的集大成者,里面什么妖魔鬼怪都有,调试的时候真是一把辛酸泪。当然我也是不会说的,哈

有鉴于程序太短,所以我准备详细地来说说,以免大家不太明白其中奥妙:)
我们知道,语法解析一般有LL(1),LR(0),SLR(1),LALR(1),LR(1)等分析方法。比较常见的,就是LL(1),LR(0)
LL这种分析方法是从左到右扫描,最左推导;LR是从左到右扫描,最右推导;LL采用的是预测表,LR采用的是分析表;LR的难度在LL之上,分析能力也在LL之上,而且,LR的变化也更多。所以这样一个玩票的项目,当然要用LR才能稳稳地创(zhuang)新(bi)。
LR分析器的模型如下图。

包括两个栈,其中最首要地工作是生成LR分析表。当然我并不准备老老实实地按课本上的经典方法来,如何创(tou)新(lan)呢?这是关键。
我们看SLR(1),LALR(1),LR(1)都是对LR(0)的一种改进,其中最重要的就是那个(1),代表向前查看。为什么要向前看?为了减少分析表的规模。未来有无数的可能性,向前看了,可能性减少了,分析的规模也会大大减少。我们要减少分析的规模就必须向前看,而且看得越多分析表越小,而相反的编程难度也越大。那么,有没有一种方法让我站着把钱赚了,让我不向前看,难度不增加,分析表又减少呢。
有,还真有,这难不倒一个资深懒汉。我们知道,向前看的需求,来源于文法表达式:如A → Abc,它的单个表达式长度越长,不确定性越大。所以,限制方法表达式的最大长度,可以在此长度内保证100%的确定性,也就完全不需要向前看了。我把这种方法命名限长LR,即LLLR(0,n),n>=3。
如此,这次我理所当然地选择LLLR(0,3)做为分析方法,而且为了实现方便,我决定不保存状态,也就不需要生成分析表了,不生成表了,不生成表了……
妈蛋!这也太偷懒了。不保存状态,意味着每次都需要从头搜索,效率呢效率,这是程序员的生命!
稍安勿躁,表达式的最大长度为3,最多搜索3步即可,放心吧,就这么定了。:)
这就是100行超简Php编译器的奥秘,如何,够创(zhuang)新(bi)吧。源码在此:converterV0.4.zip Enjoy!
<未完待续>
转换器4:手写PHP转Python编译器,语法解析部分的更多相关文章
- 转换器3:手写PHP转Python编译器,词法部分
上周写了<ThinkPhp模板转Flask.Django模板> 一时技痒,自然而然地想搞个大家伙,把整个PHP程序转成Python.不比模板,可以用正则匹配偷懒,这次非写一个Php编译器不 ...
- 为sproto手写了一个python parser
这是sproto系列文章的第三篇,可以参考前面的<为sproto添加python绑定>.<为python-sproto添加map支持>. sproto是云风设计的序列化协议,用 ...
- 手写 Vue2 系列 之 编译器
前言 接下来就要正式进入手写 Vue2 系列了.这里不会从零开始,会基于 lyn-vue 直接进行升级,所以如果你没有阅读过 手写 Vue 系列 之 Vue1.x,请先从这篇文章开始,按照顺序进行学习 ...
- KNN手写实践:Python基于数据集整体计算以及排序
1. 距离计算,不要通过遍历每个样本来计算和指定样本距离,而是通过对于指定样本进行广播(复制)成为一个shape和全局一致后,再进行整体计算,这里的广播 / 复制采用的是tile函数来实现的: 2. ...
- 用java实现一个简易编译器-语法解析
语法和解析树: 举个例子看看,语法解析的过程.句子:“我看到刘德华唱歌”.在计算机里,怎么用程序解析它呢.从语法上看,句子的组成是由主语,动词,和谓语从句组成,主语是“我”,动词是“看见”, 谓语从句 ...
- Python学习宝典,Python400集让你成为从零基础到手写神经网络的Python大神
当您学完Python,你学到了什么? 开发网站! 或者, 基础语法要点.函数.面向对象编程.调试.IO编程.进程与线程.正则表达式... 当你学完Python,你可以干什么? 当程序员! 或者, 手写 ...
- TensorFlow下利用MNIST训练模型识别手写数字
本文将参考TensorFlow中文社区官方文档使用mnist数据集训练一个多层卷积神经网络(LeNet5网络),并利用所训练的模型识别自己手写数字. 训练MNIST数据集,并保存训练模型 # Pyth ...
- 手写 Vue2 系列 之 初始渲染
前言 上一篇文章 手写 Vue2 系列 之 编译器 中完成了从模版字符串到 render 函数的工作.当我们得到 render 函数之后,接下来就该进入到真正的挂载阶段了: 挂载 -> 实例化渲 ...
- 手写一个IOC容器
链接:https://pan.baidu.com/s/1MhKJYamBY1ejjjhz3BKoWQ 提取码:e8on 明白什么是IOC容器: IOC(Inversion of Control,控制反 ...
随机推荐
- PowerDesigner如何把建好的表导入到数据库中,并且把注释也导入进去
第一次接触这个软件,经过自己的捣鼓和百度,终于可以顺利的导入数据库中了,好开森,希望可以帮助到更多人. 数据库(mysql)其实和sqlserver差不多,以16.5版本为例 1.选中一个PDM项目, ...
- AtomicInteger相关类
引用地址:http://blog.csdn.net/xh16319/article/details/17056767 在java6以后我们不但接触到了Lock相关的锁,也接触到了很多更加乐观的原子修改 ...
- Windows 10 IoT Core环境配置中的那些坑
我使用的设备是Raspberry Pi 3B,想来国内的嵌入式玩具应该还是树莓派最常见吧.这段时间一直在捣鼓Win10 IoT,结果发现,从安装一直到编码调试一路下来全都是坑.写这篇东西一个是为了备忘 ...
- 在ubuntu linux 中编写一个自己的python脚本
在ubuntu linux 中编写一个自己的简单的bash脚本. 实现功能:终端中输入简单的命令(以pmpy为例(play music python),为了区别之前说的bash脚本添加了py后缀),来 ...
- 关于Task的一点思考和建议
前言 本打算继续写SQL Server系列,接下来应该是死锁了,但是在.NET Core项目中到处都是异步,最近在写一个爬虫用到异步,之前不是很频繁用到异步,当用到时就有点缩手缩尾,怕留下坑,还是小心 ...
- ADO.NET 扩展属性、配置文件 和 对战游戏
扩展属性 有外键关系时将信息处理成用户可看懂的 利用扩展属性 如:Info表中的民族列显示的是民族代号处理成Nation表中的民族名称 需要在Info类里面扩展一个显示nation名称的属性 例:先前 ...
- 安卓UDP通信
功能: 实现了单次一发一收: import java.net.*; import java.io.*; public class udpRecv { /* * 创建UDP传输的接收端 * 1.建立ud ...
- C++ 头文件系列(fstream)
1. 简介 该头文定义了与文件箱关联的流类的4个模版: basic_filebuf basic_ifstream basic_ofstream basic_fstream 和8个类型: filebuf ...
- 4G最快网速相当于30M宽带
[导读]据北京移动方面介绍,目前其4G网络的覆盖范围包括:东西北三环.南至两广路以内的地区:清华北大.国贸CBD及园博会等地区. 在4G年内发牌已成定局的背景下,各运营商都在加快布局,北京移动近期就推 ...
- centos 把网卡名称修改为 eth0
默认网卡名称是 eno16777736 1.修改配置文件 ifcfg-eno16777736 [root@localhost ~]# cd /etc/sysconfig/network-scripts ...