世界上第一门编程语言究竟是谁?

写在前面

它们不厌其烦地执行人的指令;它们收集世间万物的知识,供人顷刻之间随心调取;它们是现代社会的中流砥柱,但其存在却往往备受忽视。

它们就是计算机,是人类迄今为止最伟大的发明成就,是登峰造极、至高无上的终极工具。

计算机科学的问世,推动了人类历史上最非比寻常的社会变革之一。

编程语言作为计算机的灵魂,存在感却远远高于计算机,它就像一个纽带把我们和计算机深深的联系在了一起。

编程语言的发展更是和计算机的演变有着密不可分的关系。

不知道大家有没有好奇过,世界上第一门编程语言是什么?

今天就由我带领大家穿越到这一切的起点,去看一看计算机和编程语言的爱恨情仇。

正文

图灵机

不同的的人面对计算机有着不同的给关注点,有人觉得计算机的设计很巧妙,有人觉得计算机的结构布置很酷,有人觉得计算机的界面很漂亮……

但计算机的美妙之处并不在于其闪烁的灯光、旋转的磁盘、成排的芯片和电线,而在于,这些部件的背后隐藏着一个优雅而简单的想法。这个想法同晶体管、操作系统、网络和文字处理器毫无关联,也不可能有任何关联,因为它的诞生时间比这些设备都早。

图灵的相关生平,这里不多做赘述,这里我们只关注他的“可计算性理论”。

还记得当时初学冯诺依曼结构时,我们班里的同学还就冯诺依曼机与图灵机谁的贡献最大,而吵的不可开交,最后也是谁也没说服谁。

冯诺依曼机大家都不陌生,可以简单地理解成冯诺依曼机更侧重于硬件的实现

图灵机偏重的抽象模型是“可计算”和“不可计算”这个计算机的边界

  1. 世界上有很多问题,其中只有一小部分是数学问题;
  2. 在数学问题中,只有一小部分是有解的;
  3. 在有解的问题中,只有一部分是理想状态的图灵机可以解决的;
  4. 在后一类的问题中,又只有一部分是今天实际的计算机可以解决的。

这个时候可能有人就要说了,这和今天要讲的世界上第一个编程语言有什么关系?你这不是上来就先给计算机定下了一个边界了吗?

是的,先展示这段的目的就是为了告诉大家:不要迷信计算机,不要迷信我们的编程语言

不管是在人工智能和深度学习大行其道的今天,有些问题也是无法用计算机去解决的,我们要始终怀着一种敬畏之心来面对这个世界。

打孔卡片

这一切都要从打孔卡片开始说起。

美国宪法中要求,每10年就得进行一次人口普查。到了19世纪末期,人口增长的实在是太频繁了,以至于1880的人口普查历时8年才最终完成,当时还都是通过纸和笔来完成的。

1890年,Herman Hollerith被授命去解决这一问题,他最终使用了穿孔卡来存储数据,并用一台制表机(tabulating machine)来进行统计和排序。

在 20 世纪的大部分时间里,穿孔卡在数据处理行业得到了广泛的应用,其中专业且日益复杂的单元记录机器被组织成半自动数据处理系统,使用穿孔卡进行数据输入、输出和存储

1896年,Hollerith成立了制表机器公司,开始了自己的事业。他把自己的设备和卡片出售给大的保险公司,以及包括英国,意大利,德国,俄罗斯,澳大利亚,加拿大,法国,挪威,波多黎各,菲律宾等国在内的多国政府。

他的公司后来跟别的公司进行了合并,并在1924年最终成为了国际商业机器公司。没错,它就是IBM

这就是我们的第一站:打孔机和打孔卡片。

有人可能会有疑问,这打孔卡片也算是一门编程语言吗?这就要看大家怎么去定义编程语言了。

在我看来,只要其涉及数据处理与一定的计算规则都可以称为一种语言。就像我们常说的:

程序=数据+算法

哪怕这些数据只是最常见的自然数,哪怕这些算法只是加减乘除。

机器代码

打孔卡片靠其出色的能力盛行了一段时间,但你能想想那硕大的机器和成吨种的卡片吗?

幸运的是这些都只是暂时的,而拯救我们的就是电子学与计算机科学的结合,让我们脱离了笨重的机械式计算机。

晶体管的出现更是让“开/关”动作变得简洁又优雅。

而我们这次的主角——机器代码,就是这一开一关动作的化身:0和1。

机器代码之所以被称为机器代码,就是因为这种代码是可以直接被机器(计算机)所读取。

用二进制代码表示的计算机能直接识别和执行的一种机器指指令系统令的集合。

大家可以随便打开一个自己用任何一种高级语言编译好的二进制文件(.bin)来查看这些机器码到底长什么样子。

最右边就是我们的机器码,但为什么不是01组合,怎么还有其他数字和字母呢?

这是因为二进制表示的数字实在是太小了,所以大多采用的是十六进制来表示。

汇编语言

用机器语言编写程序,编程人员要首先熟记所用计算机的全部指令代码和代码的涵义。

手编程序时,程序员得自己处理每条指令和每一数据的存储分配和输入输出,还得记住编程过程中每步所使用的工作单元处在何种状态。这是一件十分繁琐的工作。

编写程序花费的时间往往是实际运行时间的几十倍或几百倍,而且,编出的程序全是些0和1的指令代码,直观性差,还容易出错

那么有没有一种方式,让我们能够更容易的记住这些机器指令?

汇编语言闪亮登场。

汇编语言的主体是汇编指令。汇编指令和机器指令的差别在于指令的表示方法上,汇编指令是机器指令便于记忆的书写格式。说白了,汇编语言就是助记符(Mnemonics)。

可能有人会问,我们用汇编语言编写程序,可是计算机只认识机器指令,那该怎么办?这时候就需要一个能将汇编语言转换成机器指令的工具,我们称其为编译器。程序员用汇编语言写出源代码,再用汇编编译器将其编译为机器码,最后由计算机执行。

再者,汇编语言指令是机器指令的一种符号表示,而不同类型的CPU 有不同的机器指令系统,也就有不同的汇编语言,所以,汇编语言程序与机器有着密切的关系

所以,除了同系列、不同型号CPU 之间的汇编语言程序有一定程度的可移植性之外,其它不同类型(如:小型机和微机等)CPU 之间的汇编语言程序是无法移植的,也就是说,汇编语言程序的通用性和可移植性要比高级语言程序低。(因为高级语言可以再不同类型的计算机上用不同的编译器翻译成机器语言)

Fortran

Fortran语言最初是由 IBM 公司在 50 年代开发的。

当时,创建语言的目的是专门解决一组特定的问题:Fortran 语言的目的是科学处理。

它仍然是在高性能计算领域最流行的语言之一,而且作为基准,用于世界最快的超级计算机程序的语言的排名。

Fortran 语言建立使用星号乘法,这是今天仍在使用的所有语言中的约定。

这是它的外观:

Program Hello
Print *, "Hello World!"
End Program Hello

COBOL

COBOL (Common Business-Oriented Language)
被设计用于商业用途。这是企图使编程语言更类似于英语,让程序员和管理人员可以读取它。

它的设计者有 Grace Hopper(发现 “Bug” 的人),以及发明了类似英语的数据处理语言 FLOW-MATIC的人,也是最合适,帮助创建一个看起来类似英文通用商业语言的人选。

这是一个 COBOL 的 Hello World 程序:

IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO-WORLD.
ENVIRONMENT DIVISION.        
DATA DIVISION.
PROCEDURE DIVISION.
MAIN.
    DISPLAY 'Hello, world.'.
    STOP RUN.

ALGOL 60

ALGOL 60 (ALGOrithmic Language 1960)
是一个委员会推动的,非常好,有影响力的语言, 发布于 1960 年。

它从来没有得到普及,但它推出了许多重要概念,包括摆脱 GOTO。在行与行之间跳来跳去行的语言,如 BASIC,难以遵循程序的流程,导致编写程序容易出错。

ALGOL 60 引入结构化程序设计和模块:它使用 BEGIN 和 END(因为大括号是不可用),感谢 ALGOL 60 现在我们有了代码块,而不是 GOTO。

ALGOL 也不希望太过专业,从而适合良好的科学和业务处理

下面是它的样子:

procedure Absmax(a) Size:(n, m) Result:(y) Subscripts:(i, k);
    value n, m; array a; integer n, m, i, k; real y;
comment The absolute greatest element of the matrix a, of size n by m 
is transferred to y, and the subscripts of this element to i and k;
begin integer p, q;
    y := 0; i := k := 1;
    for p:=1 step 1 until n do
    for q:=1 step 1 until m do
        if abs(a[p, q]) > y then
            begin y := abs(a[p, q]);
            i := p; k := q
            end
end Absmax

Pascal

Pascal 是在 1968 - 1969 年设计, 由 Niklaus Wirth出版于1970年,其灵感来自 ALGOL

它最初是非常流行的,虽然最初设计为教学工具,很长一段时间很多人用它做通用编程。

但是,它不是模块化不够,有一些使得编程难的设计挑战。

比如有一个片段:

while a <> b do  WriteLn('Waiting');
 
if a > b then WriteLn('Condition met')   {no semicolon allowed!}
           else WriteLn('Condition not met');
 
for i := 1 to 10 do  {no semicolon for single statements allowed!}
  WriteLn('Iteration: ', i);
 
repeat
  a := a + 1
until a = 10;
 
case i of
  0 : Write('zero');
  1 : Write('one');
  2 : Write('two');
  3,4,5,6,7,8,9,10: Write('?')
end;

B语言

B 在贝尔实验室开发于 1969 年, 它的灵感来自于 Fortran 和 BCPL。

还记得有个同学开玩笑说,既然有C语言,那肯定会有B语言和A语言,没想到还真有B语言(其实还有个E语言就不说了)。

B 引入了 += 操作符 (尽管写成 =+), 以及自增/自减操作符 (++)

printn(n,b) {
        extrn putchar;
        auto a;
 
        if (a=n/b) /* assignment, not test for equality */
                printn(a, b); /* recursive */
        putchar(n%b + '0');
}

C语言

C 诞生于 B 加上从 Pascal 加入一些好的想法。它是在贝尔实验室(再次)的 Dennis Ritchie 在 1969 年和 1973 年之间开发。

相比较于机器语言与汇编语言来说,C已经拥有更强的表达能力,可方便地表示数据的运算和程序的控制结构,能更好的描述各种算法,而且容易学习掌握

但高级语言编译生成的程序代码一般比用汇编程序语言设计的程序代码要长,执行的速度也慢。

关于编程语言就说到这里,如果把每一门语言都说一遍的话,可能几天几夜都说不完。

感兴趣的同学可以去维基百科上看一看

编程语言列表

第一个编译器是什么语言编译的?自举

除了第一个编程语言外,相信大家肯定还有一个疑问:世界上第一个编译器使用什么语言来编译的?

这就类似于那个世界上是先有鸡还是先有蛋的问题。

其实在编译原理中,有一个概念:自举。

编程语言是自举的,指的是说,我们能用自己写出来的程序编译自己。但是自举,并不要求这门语言的第一个编译器就是用自己写的。

比如,这里说到的 Go,先是有了 Go 语言,我们通过 C++ 写了编译器 A。然后呢,我们就可以用这个编译器 A,来编译 Go 语言的程序。接着,我们再用 Go 语言写一个编译器程序 B,然后用 A 去编译 B,就得到了 Go 语言写好的编译器的可执行文件了。这个之后,我们就可以一直用 B 来编译未来的 Go 语言程序,这也就实现了所谓的自举了。

更详细的关于鸡蛋问题,可以直接看 Wikipedia 上这个链接,里面讲了多种这个问题的解决方案。

自举

写在最后

在上文中,我们大致了解了计算机和编程语言的发展史。

如果从严谨一点的角度去考虑的话,Fortran语言应该是世界上第一门高级编程语言。

编程语言千千万,这些语言之间没有高低贵贱,更不存在什么歧视链, 有的只有不同的应用环境适合哪一种编程语言。

最后祝愿大家不管使用哪一种语言都能bug少少!!!

(室友和同门都申请离校回家了,我还悲惨的在学校呆着,可快点解封吧~我要出去吃烧烤,吃火锅!)

参考文献:

《计算机:一部历史》彼得·本特利

http://foorious.com/articles/brief-history-of-programming-languages/

https://segmentfault.com/a/1190000004303544

https://time.geekbang.org/column/article/91793

https://www.cnblogs.com/ysocean/p/7580162.html

posted @ 2022-05-28 14:05  iron2222  阅读(1953)  评论(2编辑  收藏  举报