我总是对此感到疑惑,也许我需要一门关于编程语言的良好历史课程。但是,由于当今大多数编译器都是用C编写的,那么最早的编译器是如何编写的(在C之前是AKA),或者是所有语言都只是被解释了?
话虽这么说,我还是什至不了解第一种汇编语言是如何完成的,我理解什么是汇编语言,但是我看不到他们如何使非常第一的汇编语言起作用(例如,他们是如何使第一命令(如mov R21
)或w / e设置为等效的二进制代码?
我总是对此感到疑惑,也许我需要一门关于编程语言的良好历史课程。但是,由于当今大多数编译器都是用C编写的,那么最早的编译器是如何编写的(在C之前是AKA),或者是所有语言都只是被解释了?
话虽这么说,我还是什至不了解第一种汇编语言是如何完成的,我理解什么是汇编语言,但是我看不到他们如何使非常第一的汇编语言起作用(例如,他们是如何使第一命令(如mov R21
)或w / e设置为等效的二进制代码?
Answers:
哈,我已经做到了。许多CPU具有固定大小的简单指令,这些指令只有几个字节长。例如,对于像Motorola 6800这样的简单CPU,您可以将其所有说明放在一张纸上。每个指令都将有一个与它关联的两字节操作码和参数。您可以通过查找每个指令的操作码来手工汇编程序。然后,您需要在纸上编写程序,并用相应的操作码注释每个指令。编写完程序后,可以将每个操作码依次刻录到EPROM然后会存储您的程序。仅在正确的地址使用正确的指令将EPROM连接到CPU,您便有了一个简单的工作程序。并回答您的下一个问题,是的。这很痛苦(我们在高中时就这么做了)。但是我不得不说,连接8位计算机中的每个芯片并手动编写程序使我对计算机体系结构有了更深入的了解,而我可能无法以其他任何方式实现。
更高级的芯片(例如x86)很难手动编码,因为它们通常具有可变长度的指令。像Itanium这样的VLIW / EPIC处理器几乎不可能有效地手动编码,因为它们处理的指令包是由高级编译器优化和汇编的。对于新体系结构,几乎总是先在另一台计算机上编写和组装程序,然后再将其加载到新体系结构中。实际上,对于像Intel这样真正在构建CPU的公司来说,他们可以通过在模拟器上运行尚不存在的架构来运行实际程序。但是我离题了...
对于编译器,最简单的说就是“剪切并粘贴”程序。您可以编写一种非常简单的,非优化的“高级语言”,而无需进行大量工作即可将简单的汇编语言指令聚集在一起。
如果您需要编译器和编程语言的历史记录,建议您转到FORTRAN的历史记录。
这就是编译器引导的内容(因为没有人提到它的调用方式=)。
用要编译的目标编程语言编写编译器(或汇编器)的过程。应用此技术将导致自托管编译器。
引导了许多编程语言的许多编译器,包括BASIC,ALGOL,C,Pascal,PL / I,Factor,Haskell,Modula-2,Oberon,OCaml,Common Lisp,Scheme,Java,Python,Scala等的编译器。 。
鸡肉和鸡蛋问题
如果需要语言X的编译器来获得语言X(以语言X编写)的编译器,那么第一个编译器是如何编写的?解决这种鸡肉或鸡蛋问题的可能方法包括:
- 用语言Y实现语言X的解释器或编译器。Niklaus Wirth报告说他在Fortran中编写了第一个Pascal编译器。
- X的另一种解释器或编译器已经用另一种语言Y编写;这就是Scheme经常被引导的方式。
- 较早版本的编译器是用X的子集编写的,而X的子集还存在其他一些编译器。这就是引导Java,Haskell和最初的Free Pascal编译器的某些超集的方式。
- X的编译器是从存在X的编译器的另一体系结构交叉编译而成的。这就是C编译器通常如何移植到其他平台的方式。这也是初始引导后用于Free Pascal的方法。
- 用X编写编译器;然后从源代码手工编译它(很可能以一种非优化的方式),然后在代码上运行它以获得优化的编译器。唐纳德·克努斯(Donald Knuth)将其用于他的WEB文学编程系统...
最终,所有计算机都以二进制代码运行,然后将其输入CPU。这些二进制代码对于CPU来说是完全自然的,但对人类却完全没有用。编写程序的最早方法之一是在卡上打孔。孔的位置表示一个单词中的特定位位置,并且孔的存在与否被解释为零或一。将这些卡按正确的顺序放入一个盒子中,然后送入读卡器中,该读卡器将它们有效地转换为用于CPU的二进制代码(如果您丢下盒子,您的生命将被完全丧失)。
显然,最早的程序员一步一步地制作出了二进制代码,并拥有一台机器来打卡。这实际上是您双手和膝盖上的汇编语言编程。一旦有了它,就可以从中创建所有其他内容:一个简单的文本编辑器,一个汇编语言编译器(用于将文本汇编语句转换为二进制代码),一个链接器和一个加载器。而其余的,正如他们所说,是历史。
从40年代后期开始,略微谷歌搜索就增加了EDSAC的初始订单。由于它是第一个汇编程序,因此可能是用机器语言编写的。
后来出现了其他机器的汇编程序,例如IBM 650的SOAP I和II。尽管我还没有找到明确的陈述,但SOAP I也可能用机器语言编码。
后来又出现了IBM 704的Fortran(公式转换器)。大概是704的汇编程序编写的。701的早期汇编程序归功于Nathan Rochester。
如果您想了解如何使用机器语言对计算机编程,请查看我最喜欢的站点之一,Harry Porter的中继计算机。
可能(如果很乏味)编写直接的机器代码。也许您将程序写在汇编器中的一张纸上,然后手动将其转换为数字机器码指令,然后将其输入到机器存储器中。如果您已记住所有机器代码指令的数值,则甚至可以跳过纸上汇编程序的步骤-在那些日子里并不罕见,信不信由你!
最初的计算机是通过切换物理开关直接以二进制方式编程的。当硬件发展到允许程序员(或数据输入助手)通过小键盘以十六进制数字输入代码时,这极大地提高了生产率!
仅当有更多内存可用时软件汇编器才有意义(因为汇编器代码比原始机器代码占用更多的空间),并且硬件发展为允许字母数字输入。因此,第一批汇编程序是由精通机器代码的人员直接编写的。
当您拥有汇编器时,可以在汇编器中编写用于高级语言的编译器。
C的故事有多个步骤。第一个C编译器是用B(C的前身)编写的,而B又是用BCPL编写的。BCPL是一种非常简单的语言(例如,它根本没有类型),但是仍然比原始汇编程序更先进。因此,您将了解如何逐渐将更复杂的语言以更简单的语言构建,一直到汇编程序。从今天的标准来看,C本身是一种非常小巧的语言。
如今,一种新语言的第一个编译器通常是用C编写的,但是当该语言达到一定成熟度时,通常会“本身”进行重写。第一个Java编译器是用C编写的,但后来用Java重写了。第一个C#编译器是用C ++编写的,但是最近它已经用C#重写。Python编译器/解释器是用C编写的,但是PyPy项目试图用Python重写它。
但是,用语言本身编写语言的编译器/解释器并不总是可行的。存在用JavaScript编写的JavaScript解释器,但是出于性能方面的考虑,当前浏览器中的编译器/解释器仍然使用C或C ++编写。用JavaScript编写的JavaScript太慢了。
但是您不必使用C作为编译器的“起始语言”。第一个F#编译器是使用OCaml编写的,这是与F#关系最密切的另一种语言。编译器完成后,它已用F#重写。Perl 6的第一个编译器是用Haskell(与Perl 完全不同的纯功能语言)编写的,但是现在有用C编写的编译器。
Rust是一个有趣的案例,其中第一个编译器是用OCaml编写的(现在已经用Rust重写了)。这是值得注意的,因为OCaml通常被认为比Rust(一种更接近金属系统的语言)的级别更高。因此,不一定总是用较低层的语言来实现较高层的语言,反之亦然。
它看起来并不困难。在童年时期;)我想到了一些x86拆卸。
您甚至不需要特别学习它。当您能够在ASM中进行编程,然后尝试使用交互式反汇编程序修复第三方二进制文件时,就会发生这种情况。或者在编写自己的代码加密保护时。
即有时您甚至毫无疑问地从语言迁移到代码。