转换器3:手写PHP转Python编译器,词法部分
上周写了《ThinkPhp模板转Flask、Django模板》
一时技痒,自然而然地想搞个大家伙,把整个PHP程序转成Python。不比模板,可以用正则匹配偷懒,这次非写一个Php编译器不可。
上网搜了一下,发现大部分Python to xxx的transpile都是直接基于AST,省略了最重要的Tokenizer,Parser。直接写个Visitor了事。要不然就是基于Antlr之类的生成器,搞一大堆代码,看得令人心烦。
既然大家都不想做这个苦力,我就来试试,手工写一个Php编译器。分Tokenizer,Parser,Visitor三个部分来实现。
翻出《龙书》《虎书》做参考,仔细学了一回PHP,不学不知道,原来PHP有那么多特性,做个编译器真心累人。
词法部分很简单,就是一个自动机。设计了一个结构存放自动机,然后简单粗暴地在自动机上编程,也顾不上什么性能了,就是个一锤子买卖。
写得还算快,调试不是很顺,不过我是不会说的,哈
自动机不复杂,发上来大家看看,敬请指正。
self.statemachine = {
'current': {
'state': 'default', 'content': '', 'line': 0},
'default': [
{'name': 'open', 'next': 'php', 'extra': 0, 'start': 0, 'end': 0, 'cache': '',
'token': r'<\?'},
{'name': 'open', 'next': 'php', 'extra': 0, 'start': 0, 'end': 0, 'cache': '',
'token': r'<\?php'}],
'php': [
{'name': 'close', 'next': 'default', 'extra': 0,
'token': r'\?>', 'start': 0, 'end': 0, 'cache': ''},
{'name': 'lnum', 'next': '', 'extra': 0, 'start': 0, 'end': 0, 'cache': '',
'token': r'[0-9]+'},
{'name': 'dnum', 'next': '', 'extra': 0, 'start': 0, 'end': 0, 'cache': '',
'token': r'([0-9]*\.[0-9]+)|([0-9]+\.[0-9]*)'},
{'name': 'exponent', 'next': '', 'extra': 0, 'start': 0, 'end': 0, 'cache': '',
'token': r'(([0-9]+|([0-9]*\.[0-9]+)|([0-9]+\.[0-9]*))[eE][+-]?[0-9]+)'},
{'name': 'hnum', 'next': '', 'extra': 0, 'start': 0, 'end': 0, 'cache': '',
'token': r'0x[0-9a-fA-F]+'},
{'name': 'bnum', 'next': '', 'extra': 0, 'start': 0, 'end': 0, 'cache': '',
'token': r'0b[01]+'},
{'name': 'label', 'next': '', 'extra': 0, 'start': 0, 'end': 0, 'cache': '',
'token': r'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'},
{'name': 'comment', 'next': 'commentline', 'extra': 1,
'token': r'//', 'start': 0, 'end': 0, 'cache': ''},
{'name': 'comment', 'next': 'commentline', 'extra': 1,
'token': r'#', 'start': 0, 'end': 0, 'cache': ''},
{'name': 'comment', 'next': 'comment', 'extra': 1,
'token': r'/\*', 'start': 0, 'end': 0, 'cache': ''},
{'name': 'string', 'next': 'string1', 'extra': 1,
'token': r'\'', 'start': 0, 'end': 0, 'cache': ''},
{'name': 'string', 'next': 'string2', 'extra': 1,
'token': r'"', 'start': 0, 'end': 0, 'cache': ''},
{'name': 'symbol', 'next': '', 'extra': 0, 'start': 0, 'end': 0, 'cache': '',
'token': r'[\\\{\};:,\.\[\]\(\)\|\^&\+-/\*=%!~$<>\?@]'}],
'string1': [
{'name': 'string', 'next': 'php', 'extra': 0,
'token': r'\'', 'start': 0, 'end': 0, 'cache': ''},
{'name': 'string', 'next': 'escape1', 'extra': 1,
'token': r'\\', 'start': 0, 'end': 0, 'cache': ''},
{'name': 'string', 'next': '', 'extra': 1,
'token': r'', 'start': 0, 'end': 0, 'cache': ''}],
'escape1': [
{'name': 'string', 'next': 'string1', 'extra': 1,
'token': r'.', 'start': 0, 'end': 0, 'cache': ''}],
'string2': [
{'name': 'string', 'next': 'php', 'extra': 0,
'token': r'\'', 'start': 0, 'end': 0, 'cache': ''},
{'name': 'string', 'next': 'escape2', 'extra': 1,
'token': r'\\', 'start': 0, 'end': 0, 'cache': ''},
{'name': 'string', 'next': '', 'extra': 1,
'token': r'', 'start': 0, 'end': 0, 'cache': ''}],
'escape2': [
{'name': 'string', 'next': 'string2', 'extra': 1,
'token': r'.', 'start': 0, 'end': 0, 'cache': ''}],
'commentline': [
{'name': 'comment', 'next': 'php', 'extra': 0,
'token': r'(\r|\n|\r\n)', 'start': 0, 'end': 0, 'cache': ''},
{'name': 'comment', 'next': 'php', 'extra': 0,
'token': r'', 'start': 0, 'end': 0, 'cache': ''}],
'comment': [
{'name': 'comment', 'next': 'php', 'extra': 0,
'token': r'\*/', 'start': 0, 'end': 0, 'cache': ''},
{'name': 'comment', 'next': '', 'extra': 1,
'token': r'', 'start': 0, 'end': 0, 'cache': ''}]}
<未完待续>
转换器3:手写PHP转Python编译器,词法部分的更多相关文章
- 转换器4:手写PHP转Python编译器,语法解析部分
写完词法部分,又有很多杂事,周末终于有空来实现伟大的语法解析部分了. 撸完代码之后发现,程序太短了,不算上状态机,才186行(含注释),关键代码不到100行.运行调试过后,发现还行.居然可以解析One ...
- 为sproto手写了一个python parser
这是sproto系列文章的第三篇,可以参考前面的<为sproto添加python绑定>.<为python-sproto添加map支持>. sproto是云风设计的序列化协议,用 ...
- 手写 Vue2 系列 之 编译器
前言 接下来就要正式进入手写 Vue2 系列了.这里不会从零开始,会基于 lyn-vue 直接进行升级,所以如果你没有阅读过 手写 Vue 系列 之 Vue1.x,请先从这篇文章开始,按照顺序进行学习 ...
- KNN手写实践:Python基于数据集整体计算以及排序
1. 距离计算,不要通过遍历每个样本来计算和指定样本距离,而是通过对于指定样本进行广播(复制)成为一个shape和全局一致后,再进行整体计算,这里的广播 / 复制采用的是tile函数来实现的: 2. ...
- Python学习宝典,Python400集让你成为从零基础到手写神经网络的Python大神
当您学完Python,你学到了什么? 开发网站! 或者, 基础语法要点.函数.面向对象编程.调试.IO编程.进程与线程.正则表达式... 当你学完Python,你可以干什么? 当程序员! 或者, 手写 ...
- TensorFlow下利用MNIST训练模型识别手写数字
本文将参考TensorFlow中文社区官方文档使用mnist数据集训练一个多层卷积神经网络(LeNet5网络),并利用所训练的模型识别自己手写数字. 训练MNIST数据集,并保存训练模型 # Pyth ...
- 手写 Vue2 系列 之 初始渲染
前言 上一篇文章 手写 Vue2 系列 之 编译器 中完成了从模版字符串到 render 函数的工作.当我们得到 render 函数之后,接下来就该进入到真正的挂载阶段了: 挂载 -> 实例化渲 ...
- 使用神经网络来识别手写数字【译】(三)- 用Python代码实现
实现我们分类数字的网络 好,让我们使用随机梯度下降和 MNIST训练数据来写一个程序来学习怎样识别手写数字. 我们用Python (2.7) 来实现.只有 74 行代码!我们需要的第一个东西是 MNI ...
- 手写数字识别 ----在已经训练好的数据上根据28*28的图片获取识别概率(基于Tensorflow,Python)
通过: 手写数字识别 ----卷积神经网络模型官方案例详解(基于Tensorflow,Python) 手写数字识别 ----Softmax回归模型官方案例详解(基于Tensorflow,Pytho ...
随机推荐
- iOS NSTimer
示例: //创建 scrollTimer =[NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selecto ...
- Tamper Data 安装与使用
Tamper Data概览 注意:我将会讲述一些有关Tamper Data的基本常识,包括它的基本功能,如何安装等. Tamper Data是什么? Tamper Data 的真实含义,即&q ...
- 如何测试LBS功能
在LBS功能的开发中,为了保证通用性,服务器存在的坐标是基于wgs84的,这个通常由GPS设备传过来,对于PC来说,如何获得这个值呢?可以利用Google Earth来获得,并修改显示的坐标系统,“工 ...
- 用 NodeJS 实现 BigPipe
BigPipe 是 Facebook 开发的优化网页加载速度的技术.网上几乎没有用 node.js 实现的文章,实际上,不止于 node.js,BigPipe 用其他语言的实现在网上都很少见.以至于这 ...
- 微信小程序开发系列(二)小程序的全局文件
其实你已经知道了小程序的文件结构 上一节讲到,小程序的页面由三部分组成: 视图(.wxml).逻辑(.js).样式(.wxss). 我们这次重新展开文件结构: 小程序用到的文件类型只有四种,正如你所看 ...
- HDU2063(二分图最大匹配)
过山车 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- HDU4403(暴搜)
A very hard Aoshu problem Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & ...
- [TPYBoard-Micropython之会python就能做硬件 4] 学习使用电位器和1602显示屏
一.实验器材 1.TPYboard V102板 一块 2.电位器 一个 3.1602 屏 一块 4.杜邦线:若干 二.电位器的使用 电位器 (英文:Potentiometer)是可变电阻器的一种 ...
- Oracle DataGuard 升级 [11.2.0.1 -> 11.2.0.4]
Oracle DataGuard 升级 [11.2.0.1 -> 11.2.0.4] Primary: 11.2.0.1 单机,Site A. Standby: 11.2.0.1 单机,Site ...
- 《微信小程序七日谈》- 第七天:不要捡了芝麻丢了西瓜
<微信小程序七日谈>系列文章: 第一天:人生若只如初见: 第二天:你可能要抛弃原来的响应式开发思维: 第三天:玩转Page组件的生命周期: 第四天:页面路径最多五层?导航可以这么玩: 第五 ...