编译型动态语言

7
我正在寻找一种编程语言,该语言具有编译器并支持自修改代码。我听说Lisp支持这些功能,但我想知道是否有一种更像C/C++/D的语言具备这些功能。
为了澄清我的意思:
我希望能够以某种方式在运行时访问程序代码,并对其进行任何类型的更改,即删除命令、添加命令、更改命令,就像我拥有程序的AstTree一样。当然,在编译语言中无法拥有该树,因此必须采用不同的方法。编译器需要将自修改命令转换为它们的二进制等效修改,以便它们可以在编译后的代码中运行。
我不想依赖虚拟机,这就是我所说的编译 :)

http://en.wikipedia.org/wiki/Self-modifying_code#High_level_languages - Mauricio Scheffer
你说的“自修改代码”和“动态”的意思是什么?这两个词通常不被视为同义词。如果您能澄清您的需求,我们可能可以更好地帮助您。 - David Thornley
是的,我之前看过维基页面了,但我希望能找到其他类似于C/C ++的编程语言。 - Marenz
什么是使用案例?为什么您希望能够在运行时编译代码?您是否尝试过简单地调用gcc或其他编译器,并将代码作为动态库加载? - Brian Campbell
我并没有特定的使用场景需要这个语言。我更想使用这样一种语言,来尝试玩耍。可能的用例是人工智能编程和优化,但对我来说,这只是我非常想要尝试的东西。 - Marenz
你可以在这里找到C#的示例: http://reboltutorial.com/blog/redirect-shell-to-rebol-console/ - Rebol Tutorial
7个回答

10

或许Lisp之所以是它的样子,是有原因的?Lisp被设计成用于编写其他语言,并使用代码和数据的符号表示进行计算。代码和数据之间的边界不存在了。这影响了编程语言的设计和实现。

Lisp具有其语法特性来生成新代码、翻译该代码并执行它。因此,预解析的代码也使用与其他程序相同的数据结构(符号、列表、数字、字符等)。

Lisp在运行时知道它的数据-您可以查询所有内容以获取其类型或类。类本身就是对象,函数也是如此。因此,编程语言和程序的这些元素也是一级对象,可以像这样进行操作。动态语言与“动态类型”无关。

“动态语言”意味着可以在运行时查看编程语言的元素(例如通过元类和元对象协议),并可以在运行时修改程序(其类、函数、方法、插槽、继承等)。

可能你为语言添加的这些特性越多,它看起来就越像Lisp。由于Lisp基本上是一个简单、动态、可编程的编程语言的局部最大值,如果您想要其中一些特性,那么您可能需要考虑放弃或愿意放弃其他编程语言的哪些特性。例如,对于一个简单的代码即数据语言,整个C语法模型可能并不实用。

因此,类似于C和“动态语言”可能并不是很匹配-语法只是整个情况的一部分。但是,即使C语法模型也限制了我们使用动态语言时的易用性。


谢谢你详细的回答。我已经了解其中的一些部分,但我仍然想知道是否可能使用更类似于C的语言,并且是否有人这样做过。我想我会更仔细地研究Lisp。 - Marenz

3

C#一直允许自我修改代码。

  • 在C# 1中,您可以基本上创建和编译即时代码。
  • C# 3添加了“表达式树”,它提供了一种有限的方法来使用对象模型和抽象语法树动态生成代码。
  • C# 4基于此,引入了对“动态语言运行时”的支持。在编译语言中,这可能是最接近LISP功能的.NET平台。

1
但它不是本地编译的(在CLR内运行)。然而,OP并没有明确说明这一点。 - Johannes Rudolph
这并不一定是真的。C# 在某些平台上(例如 iPhone 和 Xbox 360)可以编译成本机代码。但是,在这些平台上无法使用 Reflection.Emit。 - Jonathan Allen

2
您可能想考虑使用C++和LLVM生成(大多数情况下)可移植的代码。您甚至可以同时引入clang来处理C解析树(请注意,clang目前对C ++的支持不完整,但它本身是用C ++编写的)。
例如,您可以在C ++中编写一个自我修改的核心,以与clang和LLVM进行交互,并将程序的其余部分编写为C。将主程序的解析树存储在自我修改代码旁边,然后在运行时使用clang进行操作。 Clang将允许您直接以任何方式操作AST树,然后将其全部编译成机器代码。
请记住,在编译语言中操作AST始终意味着在程序中包含编译器(或解释器)。 LLVM只是这种操作的一种简单选择。

是的,我读了很多关于LLVM的内容。这是一个非常好的项目,但不是我在这个特定问题中所需要的 :) - Marenz
1
实际上,这听起来正是你所需要的。我在我的回答中澄清了一个可能的用途。 - bdonlan
在我的脑海中,我一直希望有一种直接应用这些修改的方法,而不必再次编译它们 - 直接操作二进制代码。但是似乎这几乎是不可能的,除非回到汇编语言。 - Marenz
1
直接操作二进制代码将会非常痛苦。首先,你无法从高层次视角进行操作;编译器会混淆执行顺序,在寄存器中保存随机变量等,因此汇编代码和C代码之间的联系并不明显。Linux内核确实会进行一些自我修补——但仅限于极其有限的范围,并且仅限于内联汇编段。 - bdonlan

1

JavaScirpt + V8(Chrome JavaScript编译器)

JavaScript是

  • 动态的
  • 自我修改(自我评估)(嗯,根据您的定义而定)
  • 具有类似C的语法(同样,这是最适合动态语言的)

现在,您可以使用V8编译它:http://code.google.com/p/v8/


2
V8是“即时编译”的,但它仍然在虚拟机中运行,而提问者不希望如此。 - Callum Rogers
2
显然,自解析语言必须在JIT编译器或解释器上运行,否则它怎么能运行数据作为代码呢?不存在100%预编译的自解析语言。 - Tamas Czinege

0
“动态语言”是一个广泛的术语,涵盖了各种概念。动态类型由编译语言C# 4.0支持。Objective-C也支持一些动态语言的特性。然而,它们都无法与Lisp相比,后者在支持自修改代码方面更胜一筹。
为了支持这种程度的动态性和自修改代码,您应该拥有一个完整功能的编译器,在运行时调用;这基本上就是解释器的作用。

一些 Lisp 实现并没有真正的解释器,而是通过即时编译来模拟解释器。我想这会在你一开始就将代码解析成形式时有所帮助。 - David Thornley
大卫:确实。这就是我所说的“...你应该在运行时调用一个完整功能的编译器。”解释器可以无缝地提供此功能,而在编译环境中,您基本上应该在运行时编译代码。尽管如此,它并不像静态编译的代码那样。 - Mehrdad Afshari

0

试试Groovy吧。它是一种基于Java-JVM的动态语言,可以在运行时编译。它应该能够执行自己的代码。

http://groovy.codehaus.org/

否则,你总是可以使用Perl、PHP等语言,但这些并不像你所建议的C/C++/D那样。

Perl或PHP就足够像C/C++/D一样了,我更想排除像Cobol、Lisp和类似的东西。但是我不想要JIT,我真的希望它被完全编译成独立的可执行文件。 - Marenz
在这种情况下,一定要选择Perl...你再也不会回头了。 - Lincoln

0
我不想依赖于虚拟机,这就是我所说的编译 :) 如果您只是寻找这个,我建议使用Python或Ruby。它们都可以在自己的虚拟机上运行,也可以在JVM和.Net CLR上运行。因此,您可以选择任何运行时。两者中,Ruby似乎有更多的元编程功能,但Python似乎在其他平台上有更成熟的实现。

我的意思是,我不想要任何那种类型的虚拟机。Ruby、Java等都没有编译。我不想要那个。 - Marenz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接