当某人编写一种新的编程语言时,他们用什么来编写?


162

请原谅我的无知。我正在涉足PHP,并且全神贯注地浏览SO,并且不得不问一个我多年来一直想知道的问题:

当您编写全新的编程语言时,该用什么编写

对于你们所有的程序员来说,这听起来都是很愚蠢的事情,对此我深表敬意,但这对我来说却是一件令人费解的事情。你是做什么?对自己说:今天我要发明一种新的语言!然后启动...记事本?所有的编译器是否都建立在以前存在的语言之上,以至于一劳永逸就可以将所有设计过的编程语言绘制到一棵巨大的分支树上,最终植根于……我不知道,有些古老了吗?

凭着我无能为力的智慧,我发现这很着迷...请教育我!

Answers:


193

这不是一个愚蠢的问题。这是一个很好的问题。

正如已经回答的那样,简短的答案是“另一种语言”。

好吧,这引出了一些有趣的问题?如果它是为您的特定硬件编写的第一语言,该怎么办?对于在嵌入式设备上工作的人来说,这是一个非常现实的问题。正如已经回答的“另一台计算机上的一种语言”。实际上,某些嵌入式设备永远都不会获得编译器,它们的程序将始终在其他计算机上进行编译。

但是您可以将其进一步推回去。那么第一个编写的程序呢?

那么,“高级语言”的第一个编译器将以所谓的“汇编语言”编写。汇编语言是一种语言,其中该语言中的每个指令都对应于CPU的单个指令。它的语言水平很低,编写起来非常冗长且费力。

但是即使编写汇编语言,也需要一个称为汇编程序的程序才能将汇编语言转换为“机器语言”。我们再回头。最早的汇编程序是用“机器代码”编写的。一个完全由二进制数组成的程序,它与计算机本身的原始语言直接一一对应。

但这还没有结束。即使其中仅包含原始数字的文件仍然需要翻译。您仍然需要将这些原始编号存储在计算机中的文件中。

不管您是否相信,早期的计算机都在其正面装有一排开关。翻转开关,直到它们代表一个二进制数字,然后轻拂另一个开关,然后将那个数字加载到计算机内存中。然后,您将继续轻弹切换,直到您加载了一个最小的计算机程序,该程序可以从磁盘文件或打孔卡读取程序。您轻按了另一个开关,它开始运行程序。我在80年代上大学时,看到了具有这种能力的计算机,但从未完成过用交换机加载程序的工作。

甚至比以前更早的时候,计算机程序还必须通过插头板进行硬接线!


20
+1,我认为这个答案确实符合问题的精神。
stderr

30
我曾经参加过Assembler II课程,教授问我们为什么选择选修课。我去了一个有趣的答案:“因为我想要简单的A。” 以为我能得到最好的答案,但是我们在镇上有一家霍尼韦尔工厂,而下一个家伙说:“我整天都在写微代码,我想学习一种高级语言。”
T.Rob

3
我强烈推荐代码:计算机硬件和软件的隐藏语言。从真空管一直到高级语言的编译器,它基本上涵盖了与该答案相同的材料。
MatrixFrog 2013年

计算机的发展就像人类一样,尽管时间是无限的。
Gaurav Ojha

现在,这将是一个nonconstructive评论,但它已被写入...这是各种形状,形式和信息:-)灿烂辉煌的答案
卢卡斯拉德克·

23

最常见的答案是C。大多数语言都是用C或以C的混合形式实现的,其中包括回调和“ lexer”(如Flex)和解析器生成器(如YACC)。这些是用于一种目的的语言-描述另一种语言的语法。有时,当涉及到编译语言时,它们首先用C实现。然后使用该语言的第一个版本来创建新版本,依此类推。(就像Haskell一样。)


1
有些语言是用汇编语言编写的,例如picolisp。(blog.kowalczyk.info/article/picoLisp-Arc-before-Arc.html
法尔肯教授

1
lex / yacc(flex / bison)程序如何?这些是否被视为在C语言中创建语言的补充?
戴夫

1
您有什么可以证明最常见的答案是C吗?
RichardOD

我从这里开始浏览列表: google.com/Top/Computers/Programming/Languages/Open_Source 然后我不小心关闭了大约10种语言的编辑器窗口,并失去了浏览的动力。无论如何,到目前为止,大约有一半是用C语言实现的,其余的大部分都是自举的。
法肯教授2009年

3
我认为您必须提到Lex / Yacc(或替代方法)。人们通常不会开始用C语言编写语言,而是使用词法分析器和解析器,然后使用C代码来支持。
史蒂夫·罗

14

许多语言都是自举的,它们是用自己编写的。至于为什么要这样做,通常最好吃自己的狗食

我引用的Wikipedia文章讨论了鸡肉和鸡蛋的问题。我认为您会发现它很有趣。


5
当您刚开始时,这是不可能的。
Michael Borgwardt

1
是的-很明显。但是,一旦有可能,许多语言都将以这种方式编写。我想指出这一点,这是很重要的一点。
RichardOD

+1用于使用术语引导程序。有趣的是,您必须编译两次编译器。显然,第一次是使用您拥有的准系统编译器,而第二次是使用您刚刚构建的编译器。假设您向编译器添加了优化。您构建的编译器可以通过这些优化来生成代码,但是,直到您再次使用优化编译器对其进行编译之后,编译器才能运行优化代码。
莱斯

@ Les-是的,引导是一个有趣的概念。
RichardOD

2
在这里随意评论。关于谁是第一位(鸡肉或鸡蛋)的古老问题的答案是,鸡肉是第一位的。原因是要复制/复制某些内容,您必须首先已准备好复制器/复制器才能进行复制/复制。
SpicyWeenie 2014年

10

几乎所有语言都可以使用,尽管使用适合于图形和其他复杂数据结构的语言会使许多事情变得容易。出于性能原因,生产编译器通常使用C或C ++编写,但是可以说,诸如OCaml,SML,Prolog和Lisp之类的语言可以更好地进行原型设计。

在语言设计中还使用了几种“小语言”。Lex和yacc用于指定语法和语法,例如,它们可编译为C。(存在其他语言的端口,例如ocamllex / ocamlyacc和许多其他类似的工具。)

作为一种特殊情况,新的Lisp方言通常建立在现有的Lisp实现上,因为它们可以搭载在大多数相同的基础结构上。可以在Scheme的代码页面下完成编写Scheme解释器,此时可以轻松添加新功能。

从根本上讲,编译器只是将某些内容读入并将其转换为其他内容的程序-将LaTeX源转换为DVI,将C代码转换为汇编语言,然后转换为机器语言,将语法规范转换为解析器的C代码,等等。源格式的结构(解析),这些结构的含义,如何简化数据(优化)以及生成的输出种类。口译员读取源代码并直接执行。(口译员通常更容易编写,但要慢得多。)


4

实际上,您几乎可以使用任何您喜欢的语言编写。没有什么可以阻止您使用Ruby编写C编译器的。您要做的“全部”是分析程序并发出相应的机器代码。如果您可以读取/写入文件,则您的编程语言可能就足够了。

如果您是在新平台上从头开始,则可以进行交叉编译:为您的新平台编写一个编译器,该编译器可以用Java或本机运行在x86上。在您的PC上进行开发,然后将程序转移到新的目标平台。

最基本的编译器可能是Assembler和C。


但是,这种“任何”语言都应支持递归调用。否则,实现语法分析器和解析器将是一个真正的挑战。

2
如果您为任务选择了不合适的语言,那是您自己的错。这对于任何项目都可能发生,而不仅仅是编译器/解释器。
ziggystar

4

从技术上讲,“编写一种新的编程语言”不涉及任何代码。它只是针对您的语言外观及其工作方式制定了规范。一旦了解了语言的样子,就可以编写翻译和口译员,使您的语言真正“起作用”。

翻译器以一种语言输入程序,并以另一种语言输出等效程序。解释器以某种语言输入程序并运行它。

例如,C编译器通常将C源代码(输入语言)转换为汇编语言程序(输出语言)。然后,汇编器采用汇编语言程序并生成机器语言。获得输出后,就不需要翻译程序来运行程序了。由于您现在拥有机器语言程序,因此CPU充当解释器。

许多语言的实现方式有所不同。例如,javac是一个将Java源代码转换为JVM字节码的转换器。JVM是运行Java字节码的解释器[1]。运行javac并获取字节码后,您不需要javac了。但是,无论何时要运行程序,都需要JVM。

不需要让翻译人员随便运行程序的事实是,可以“引导”您的语言而不会使其最终运行在其他语言的“层”之上。

[1]大多数JVM在后台进行翻译,但是它们并不是真正的翻译者,因为与JVM的接口不是“输入语言->输出语言”。


3

通常,您可以使用几乎任何喜欢的语言。例如,PHP用C编写。如果您无权访问任何编译器,那么您将不得不编写汇编语言并将其手工编译为机器代码。


2
您不必编译机器代码。根据定义,它是CPU的本地语言。
斯图·汤普森

1
真正。我的意思是“用汇编语言或类似的方法手工编译机器代码”。我可能是错的,但是我猜很少有人会立即以二进制/十六进制的形式输入代码。
2009年

2

许多语言首先是用另一种可用语言编写的,然后以其自身重新实现并以这种方式引导(或只是将实现保留在外语中,例如PHP和Perl),但是某些语言(例如第一个汇编器)被手工编译为机器代码,例如第一个C编译器是手工编译到汇编的。

自从我读了这篇文章以来,我就一直对引导感兴趣。为了了解更多信息,我尝试自己编写自己的BF超集(我称为EBF)来自己做。EBF的第一个版本有3个额外的原语,我手工编译了第一个二进制文件。这样做时,我发现了两步节奏。我在一个发行版中以当前语言实现了一项功能,并在一个不错的发行版中重写了代码以利用已实现的功能。该语言具有足够的表现力,可用于制作LISP解释器

我在第一个发行标签中有手工编译的版本以及源代码,并且代码很小。最新版本的大小和代码大12倍,并且允许更紧凑的代码,因此手动编译当前版本将很难正确。

Edmund Grimley Evans用他的十六进制语言做了类似的事情

自己进行此操作的有趣的事情之一是您了解为什么某些事物保持原样。我的代码是产品,如果进行细微的增量调整,则看起来更像是经过改进而不是从头开始设计。今天阅读代码时,我谨记这一点,我认为这看起来有些偏离。


1

通常使用适合系统开发的通用编程语言,例如C,Haskell,ML,Lisp等,但是选项列表很长。另外,通常使用某些特定于域的语言来实现语言,例如,解析器和词法分析器生成器,诸如LLVM之类的中间语言。还有可能是一些shell脚本,测试框架和构建配置系统,例如autoconf。


1

大多数编译器使用的是C或类似ac的程序(如果不是c的话),那么汇编语言是可行的方法。但是,从头开始编写新的lang时,您没有宏lib或原型语言的源代码,则必须定义自己的函数现在用什么语言?您可以只在机器上编写一个名为psedocode的源代码形式psedocode,它看起来像来自面向对象的结构化语言规范(如Fortran基本算法lisp的bnf语法)。因此,图像编写类似于任何这些语言语法的交叉代码就是psedo代码


1
我不认为psedo代码应该是机器可读的
Richard Tingle

0

如果您没有源文件来查看“这些对象的功能应如何在您的表述中,那么甚至进一步的二进制或汇编操作也必须转换为函数,即汇编程序/编译器工作,然后转换为对象,然后从数据和函数转换为对象语言实现,那么您必须识别“看到”实现,或者定义自己的功能,过程和数据结构,这需要大量的知识,您需要问自己什么是功能。然后您的思维就变成了语言模拟。这样可以将Master程序员与其他人分开。


0

几个月前我也有这个问题。而且我读了几篇文章,还看了一些视频,这些视频帮助我开始写自己的语言,称为“软”。它还没有完成,但是我从这次旅行中学到了很多东西。

您应该了解的基本知识是编译器在必须执行代码段时的工作方式。编译器有很多阶段,如词法分析,语义分析器,AST(抽象语法树)等。

我在这里使用新语言所做的工作-http: //www.singhajit.com/writing-a-new-programming-language/

如果您是第一次编写语言,那么一切顺利,您还有很长的路要走。


0

一般而言,什么是编程语言?

编程语言只是与计算机对话的一种方式。首先粗略地说,因为计算机只能理解零和一(由于计算机是由晶体管制成的开关,所以只能接受两个状态,所以我们将这两个状态称为0和1),并且很难使用0,1我们是人类,因此计算机科学家决定对二进制(0,1)中的每条指令进行一对一的映射,以使其更易于理解,并将其称为汇编语言。

例如,如果我们有一条类似的指令:

11001101

在组装中将其称为:

LOAD_A 15

这意味着将寄存器a的内容加载到内存位置15中。正如我所说,这只是一个惯例,例如为晶体管的两个状态或计算机中的任何其他状态选择0和1。这样,程序就有50条指令,记住汇编语言会更容易。因此用户可以编写汇编代码,而某些程序(在这种情况下为汇编程序)会将代码转换为二进制指令或机器语言(如其所称)。

但是随着计算机的日趋完善,还有更多的空间可以编写更多的指令,例如10000。

在这种情况下,像汇编这样的一对一映射将不起作用,因此创建了其他高级编程语言。他们说,例如,如果要与I / O设备建立关系,以便在用户创建的屏幕上打印某些内容时需要大约80条指令,让我们在此处执行一些操作,就可以将所有这些代码打包到一个库中,并称之为printf。并创建另一个程序,该程序可以将此处的printf转换为相关的程序集代码,然后程序集将在此完成其余的工作。所以他们称其为编译器。

因此,现在每个只想在屏幕上打印某些内容的用户都不必用二进制或汇编语言编写所有指令,只需键入printf(“ something”),其余的程序(例如编译器和汇编器)就可以完成。现在以后,其他较长的代码将以相同的方式打包,以方便其他人的工作,就像您看到的那样,您可以将成千上万行代码简化为python中的一个代码,并将其打包以供其他人使用。

因此,假设您在python中打包了许多不同的代码,并创建了一个模块(libray,package或任何您想调用的模块),然后您将该模块称为mgh(只是我的名字)。现在,假设我们以某种方式创建了该mgh,

import mgh
mgh.connect(ip,port.data)...

可以轻松地使用指定的ip和端口号连接到远程服务器,然后再发送数据(或类似的东西)。现在人们可以只用一行执行所有操作,但是发生的事情是,正在执行许多从mgh文件中检索到的代码。打包并不是为了加快执行过程,而是为了促进其他程序员的工作。因此在这里,如果有人想先使用您的代码,他应该导入文件,然后python解释器将识别其中的所有代码,以便它可以解释代码。

现在,如果您想创建一种编程语言并要执行它,首先需要翻译,例如,假设您创建了一个可以理解语法并将其转换为c的程序,在这种情况下,将其翻译为c到c,其余的工作将由c编译器处理,然后由汇编器,链接器等处理。即使您必须付出变慢的代价,因为它必须先转换为c。

现在您可以做的另一件事是创建一个程序,该程序可以将所有代码转换为等效的汇编语言,就像c发生的情况一样,但是在这种情况下,程序可以直接执行此操作,其余的操作将由链接器。我们知道该程序称为编译器。

所以我在说的是,系统可以理解的唯一代码是0,1,因此您应该以某种方式将语法转换为0,1,现在在我们的操作系统中,许多不同的程序,例如汇编器,链接器和...创建它是为了告诉您,如果您可以将代码转换为汇编语言,则可以解决其余问题,或者正如我所说,您甚至可以通过将代码转换为该语言来使用其他编程语言编译器。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.