这几天如何创建语言?

时间:2009-10-11 06:33:41

标签: programming-languages language-design compiler-construction

我需要开始编写我一直想写的编程语言。这些天你们小孩怎么做?我已经离开了十多年了;你现在以不同于我们之前在互联网之前,窗前的日子做的事情吗?你知道吗,当“真正的”编码器用C语言编码时,使用命令行,并对哪个shell优于什么进行狡辩?

只是澄清一下,我的意思是,你不是如何设计一种语言(我可以很容易地弄清楚)但是你如何构建编译器和标准库等等?你这几天孩子们使用什么工具?

19 个答案:

答案 0 :(得分:7)

自打孔卡时代以来的一个新考虑因素是虚拟机的存在已经丰富地提供了“标准库”。针对JVM或.NET CLR而不是“语言围墙花园”,可以为您节省大量的时间。如果你正在创建一个编译语言,你也可能会发现Java字节代码或MSIL比机器代码更容易编译目标(当然,如果你是为了创建一个紧密优化编译器的乐趣那么你会看到这个作为一个错误而不是一个功能)。

从消极方面来说,JVM或CLR的习语可能不是您想要的语言。因此,您最终可能只是为了在平台设施上提供惯用接口而构建“标准库”。 (一个例子是,每种语言及其狗似乎都提供了自己的方法来写入控制台,而不是让用户手动调用System.out.println或Console.WriteLine。)尽管如此,它还能实现惯用语的增量开发。库,意味着即使是以丑陋的方式,仍然可以访问更难以理解的构建惯用接口的库。

如果您正在考虑解释语言,.NET还支持通过动态语言运行时(DLR)进行有效解释。 (我不知道是否有JVM的等价物。)这应该有助于你专注于语言设计,而不必过多担心解释器的优化。

答案 1 :(得分:6)

我现在已经在Haskell中编写了两个针对特定领域特定语言的编译器,并且发现它是一种非常高效的体验。 parsec库使得语法播放变得容易,并且解释器在Haskell数据结构上编写非常简单。我发现writing a Lisp interpreter in Haskell的说明很有帮助。

如果您对高性能后端感兴趣,我建议LLVM。它有一个简洁优雅的字节码和最好的x86 / amd64生成后端,你可以找到。有一个可选的垃圾收集器,以及target the JVM and CLR

的一些实验后端

您可以使用生成LLVM字节码的任何语言编写编译器。如果你喜欢冒险学习Haskell但想要LLVM,那么就有一组Haskell-LLVM绑定。

答案 2 :(得分:3)

已经发生了很大变化但尚未提及的是IDE支持和互操作性:

现在我们非常期待Intellisense,逐步执行和状态检查“正好在编辑器窗口中”,新类型告诉调试器如何对待它们,而不是有用的诊断消息。旧的“编译.x - > .y”可执行文件不足以创建语言。环境首先无需关注,但会影响采用的意愿。

此外,图书馆变得更加强大,没有人想用另一种语言实现所有这些。尝试借用,轻松调用现有代码,并使其他代码轻松调用。

根据itowlson的建议,定位虚拟机可能是一种很好的入门方式。如果结果出现问题,它仍然可以由本机编译器替换。

答案 3 :(得分:2)

我很确定你会做你一直做的事情。

编写一些代码,并向全世界展示您的结果。

与过去相比,有一些工具可以让你的工作变得更轻松。我可以建议ANTLR来解析你的语言语法吗?

答案 4 :(得分:2)

你不应该接受像使用最新工具这样的懦弱解决方案。您应该通过在Visual Basic for Applications或类似语言中编写最小编译器来引导语言,然后用新语言编写所有编译工具,然后仅使用语言本身进行自编译。

此外,该语言的拟议名称是什么?

我认为最近还没有像COBOL和FORTRAN这样的所有大写字母的语言,所以我希望你能用大写字母称它为MIKELANG。

答案 5 :(得分:2)

作为一个刚刚构建了非常简单程序集(如语言和解释器)的人,我开始使用.NET框架或类似的东西。在尝试编写大多数内容时,没有任何东西可以击败C#+的强大语法,这是整个.NET社区的支持。从这里开始,我设计了一个简单的字节码格式和汇编语法,然后编写了我的解释器+汇编程序。

就像我说的那样,它是一种非常的简单语言。

答案 6 :(得分:2)

与实现有关,而不是影响实现的设计决策 - 如果你使用你的语言的每个语句都有一个没有上下文的独特的解析树,你就会得到一些很容易手工编写解析器的东西,而且不会不需要大量的工作来提供语法高亮。类似的简单事情,比如对模块命名空间和对象命名空间使用不同的符号(与对包和类命名空间一起使用.的Java不同)意味着您可以解析代码而不加载它引用的每个模块。

标准库 - 包括除setjmp之外的C99标准库中的所有内容。添加域名所需的其他内容。找出一种简单的方法来做到这一点,比如SWIG或内联FFI,比如Ruby [不记得模块名称]和Python的ctypes。

在语言中构建尽可能多的语言是一种选择,但是开始做的项目要么放弃(rubinius转移到使用C ++来部署其标准库),或者仅用于研究目的( Mozilla Narcissus

答案 7 :(得分:1)

我其实是个孩子,哈哈。我以前从未编写过实际的编译器或设计过一种语言,但我已经完成了“红龙书”,所以我想我有点想法(我希望)。

首先取决于语法。如果它是LR或LALR,我认为像Bison / Flex这样的工具可以正常工作。如果它更多LL,我会使用Spirit,它是Boost的一个组件。它允许您以类似EBNF的语法在C ++中编写语言的语法,因此不会混淆代码生成器; C ++编译器为您编译语法。如果其中任何一个失败了,我会在纸上写一个EBNF语法,然后继续做一些重的递归下降解析,这似乎有效;如果使用RDP可以很好地解析C ++(就像GCC那样),那么我认为有足够的单元测试和耐心,你可以使用RDP编写整个编译器。

一旦我运行了解析器和某种中间表示,它就取决于它的运行方式。如果是某些字节码或本机代码编译器,我将使用LLVMlibJIT来处理它。 LLVM更适合一般编译,但我更喜欢libJIT API和文档。或者,如果我真的很懒,我将生成C代码并让GCC进行实际编译。另一种选择是针对现有的VM,如Parrot或JVM或CLR。 Parrot是为Perl设计的VM。如果它只是一个解释器,我会走语法树。

一个激进的替代方案是使用Prolog,它具有显着模拟EBNF的语法功能。我没有经验,如果我没有错(我几乎肯定会这样),如果用于解析具有大量语法结构和怪癖的重型编程语言,Prolog会很慢(阅读:C ++和Perl)。

所有这些我将在C ++中完成,只是因为我更习惯于写作而不是C.我会远离Java / Python或任何类似的实际生产代码(在C中编写编译器) / C ++有助于使其可移植),但我可以看到自己使用它们作为原型语言,尤其是Python,我偏向它。当然,我以前从未真正做过这些,所以我不能说。

答案 8 :(得分:1)

在开始创建语言之前,您应该阅读:

Hanspeter Moessenboeck,Niklaus Wirth的艺术

ftp://ftp.ssw.uni-linz.ac.at/pub/Papers/Moe00b.pdf

答案 9 :(得分:1)

lambda-the-ultimate上有一个由Marc-AndréCournoyer指向Create Your Own Programming Language的链接,该链接似乎描述了如何利用一些现代工具来创建小语言。

答案 10 :(得分:1)

  

只是澄清,我的意思是,你不是如何设计一种语言(我可以很容易地弄清楚)

只是一个提示:在设计新语言(即具有非常不同的评估策略的语言)之前,先查看一些非常不同的语言。我会想到HaskellOz。虽然你也应该知道Prolog和Scheme。一年前我也喜欢“嘿,让我们设计一种行为与我想要的完全一样”,但幸运的是我首先看了那些其他语言(或者你也可以说不幸,因为现在我不喜欢我不知道我希望语言如何表现......)。

答案 11 :(得分:0)

实现一种我在其他答案中没有看到的语言有一个很大的捷径。如果您使用Lukasiewicz的“未加掩饰”形式之一(即前向波兰语或反向波兰语),您根本不需要解析器!通过反向抛光,依赖关系从右向左进行,因此您只需在扫描时执行每个标记。使用正向抛光,它是相反的,所以你实际上“向后”执行程序,简化子表达式,直到达到起始标记。

要了解其工作原理,您应该研究3种主要的树遍历算法:预订,按顺序,后订购。这三个遍历是语言阅读器(即解析器)必须执行的解析任务的逆过程。只有按顺序表示法“需要”一个递归的体面来重构表达式树。使用其他两个,你可以只用一堆就可以逃脱。

这可能需要更多“思考”而不是“实施”。

顺便说一句,如果你已经找到答案(这个问题是一年之久),你可以发布并接受它。

答案 12 :(得分:0)

如果你想编写一个编译器,你需要阅读Dragon Book;)

这是我刚读过的另一本好书。它比Dragon Book更实用,更容易理解:

http://www.amazon.co.uk/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=language+implementation+patterns&x=0&y=0

答案 13 :(得分:0)

使用bison / flex,它是yacc / lex的gnu版本。这book is extremely helpful

使用野牛的原因是它捕获了语言中的任何冲突。我用它并且它让我的生活变得更加容易(好吧,所以我在第二年,但是前几个月是几年前用C ++编写它并且解析/冲突/结果非常糟糕!:(。)

答案 14 :(得分:0)

当然,旧技术仍然很常见(例如使用Flex和Bison)许多较新的语言实现通过使用基于解析表达式语法(PEG)的解析器来组合lexing和解析阶段。这适用于使用组合器创建的递归下降解析器,或者记忆Packrat解析器。许多编译器也是使用Antlr框架构建的。

答案 15 :(得分:0)

首先,我花了一年左右的时间才真正想到语言的外观。与此同时,我帮助开发了Ioke(www.ioke.org)来学习语言内部。

我选择了Objective-C作为实现平台,因为它快速(足够),简单而丰富的语言。它还提供了测试框架,因此敏捷的方法是一个进步。它还有一个我可以构建的丰富的标准库。

由于我的语言在语法层面上很简单(没有关键字,只有文字,运算符和消息),我可以使用Ragel(http://www.complang.org/ragel/)来构建扫描程序。它速度快,使用简单。

现在我有一个工作对象模型,扫描仪和简单的操作符改组以及标准库引导代码。我甚至可以运行一个简单的程序 - 只要它们适合一个文件:)

答案 16 :(得分:0)

不是一个简单的答案,但是......

你基本上想要定义一组用文本(令牌)编写的规则,然后是一些解析这些规则并将它们组装成片段的解析器。

http://www.mactech.com/articles/mactech/Vol.16/16.07/UsingFlexandBison/

人们可以在此花费数年时间,上面的文章讨论了使用两个工具(Flex和Bison)可以用来将文本转换为可以提供给编译器的代码。

答案 17 :(得分:0)

真正的编码员仍然在C编码。只是它更加清晰 嗯...语言设计?或编写编译器? 如果你想编写一个编译器,你可以使用Flex + Bison。 (谷歌)

答案 18 :(得分:-1)

迈克 -

如果您对Windows的高效本机代码生成编译器感兴趣,那么您可以轻松完成所有不必要的小部件,小工具和其他混乱当今机器的废话 - 我推荐Osmosian Order的简明英语开发系统。它包括一个独特的界面,一个简化的文件管理器,一个友好的文本编辑器,一个方便的十六进制转储器,编译器/链接器(当然),以及一个用于文档的所见即用的页面布局应用程序。完全用简单英语编写,它是一个快速下载(小于一兆字节),小到足以在短时间内理解(大约25,000行普通英语代码,编译器/链接器只有4,000行),但功能强大,足以重现自身在不到三秒钟的时间内在戴尔底线上。真的:三秒钟。所有写作和索要副本的人都可以免费使用,包括源代码和一本相当幽默的100页手册。有关如何获取副本或直接写信给我的问题或评论的详细信息,请访问www.osmosian.com:Gerry.Rzeppa@pobox.com