D. 高级语言怎么来的
本文关键词:高级语言,由笔耕文化传播整理发布。
作者:徐宥
原文:
我主要想八卦一下高级语言的设计思想和各种范式的来龙去脉编程语言为什么会发生成现在这个样子哩包括虚拟机的设计栈和寄存器两大流派的来龙去脉等等, 也算是完成年初给大家许下的诺言. 仅电路与连线天地开, 始有FORTRAN, LISP. ALGOL是基于递归函数的现在的都比较像不像可是很少有人知道, 最初, FORTRAN所有高级语言里面的递归调用那里学来的值得八卦一番. 之外不是阶乘就是菲波拉契数列基本上都是因为函数的递归调用才显得简单漂亮人民非常想念您第一版的就居然居然不支持递归不支持递归的语言能图灵完全么但是没递归调用的程序会很难写那么, FORTRAN年. 至于计算能力嘛, 却比你的手机还弱. 那时候计算机所做的最多的事情, 不是发邮件打游戏, 而是作计算. 作计算嘛, 自然需要一种和数学语言比较接近的编程语言. 于是, 1960年, IBM 就捣鼓出了用行话说 用现在的眼光看所以数学公式加上一个数组, 基本上就能完成所有的科学计算了. IBM 语言规范, 并且在自家的大型机上实现了这个语言. 编译器那时候的编译器都是用机器语言或者很低级的汇编语言写成的这些工程师觉得因为在科学计算中用到的变量等就是可以知道大小的也就相当于没有的或者没有++一个程序要多少内存这个主意看上去很聪明的工程师比你想得更加聪明既然一个程序或者子程序要多少内存在编译的时候都知道了子程序中参数大小都定好是的在没有操作系统管理的情况下如果内存放的整整齐齐的这样也是一件非常好的事情. (再次强调操作系统要等到才有人月神话>). 这样静态的搞内存分配为啥呢我有个函数个菲波拉契数返回一个整数, FORTRAN我运行起来存在某个专门给输入参数的位置里面递归的调用了Fib(4), FORTRAN不还是么我存新的参数给覆盖掉了也把原来的返回值给覆盖掉了这么一搞这下了怎么递归啊? 不是不知道这个问题你丫科学计算递归什么呀展不开是你数学没学好你就不要用那时候乃是老大老大发话, 下面的消费者只能听他的. 所以就压根没有任何栈支持计算机发展史上我们现在也很难猜测的软件工程师因为的硬件工程师没有在硬件上设计出堆栈所以没有能在里面设计出递归调用呢的硬件工程师觉得既然软件没要求不管怎么样, 我们看到的是, 1960熟悉里面一个叫做用来标记下一条要执行的指令的位置如果没有后者因为需要程序员手工维护一个栈而当年压根就不支持递归的硬件如果一个程序员想要递归调用就是让程序员借用一个通用寄存器作为栈指针而且不能用 FORTRAN. 按照自然规律于是, 很快的, LISP这两个新语言就出道了它的创始人是 是学院派人物演算所以, LISP因为递归就是 但是有两大问题摆在 一是他的二是他的 的指令而这个按照 Paul Graham里面的说法指令的一个叫 Steve Russell的工程师宣称要实现的时候实际是实际可是, Russell叫 就是写了一个解释器在这个解释器里面跑让传统上编译-> 运行 的高级语言流程解释执行的流程流程相当于在用来解释所有的 这个创举从理论走到了实践. 就可以怎么递归上面我也说了写有了解释器因为现在所有的空间分配都可以由解释器管理了运行时环境允许你动态的分配空间随之就带来了一项新技术这个技术出现在 是解释器的自然要求和归宿上本来被绕过的问题里面用全新的方法被解决了. LISP比如抽象语法树垃圾收集都很早的出现在了加上本身规则很少所以特别是和解释器和运行时相关的一项新技术出现“这玩意儿里早就有了”是有一定道理的. 这一派为日后所有虚拟机理论铺开了一条新路. 这一派在70, 80年代迅速崛起的兴起又迅速的陨落, 让人唏嘘不已. 高级语言编程领域也发生了一件大事的提出. ALGOL全是 注意到了 于是从一开始但是, 处理递归需要很小心的安排每个函数每次调用的地址和所谓的活动窗口(Active Frame),难免会出点小问题和小这时候出场了叫做 “是男人就得负不能给各位读者把这个男人测试的关窍讲清楚我知道乃是看 ALGOL 60真的男人要能得到正确答案当然所以自己猜了一个后来正确答案是可见也不是男人编译器…虚拟机的前世今生
因为的原因, 发展出了运行时环境这样一个概念。基于这个概念,日后发展出了虚拟机技术。但这段历史并不是平铺直叙的,实际上,这里面还经历了一个非常漫长而曲折的过 程, 说起来也是非常有意思的。 这一节我们就着重解释虚拟机的历史。
我们世纪的程序员,凡要是懂一点编程技术的,基本上都知道虚拟机和字节码这样两个重要的概念。 所谓的字节码 (bytecode), 是一种非常类似于机器码的指令格式。这种指令格式是以二进制字节为单位定义的(不会有一个指令只用到一个字节的前四位),所以叫做字节码。所谓的虚拟机, 就是说不是一台真的计算机,而是一个环境,其他程序能在这个环境中运行,而不是在真的机器上运行。现在主流高级语言如 Java, Python, PHP, C#,编译后的代码都是以字节码的形式存在的, 这些字节码程序, 最后都是在虚拟机上运行的。
1. 虚拟机的安全性和跨平台性
虚拟机的好处大家都知道,最容易想到的是安全性和跨平台性。安全性是因为现在可执行程序被放在虚拟机环境中运行,虚拟机可以随时对程序的危险行为, 比如缓冲区溢出,数组访问过界等等进行控制。跨平台性是因为只要不同平台上都装上了支持同一个字节码标准的虚拟机,程序就可以在不同的平台上不加修改而运 行,因为虚拟机架构在各种不同的平台之上,用虚拟机把下层平台间的差异性给抹平了。我们最熟悉的例子就是了。Java 语言号称 一次编写,到处运行(Write Once, Run Anywhere),就是因为各个平台上的虚拟机都统一支持字节码,所以用户感觉不到虚拟机下层平台的差异。
虚拟机是个好东西,但是它的出现,不是完全由安全性和跨平台性驱使的。
2. 跨平台需求的出现
我们知道,在计算机还是锁在机房里面的昂贵的庞然大物的时候,系统软件都是硬件厂商附送的东西(是比尔盖茨这一代人的出现,才有了和硬件产业分庭抗礼的软件产业), 一个系统程序员可能一辈子只和一个产品线的计算机打交道,压根没有跨平台的需求。应用程序员更加不要说了,因为计算机很稀有,写程序都是为某一台计算机专 门写的,所以一段时间可能只和一台庞然大物打交道,更加不要说什么跨平台了。 真的有跨平台需求,是从微型计算机开始真的普及开始的。因为只有计算机普及了,各种平台都被广泛采用了,相互又不互相兼容软件,才会有软件跨平台的需求。 微机普及的历史,比普及的历史要早发展史是并行重叠的。
熟悉发展史的读者都知道,真正普及开来,是因为其全部都用版本的出生没多久,就迅速从原始的实现,移植到了等平台上,产生了无数衍生版本。随着跨平台的的普及, 微型计算机也更多的普及开来,因为只需要掌握基本的知识,就可以顺利操作微型计算机了。所以,微机和这两样东西都在年在美国政府,大学,科研机构,公司,金融机构等各种信息化前沿部门间真正的普及开来了。这些历史都是人所共知耳熟能详的。
既然是跨平台的,那么,本节所有的故事都和无关,因为本身就不是一个跨平台的操作系统)。的跨平台性,一般是以各平台厂商提供编译器的方式实现的,而最终编译生成的可执行程序,其实不是跨平台的。所以,跨平台是源代码级别的跨平台,而不是可执行程序层面的。 而除了标准了语言外,UNIX 上有一派生机勃勃的跨平台语言,就是脚本语言。(注:脚本语言和普通的编程语言相比,在能完成的任务上并没有什么的巨大差异。脚本语言往往是针对特定类型的问题提出的,,语法更加简单,功能更加高层,常常几百行C语言要做的事情,几行简单的脚本就能完成)
3. 解释和执行
脚本语言美妙的地方在于,它们的源代码本身就是可执行程序,所以在两个层面上都是跨平台的。不难看出,脚本语言既要能被直接执行,又要跨平台的话,就必然要有一个“东西”,横亘在语言源代码和平台之间,往上,在源代码层面,分析源代码的语法,结构和逻辑,也就是所谓的“解释”;往下,要隐藏平台差异,使得源代码中的逻辑,能在具体的平台上以正确的方式执行,也就是所谓的“执行”。
虽说我们知道一定要这么一个东西,能够对上和两个模块毕竟是相互独立的,因此就很自然的会出现两个流派:把解释和执行设计到一起 和 把解释和执行单独分开来 这样两个设计思路,需要读者注意的是,现在这两个都是跨平台的,安全的设计,而在后者中字节码作为了解释和执行之间的沟通桥梁,前者并没有字节码作为桥梁。
4. 解释和执行在一起的方案
我们先说前者,前者的优点是设计简单,不需要搞什么字节码规范,所以上早期的脚本语言,都是采用前者的设计方法。 我们以上大名鼎鼎的和两个脚本语言的解释器为例说明。和都是上极为常用的,图灵完全的语言,其中在任何系统中都是作为标准配置的,甚至入选 IEEE POSIX卢浮宫的唯一同类语言品牌,其地位绝对不是下其他脚本语言能够比的。这两个语言是怎么实现解释和运行的呢? 我从的标准实现中摘一段代码您一看就清楚了:
argv[]) { ... syminit(); yyparse(); ... run(winner); } ... }其中, run 的原型是
run(Node *a) /* execution of parse tree starts here */
而 winner 的定义是:
Node *winner ; /* root of parse tree */
熟悉的读者应该能够立即看出解析源代码,生成了一棵语法树。按照 winner 的定义, winner 是这棵语法树的根节点。 在变成了 0),将 run 作用到这棵语法树的根节点上。 不难想像,这个的基本逻辑先用解释器(这里解释器),生成一棵语法树,然后,从树的根节点开始,往下用这个函数,遇山开山,遇水搭桥,一路递归下去,最后把整个语法树遍历完,程序就执行完毕了。(这里附送一个小八卦,抽象语法树这个概念是先提出的,因为是最早像这样做的,的源代码也是类似的逻辑解释执行的,我就不一一举例了。
5. 三大缺点
现在我们看看这个方法的优缺点。 优点是显而易见的,因为通过抽象语法树在两个模块之间通信,避免了设计复杂的字节码规范,设计简单。但是缺点也非常明显。最核心的缺点就是性能差,需要资源多,具体来说,就是如下三个缺点。
缺点1,因为解释和运行放在了一起,每次运行都需要经过解释这个过程。假如我们有一个脚本,写好了就不修改了,只需要重复的运行,那么在一般应用下尚可以忍受每次零点几秒的重复冗余的解释过程,在高性能的场合就不能适用了。
缺点2,因为运行是采用递归的方式的,效率会比较低。 我们都知道,因为递归涉及到栈操作和状态保存和恢复等,代价通常比较高,所以能不用递归就不用递归。在高性能的场合使用递归去执行语法树,不值得。
缺点3,因为一切程序的起点都是源代码,而抽象语法树不能作为通用的结构在机器之间互传,所以不得不在所有的机器上都布置一个解释+运行的模块。 在资源充裕的系统上布置一个这样的系统没什么,可在资源受限的系统上就要慎重了,比如嵌入式系统上。 鉴于有些语言本身语法结构复杂,布置一个解释模块的代价是非常高昂的。本来一个递归执行模块就很吃资源了,再加一个解释器,嵌入式系统就没法做了。所以, 这种设计在嵌入式系统上是行不通的。
当然,还有一些其他的小缺点,比如有程序员不喜欢开放源代码,但这种设计中,一切都从源代码开始,要发布可执行程序,就等于发布源代码,所以不愿意 公布源代码的商业公司很不喜欢这些语言等等。但是上面的三个缺点,是最致命的,这三个缺点,决定了有些场合,就是不能用这种设计。
6. 分开解释和执行
前面的三个主要缺点,恰好全部被第二个设计所克服了。在第二种设计中, 我们可以只解释一次语法结构,生成一个结构更加简单紧凑的字节码文件。这样,以后每次要运行脚本的时候, 只需要把字节码文件送给一个简单的解释字节码的模块就行了。因为字节码比源程序要简单多了,所以解释字节码的模块比原来解释源程序的模块要小很多;同时, 脱离了语法树,我们完全可以用更加高性能的方式设计运行时,避免递归遍历语法树这种低效的执行方式;同时,在嵌入式系统上,我们可以只部署运行时,不部署 编译器。 这三个解决方案,预示了在运行次数远大于编译次数的场合,或在性能要求高的场合,或在嵌入式系统里,想要跨平台和安全性,就非得用第二种设计,也就是字节 码+虚拟机的设计。
讲到了这里,相信对对或者对历史稍微了解的读者都会一拍脑袋顿悟了: 原来这些牛逼的虚拟机都不是天才拍脑袋想出来的,而是被需求和现实给召唤出来的啊!
我们先以为例,说说在嵌入式场合的应用。语言,最初不是为桌面和服务器应用开发的,而是为机顶盒开发的。的唯一目的,就是为了参加机顶盒项目的竞标。嵌入式系统的资源受限程度不必细说了,自然不会允许上面放一个解释器和一个运行时。所以,不管虚拟机设计得直白无比,简单无比,手机上,智能卡上都能放上一个运行时(当然是精简版本的)。 这就是字节码和虚拟机的威力了。
正好对绘图支持非常好,在一统江湖之前,凭借跨平台性能,以的名义一举走红。然后,又因为这种设计先天性的能克服性能问题,在性能上大作文章,凭借技术,充分发挥上面说到的优点2,再加上安全性,一举拿下了企业服务器市场的半壁江山,这都是后话了。
再说的历史就包含了从第一种设计转化到第二种设计以用来优化运行时性能的历史。是一般用来生成服务器网页的脚本语言。一个大站点上的PHP脚本, 一旦写好了,每天能访问千百万次,所以,如果全靠每次都解释,每次都递归执行,性能上是必然要打折扣的。 所以,从开始,脚本解释引擎,就开始将解释成字节码,以支持这种一次解释,多次运行的框架。 在此之前,和还有还算平分秋色的样子,基本上服务器上三类网页的数量都差不多,三者语法也很类似,但是到了出现之后,其他两个基于第一种设计方案的页面就慢慢消逝了, 全部让位给博客,也是基于技术的,底层也是引擎的。 著名的里面的那个 P, 原始上也是年出现之后的事情。
第二种设计的优点正好满足了实际需求的事情,其实不胜枚举。比如说 在和等宿主语言上也都表现的淋漓尽致。像这样的小型语言,本来就是让运行时为了嵌入其他语言的,所以运行时越小越好,自然的,就走了和嵌入式系统一样的设计道路。
7. 结语
其实第二种设计也不是铁板一块,里面也有很多流派,各派有很多优缺点,也有很多细致的考量,下一节,如果不出意外,我将介绍我最喜欢的一个内容: 下一代虚拟机:寄存器还是栈。
说了这么多,最后就是一句话,有时候我们看上去觉得一种设计好像是天外飞仙,横空出世,其实其后都有现实,需求等等的诸多考量。虚拟机技术就是这样,在各种需求的引导下,逐渐的演化成了现在的样子。
本文关键词:高级语言,由笔耕文化传播整理发布。
本文编号:375497
本文链接:https://www.wllwen.com/wenshubaike/dxkc/375497.html