上周写了《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': ''}]}

源码:converterV0.3.zip

<未完待续>

转换器3:手写PHP转Python编译器,词法部分的更多相关文章

  1. 转换器4:手写PHP转Python编译器,语法解析部分

    写完词法部分,又有很多杂事,周末终于有空来实现伟大的语法解析部分了. 撸完代码之后发现,程序太短了,不算上状态机,才186行(含注释),关键代码不到100行.运行调试过后,发现还行.居然可以解析One ...

  2. 为sproto手写了一个python parser

    这是sproto系列文章的第三篇,可以参考前面的<为sproto添加python绑定>.<为python-sproto添加map支持>. sproto是云风设计的序列化协议,用 ...

  3. 手写 Vue2 系列 之 编译器

    前言 接下来就要正式进入手写 Vue2 系列了.这里不会从零开始,会基于 lyn-vue 直接进行升级,所以如果你没有阅读过 手写 Vue 系列 之 Vue1.x,请先从这篇文章开始,按照顺序进行学习 ...

  4. KNN手写实践:Python基于数据集整体计算以及排序

    1. 距离计算,不要通过遍历每个样本来计算和指定样本距离,而是通过对于指定样本进行广播(复制)成为一个shape和全局一致后,再进行整体计算,这里的广播 / 复制采用的是tile函数来实现的: 2. ...

  5. Python学习宝典,Python400集让你成为从零基础到手写神经网络的Python大神

    当您学完Python,你学到了什么? 开发网站! 或者, 基础语法要点.函数.面向对象编程.调试.IO编程.进程与线程.正则表达式... 当你学完Python,你可以干什么? 当程序员! 或者, 手写 ...

  6. TensorFlow下利用MNIST训练模型识别手写数字

    本文将参考TensorFlow中文社区官方文档使用mnist数据集训练一个多层卷积神经网络(LeNet5网络),并利用所训练的模型识别自己手写数字. 训练MNIST数据集,并保存训练模型 # Pyth ...

  7. 手写 Vue2 系列 之 初始渲染

    前言 上一篇文章 手写 Vue2 系列 之 编译器 中完成了从模版字符串到 render 函数的工作.当我们得到 render 函数之后,接下来就该进入到真正的挂载阶段了: 挂载 -> 实例化渲 ...

  8. 使用神经网络来识别手写数字【译】(三)- 用Python代码实现

    实现我们分类数字的网络 好,让我们使用随机梯度下降和 MNIST训练数据来写一个程序来学习怎样识别手写数字. 我们用Python (2.7) 来实现.只有 74 行代码!我们需要的第一个东西是 MNI ...

  9. 手写数字识别 ----在已经训练好的数据上根据28*28的图片获取识别概率(基于Tensorflow,Python)

    通过: 手写数字识别  ----卷积神经网络模型官方案例详解(基于Tensorflow,Python) 手写数字识别  ----Softmax回归模型官方案例详解(基于Tensorflow,Pytho ...

随机推荐

  1. Unity游戏开发——自动为动画剪辑添加事件 之 最后几帧的事件不能被调用的问题

    最近在做一个根据配置表自动生成动画剪辑clip以及controller的功能.做法是根据配置表配置的动作以及每个动作的关键帧,自动为每个clip添加事件.这样做可以把动画的事件处理在游戏运行之前就计算 ...

  2. Mac 安装Rudy环境 pod安装前的准备工作

    之前已经说过怎么使用pod 今天说一下安装pod之前的准备工作 首先呢就是Rudy 环境(前提是你已经安装了Xcode) 在终端输入一下命令 期间可能也许会要你输入密码 curl -L https:/ ...

  3. Spark SQL原理及实战

    一.Spark SQL的发展 1.spark SQL和shark SparkSQL的前身是Shark,给熟悉RDBMS但又不理解MapReduce的技术人员提供快速上手的工具,Hive应运而生,它是当 ...

  4. cssText 和 this

    一.cssText 元素.style.width = '200px';   ==>   元素.style.cssText = 'width:200px;height:200px;' 二.this ...

  5. repeater控件自定义Url分页带参数

    repeater控件的效果图如下: 该页面实现的功能如下: 1.上下分页,(也可以带首页和末页,我只是禁掉了没用) 2.根据用户输入的指定分页索引进行跳转 3.根据筛选数据的参数进行URL分页的参数传 ...

  6. 本地ssh连接到vbox中的linux

    本机是window xp系统, 安装vbox,在vbox下安装linux,想在xp中用ssh连接linux,此时需要配置网络. 1.设置vbox的网络,选择host-only 2.设置window虚拟 ...

  7. 一个基于node 的小demo

    首先我们新建一个文件夹  demo-test-node-1 目录目录如下 -- blog_recents.js --template.html --titles.jspn 首先我们新建一个 templ ...

  8. TFS2010升级至TFS2013完全指南

    一.背景:         公司已使用tfs2010很长时间,目前随着公司的发展,项目越来越少,而产品越来越多,采用的开发模式,也逐渐从瀑布式.迭代式转向敏捷开发.为了更好的支持产品研发,决定将tfs ...

  9. SOCKET是什么

    一.问题的引入--socket的引入是为了解决不同计算机间进程间通信的问题 1.socket与进程的关系 1).socket与进程间的关系:socket   用来让一个进程和其他的进程互通信息(IPC ...

  10. UI进阶 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天

    这篇博客的代码是直接在上篇博客的基础上增加的,先给出部分代码,最后会给出能实现简单功能的完整代码. UI进阶 即时通讯之XMPP登录.注册 1.好友列表 初始化好友花名册 #pragma mark - ...