笔者曾写过一篇《我眼中的C措辞及其起源》(在其他地方叫《C措辞发展史的点点滴滴》)的文章,文中从历史角度结合Unix系统源码来追溯了C措辞的起源以及发展史(C措辞的伟大毋庸置疑,但是其他措辞带来的多样化也是十分主要),至于文章内容这里就不做过多赘述,感兴趣的读者可以查看原文。
本文则缘起于,在头条转载的本文评论中一位读者提到的一句话:"国产易措辞在角落瑟瑟颤动"。看到这句话之后,顿时就对中文编程措辞的事理产生了兴趣。由于平时业务开拓过程中利用的紧张措辞是PHP/Golang,以是就从某种角度出发,并结合PHP、编译事理来剖析一下中文编程措辞的某些相似性事理。如果感兴趣的话,可以跟随笔者的步伐一探究竟。
如果说,给中文编程措辞下一个定义的话:那便是,如其字面义,中文编程措辞便是用中文汉字去编写代码逻辑,这些代码在经由编译处理之后,能够在当代打算机系统上跑起来的编程措辞。

查了一下维基百科理解到:目前,中文编程措辞大概有下面几种:
https://zh.wikipedia.org/wiki/%E4%B8%AD%E6%96%87%E7%B7%A8%E7%A8%8B%E8%AA%9E%E8%A8%80
•BCY措辞(1964年)
•朱邦复 曾设计过一些中文措辞,如中文培基与中文cobol(1980年代)
•伙计培基(1987年)
•易措辞(2000年)
•丙正正 C++措辞的中文版本(2000年代 2001)
•唐凤 曾经设计过能以文言文写作的perl模块PerlYuYan(2002年)
•中蟒(2002年)
•O措辞 中文汇编措辞(2005年)
•ZhPy(周蟒,2007年)
•习措辞 支持中文的C措辞(2009年)
•中文小海龟 中文化的Logo措辞(2009年)
•蝉语(2014年)
•wenyan-lang 类文言文的编程措辞(2020年)
对付中文编程措辞,笔者也说不好其意义与代价。只是想说一句话:凡存在即合理。这个天下,也正是由于原谅性,才有了本日的多彩多姿。(维基百科里面有这么一句话:利用中文编程措辞,不须要记住大量的英文语句,中文用户可以在自己母语的根本上从更高方面入手。而且可以减少学习英语的本钱,为汉语区的软件家当发展供应帮助。 间接的解释了其存在的意义)。
1.2 中文代码demo[ 中文编写的示例代码 ]
上面程序实行结果为:这里是如果。
看到这里,你可能认为这段代码是利用上面的某种中文编程措辞编写的。当然,干系中文编程措辞也是可以实现该功能。但是,如果我见告你,这是段PHP/Go代码的话,你会做何感想。
实行代码的PHP/Go程序用官方源码编译
代码是标准的PHP/Go格式代码
[ PHP实行示例代码 ]
[ Go实行示例代码 ]
是不是有种不可思议的觉得?是的话,那就对了。由于,这最少解释一个道理:大多数时候,你从主不雅观角度看到的事实,每每不一定是其真实的写照。
你可能会产生下面迷惑:
1.PHP/Go怎么可能利用中文编写代码?
2.这个跟中文编程措辞有什么关系?
如果你想到这两个问题的话,那我的目的也就达到了,详细缘故原由且往下看。
2. 编程措辞分类从某种角度来看编程措辞,大概分为以下几种类型:
1.编译型措辞(C、C++、golang ......)
大致实行流程:源代码->汇编代码->机器码->CPU实行
2.阐明型措辞(Python、JavaScript、PHP ......)
大致实行流程:源代码->中间代码->虚拟机->CPU实行
3.翻译 + 解析型措辞(Java、C# ......)
大致实行流程:源代码->中间代码->虚拟机->机器码->CPU实行
首先,须要解释的是:上面几种分类包含的措辞,都是属于自然措辞的范畴。其次,打算机终极实行的,都是由01组成的机器措辞。
不知道,你有没有跟笔者一样想过这样一个问题:这些自然措辞终极是怎么在打算机上跑起来的?
2.1 编译器编译器(compiler)是一种打算机程序,它会将某种编程措辞写成的源代码(原始措辞)转换成另一种编程措辞(目标措辞)。
https://zh.wikipedia.org/wiki/%E7%B7%A8%E8%AD%AF%E5%99%A8
它紧张的目的是将便于人编写、阅读、掩护的高等打算机措辞所写作的源代码程序,翻译为打算性能解读、运行的低阶机器措辞的程序,也便是可实行文件。编译器将原始程序(source program)作为输入,翻译产生利用目标措辞(target language)的等价程序。源代码一样平常为高等措辞(High-level language),如Pascal、C、C++、C# 、Java等,而目标措辞则是汇编措辞或目标机器的目标代码(Object code),有时也称作机器代码(Machine code)。
一个当代编译器的紧张事情流程如下:源代码(source code)→ 预处理器(preprocessor)→ 编译器(compiler)→ 汇编程序(assembler)→ 目标代码(object code)→ 链接器(linker)→ 可实行文件(executables),末了打包好的文件就可以给打算机去运行了。
[ 当代编译器的紧张事情流程 ]
2.2 编译过程编译器一样平常分为:前端和后端。
编译器的前端一样平常承担着词法剖析、语法剖析、类型检讨和中间代码天生几部分事情(该部分也是设计一门新的编程措辞,须要重点关注的部分。同时,也是各种编程措辞差异化最大的部分)。而编译器后端紧张卖力目标代码的天生和优化,也便是将中间代码翻译成目标机器能够运行的机器码。
对应步骤所起到的浸染为:
•词法剖析 通过词法剖析器识别出最小的语法单位,并用对应token表示其词性。(源程序字符串 → 单词符号)
•语法剖析 通过语法剖析器根据单词词性,剖析语法。(单词符号 → 语法单位)
•语义剖析与中间代码天生 根据单词值剖析语义是否精确,天生中间代码。(语法单位 → 中间代码)
•代码优化 对中间代码进行优化,以期产生更高效的目标代码。(中间代码 → 优化后的中间代码)
•目标代码天生 将中间代码转换成低级措辞代码。(中间代码 → 目标代码)
各种措辞都有上述步骤,底层的实现也基本相似。
3. PHP词法剖析笔者这里利用PHP措辞,来一步步剖析实在现中文编程代码的事理。
3.1 PHP实行过程从编程措辞分类来看,PHP属于阐明型措辞,对付阐明型措辞来说,都会有一个阐明器(php的阐明器为zend引擎,zend这个词汇来源于最初两位核心开拓者的名字组合的单词,后来成立了zend公司)。PHP源码的实行过程,大概分为下面几个步骤:
1.词法剖析 (此处是本文重点)2.语法剖析3.天生抽象语法树AST4.天生中间码opcode5.zend引擎实行opcode
[ PHP源码实行过程 ]
opcode在笔者看来是有点类似于汇编码的中间码,不过这里的中间码是被zend引擎实行的。
[ opcode构造 ]
为什么说,类似于汇编码呢?通过上面构造体可以看到几个关键字段:
操作数:op1、op2
返回值:result
操作数类型:op1_type、op2_type
返回值类型:result_type
操作动作:handler指针指向详细的操作动作处理方法
3.2 PHP中间代码与C汇编下面分别利用阐明型措辞PHP、编译型措辞C来实现相同的加法功能,并查看个中央码(下图显示的是简化之后的中间码),进行比拟剖析。
[ 实现加法功能的PHP源码与中间码opcode ]
这里获取PHP中间码opcode(可以结合3.2中zend_op构造体来剖析),利用的是vld扩展。
这里获取C的中间码汇编,利用的是objdump命令。
通过比拟可以创造,PHP的中间码与C措辞的中间码具有某种相似性。
例如,实现a+b的操作:
// 汇编add %edx,%eax// opcodeADD ~4 !0, !1
1.都有对应的操作指令
2.都有两个操作数
3.都有存储结果的位置
看到这里,是不是觉得创造了什么不得了的东西。
阐明型措辞的虚拟机,对应着的是编译型措辞更底层实行逻辑的抽象。阐明型措辞的中间码,对应着的是编译型措辞中间码的抽象。
各种措辞的实现办法可能不太一样,但是实现事理是类似的。有些比较也可能看似有点牵强,但是采取这种办法却更随意马虎理解。
3.3 自定义词法规则笔者本次所用php源码版本为 php-7.4.10。
词法剖析规则文件:php-7.4.10/Zend/zend_language_scanner.l
[ PHP原生词法规则 ]
[ 原生词法规则与token的映射 ]
为了实现1.2示例中的代码,添加了几个自定义了词法规则。
[ 添加自定义词法规则 ]
[ 添加的自定义词法规则与token的映射 ]
词法剖析器碰着一个词汇,就去查询一本词典(词法规则)。如果查到了该词汇的话,则会得到一个合规的token,接下来把token通报给语法剖析器进行后续处理。
在这里,笔者只是在词法剖析器的词典中多添加了几个条款,把新增的几个条款映射到原有的合法token上去,也正是这几个条款使得1.2处代码可以精确的实行(虽然是中文编写的,但是词法剖析器可以精确的识别其含义)。
3.4 自定义词法验证俗话说,无图无原形。下面来验证自定义的词法所产生的token是否是预期的。
[ 获取1.2示例代码的token ]
[ 1.2示例代码对应的token ]
从获取的token序列中可以看到,添加的词法规则被识别成了精确的对应token:
'如果' -> T_IF
'否则' -> T_ELSE
'输出' -> T_ECHO
也正是这一步操作,使得1.2示例中的中文代码demo可以被PHP程序精确实行。
4. 添加自定义词法规则步骤这里详细记录一下,笔者添加自定义词法规则以及编译的过程。
1.编译安装re2c
re2c官网以及github仓库
http://re2c.org/ https://github.com/skvadrik/re2c
安装过程自行百度、Google,我这里利用的是 re2c 1.3。
2.下载并解压缩PHP官方源码
这里利用的版本是 7.4.10
https://www.php.net/distributions/php-7.4.10.tar.gz
3.添加自定义词法规则 编辑php-7.4.10/Zend/zend_language_scanner.l文件,添加下面代码。
<ST_IN_SCRIPTING>"如果" { RETURN_TOKEN(T_IF);}<ST_IN_SCRIPTING>"否则" { RETURN_TOKEN(T_ELSE);}<ST_IN_SCRIPTING>"输出" { RETURN_TOKEN(T_ECHO);}
4.利用re2c重新天生最新的词法剖析器代码
/usr/local/re2c/bin/re2c--no-generation-date--case-inverted-cbdF-ozend_language_scanner.czend_language_scanner.l
5.编译安装PHP程序 回到PHP源码根目录,编译安装PHP。这里笔者只是为了大略的测试利用,没有添加、开启其他选项。
./configure --prefix=/usr/local/php7.4makemake install
到这里,恭喜你不仅已经拥有了一个跟笔者一样的,可以实行中文编写的1.2示例代码的PHP程序。而且,还可以基于PHP,来自定义一个属于自己的中文编程规范。
5. 中文编程措辞的思考从编程措辞的分类角度来看,想要开拓一种新的中文编程措辞。一样平常须要考虑下面几件事情:
1.措辞是编译型还是阐明型2.如何定义措辞词法规则3.如何定义措辞语法规则4.什么样的中间码5.中间码天生机器码还是运行在虚拟机上
5.1 设计中文编程措辞的思路一样平常有两种选择:
I. 想要减小底层设计的繁芜度,重点关注上层措辞层面特性。一样平常是利用其他措辞来构建当前措辞,利用虚拟机来实行特定格式的中间码。例如:PHP利用C措辞来编写底层内核逻辑,PHP源码天生的中间码opencode,运行在zend虚拟机之上。
II. 不依赖于其他措辞,从底层到上层全部重新设计。最关键的是,要有一个支持该措辞的编译器,能够直接将该措辞编译成某种中间码或者机器码。例如:Golang措辞(go措辞前期几个版本利用C措辞编写底层逻辑。后面实现了自举,底层除了少数文件利用汇编,其他全部利用go措辞编写)。
貌似还有第三种选择:那便是跟笔者上面的例子一样,利用某种编程措辞,仅仅是修正一下其词法规则,让其支持中文编程。(这种方法相称于穿了个新的马甲,不能称之为新的编程措辞,称之为汉化更得当。当然,很多时候也是让人嗤之以鼻的。不禁让笔者想起来了多少年前,关于国产CPU的一件事情:买一颗其他厂商的CPU,打磨掉旧的logo,换个新的logo。总之,前路漫漫,道阻且长。还是希望海内高手们能同心协力,发明一款国人亲手打造的、被广泛利用的编程措辞)。
从目前的情形来看,大部分的中文编程措辞采取的是第一种实现方法。但是,也不用除部分采取第二种方法,当然该方法对开拓职员来说也是难度最大的一种。
这里想要着重解释一点:中文编程不是大略的编程关键字更换为中文,而是中文编程时所利用关键字的底层API调用、类库支持、系统交互等一系列的设计。
5.2 中文编程的意义及未来正所谓,仁者见仁智者见智。至于中文编程的意义以及未来,笔者也搜索了一些文章,或支持、或反对,每个人有自己的独特见地。感兴趣的话读者可以搜索干系资料。
如果,你问我:你相信中文编程会有未来吗?
那么,我可能会说:我永久相信美好的事情,一定会发生。
这里抛出一个笔者个人的不雅观点(不引战,杠精绕道):中文编程对国人来说也是另一种选择,打消那些专业的开拓职员。最少,对那些不懂编程的爱好者或者低龄儿童来说,只要轻微熟习一些逻辑,也能编写出一些精良的软件。又何乐而不为呢?
当然,想要搞出一款纯粹的中文编程措辞也会是有一定难度。从打算机体系构造来看,打消高层次的编程措辞层面来看,底层的操作系统、指令集也牵扯巨量工程。如果,非要集国人之力搞出这么一套也不是不可能,只是从本钱角度来看,投入跟产出比不会太大。当前,天下正在成为一个地球村落。各种文化的领悟交汇,也匆匆使着时期滚滚向前的进程,很多新事物每每也是顺应着时期潮流,在各个行业浩瀚的顶尖人才参与下才得以涌现。我们也该当顺应时期潮流,参与进去,增加影响力、参与标准化的制订,这才是一个明智的选择。同时,也该当掌控一些核心科技才是王道。
末了,最主要的一点便是:生态。编程措辞只是个工具,有了工具(哪怕是非常好用的工具)也须要有人、有很多人来用,才能更表示其代价(有句古话:酒喷鼻香也怕巷子深)。有很多人用,自然会环绕该措辞构建出一些精良的软件、系统。每每也牵扯很多行业的支持,全体就构成了一个生态。没有很好的生态,是很难存活下去的(历史上不乏有很多例子)。
6. 总结本文以自定义词法规则来实现PHP的中文编程为例,引入编程措辞的词法剖析步骤。同时,通过简述编译器的实行过程,引出设计一种编程措辞所该当具有的一些思路与逻辑。这里,也仅仅是抛砖引玉。
这天下上唯一不变的,便是变革。编程措辞排行榜之上,各种措辞浮浮沉沉,涌现、消亡,都是时期所使令的结果。但是,有一点是具有共通性的,那便是实现事理。想必,节制了这一点,也就基本节制了大部分的不变。
鉴于个人能力有限,如有问题或者毛病,欢迎示正。
7. 参考资料及扩展阅读[1]https://juejin.im/post/6867124787576373256 聊一聊编译过程
[2]https://zh.wikipedia.org/wiki/%E7%B7%A8%E8%AD%AF%E5%99%A8
[3]http://www.ruanyifeng.com/blog/2014/11/compiler.html 编译器的事情过程
[4]https://zhuanlan.zhihu.com/p/53336801 大家都能读懂的编译器事理
[5]https://zhuanlan.zhihu.com/p/64768035 编译事理:语法剖析器的设计和实现
[6]https://draveness.me/golang/docs/part1-prerequisite/ch02-compile/golang-compile-intro/ go编译事理
[7]https://www.cnblogs.com/OceanEyes/p/implement_a_interpreter.html 从编译事理看一个阐明器的实现