您能否建议一种支持在运行时修改代码的强大语言或功能?
我的意思是在运行时修改代码:
Start:
a=10,b=20,c=0;
label1: c=a+b;
....
label1= c=a*b;
goto label1;
可能正在构建说明列表:
code1.add(c=a+b);
code1.add(c=c*(c-1));
code1. execute();
答案 0 :(得分:44)
Malbolge将是一个很好的起点。每条指令都是自我修改的,玩起来很有趣(*)。
(*)免责声明:实际上可能并不好玩。
答案 1 :(得分:22)
我强烈推荐Lisp。 Lisp数据可以作为代码读取和执行。 Lisp代码可以写成数据。
它被认为是规范的自我修改语言之一。
示例列表(数据):
'(+ 1 2 3)
或者,将数据称为代码
(eval '(+ 1 2 3))
运行+功能。
您也可以随时进入并编辑列表成员。
编辑:
我编写了一个程序来动态生成一个程序并在运行中对其进行评估,然后向我报告它与基线相比如何(div为0是通常的报告,哈哈)。
答案 2 :(得分:14)
到目前为止,每个答案都是关于反射/运行时编译,但在你提到的评论中,你对实际的self-modifying code感兴趣 - 在内存中修改自身的代码。
在C#,Java甚至(可移植)中无法在C中执行此操作 - 也就是说,您无法使用这些语言修改加载的内存中二进制文件。
一般来说,唯一的方法是使用汇编,它依赖于处理器。事实上,它依赖于高度操作系统:防范polymorphic viruses,大多数现代操作系统(包括Windows XP +,Linux和BSD)强制执行W^X,意思是你必须go through some trouble在这些操作系统中编写多态可执行文件,以便完全允许它。
在某些解释语言中,程序可能会在程序运行时修改自己的源代码。 Perl, Python (参见here),但我知道的Javascript的每个实现都不允许这样做。
答案 3 :(得分:9)
就我个人而言,我觉得很难找到比C#更易于处理的程序集。我觉得你觉得装配不是那么强大就更奇怪了:你不能比原始机器语言更强大。无论如何,他/她自己。
C#具有很好的反射服务,但是如果你对此感到厌恶......如果你对C或C ++非常熟悉,你总是可以编写一个编写C / C ++并将其发布给编译器的程序。只有当您的解决方案不需要快速的自我重写周转时间(大约几十秒或更长时间)时,这才是可行的。
Javascript和Python也支持反射。如果您正在考虑学习一种功能强大但技术要求不高的新的有趣的编程语言,我建议使用Python。
答案 4 :(得分:9)
我可以建议Python,这是一种非常高级的动态语言,包含丰富的内省(例如compile
,eval
或exec
的使用允许自修改代码的形式)。一个基于您的问题的简单示例:
def label1(a,b,c):
c=a+b
return c
a,b,c=10,20,0
print label1(a,b,c) # prints 30
newdef= \
"""
def label1(a,b,c):
c=a*b
return c
"""
exec(newdef,globals(),globals())
print label1(a,b,c) # prints 200
请注意,在上面的代码示例中,c
仅在函数范围内进行了更改。
答案 5 :(得分:7)
Common Lisp的设计考虑到了这一点。您也可以尝试Smalltalk,其中使用反射来修改正在运行的代码并不是未知的。
在这两种语言中,您可能会替换整个函数或整个方法,而不是一行代码。 Smalltalk方法往往比Lisp函数更细粒度,所以这可能是一个好的开始。
答案 6 :(得分:6)
许多语言允许您在运行时eval编码。
答案 7 :(得分:4)
在运行时编译和执行代码的高级语言中,它不是真正自我修改的代码,而是动态类加载。使用继承原则,您可以替换类Factory并在运行时更改应用程序行为。
只有在汇编语言中,您才能通过直接写入代码段来实现真正的自我修改。但它几乎没有实际用途。如果您喜欢挑战,请编写自加密,可能是多态病毒。那会很有趣。
答案 8 :(得分:2)
我有时候,虽然非常很少在Ruby中自行修改代码。
有时您会有一种方法,您实际上并不知道您正在使用的数据(例如某些延迟缓存)是否已正确初始化。因此,您必须在方法的开头检查数据是否已正确初始化,然后可能将其初始化。但是你真的只需要进行一次初始化,但每次都要检查它。
因此,有时我会编写一个执行初始化的方法,然后将其自身替换为不包含初始化代码的版本。
class Cache
def [](key)
@backing_store ||= self.expensive_initialization
def [](key)
@backing_store[key]
end
@backing_store[key]
end
end
但说实话,我认为这不值得。事实上,我很尴尬地承认我从来没有真正进行基准测试,看看 one 条件是否实际上有所不同。 (在现代Ruby实现中,可能没有积极优化配置文件反馈驱动的JIT编译器。)
请注意,根据您定义“自修改代码”的方式,这可能是您想要的,也可能不是。你 替换当前执行程序的某些部分,所以......
编辑:现在我考虑一下,这种优化没有多大意义。昂贵的初始化只会执行一次。修改唯一避免的是有条件的。最好以支票本身的价格为例,但我想不出一个。但是,我想到了一个很好的自修改代码示例:Maxine JVM。 Maxine是一个研究虚拟机(技术上不是允许被称为“JVM”,因为它的开发人员不运行兼容性测试套件)完全用Java编写。现在,有很多JVM本身编写,但Maxine是我所知道的唯一一个运行的人。这非常强大。例如,JIT编译器可以通过JIT编译自身,使其适应JIT编译的代码类型。
在Klein VM中发生了类似的事情,它是自编程语言的VM。
在这两种情况下,VM都可以在运行时优化和重新编译本身。
答案 9 :(得分:2)
我编写了Python类Code,它允许您向对象添加和删除新的代码行,打印代码并执行它。类代码最后显示。
示例:如果x == 1,则代码将其值更改为x = 2,然后使用检查该条件的条件删除整个块。
#Initialize Variables
x = 1
#Create Code
code = Code()
code + 'global x, code' #Adds a new Code instance code[0] with this line of code => internally code.subcode[0]
code + "if x == 1:" #Adds a new Code instance code[1] with this line of code => internally code.subcode[1]
code[1] + "x = 2" #Adds a new Code instance 0 under code[1] with this line of code => internally code.subcode[1].subcode[0]
code[1] + "del code[1]" #Adds a new Code instance 0 under code[1] with this line of code => internally code.subcode[1].subcode[1]
创建代码后,您可以打印它:
#Prints
print "Initial Code:"
print code
print "x = " + str(x)
输出:
Initial Code:
global x, code
if x == 1:
x = 2
del code[1]
x = 1
通过调用object:code()
来执行cadeprint "Code after execution:"
code() #Executes code
print code
print "x = " + str(x)
输出2:
Code after execution:
global x, code
x = 2
如您所见,代码将变量x更改为值2并删除整个if块。这可能有助于避免在满足条件后检查条件。在现实生活中,这种案例场景可以由协程系统处理,但这种自我修改代码实验只是为了好玩。
class Code:
def __init__(self,line = '',indent = -1):
if indent < -1:
raise NameError('Invalid {} indent'.format(indent))
self.strindent = ''
for i in xrange(indent):
self.strindent = ' ' + self.strindent
self.strsubindent = ' ' + self.strindent
self.line = line
self.subcode = []
self.indent = indent
def __add__(self,other):
if other.__class__ is str:
other_code = Code(other,self.indent+1)
self.subcode.append(other_code)
return self
elif other.__class__ is Code:
self.subcode.append(other)
return self
def __sub__(self,other):
if other.__class__ is str:
for code in self.subcode:
if code.line == other:
self.subcode.remove(code)
return self
elif other.__class__ is Code:
self.subcode.remove(other)
def __repr__(self):
rep = self.strindent + self.line + '\n'
for code in self.subcode: rep += code.__repr__()
return rep
def __call__(self):
print 'executing code'
exec(self.__repr__())
return self.__repr__()
def __getitem__(self,key):
if key.__class__ is str:
for code in self.subcode:
if code.line is key:
return code
elif key.__class__ is int:
return self.subcode[key]
def __delitem__(self,key):
if key.__class__ is str:
for i in range(len(self.subcode)):
code = self.subcode[i]
if code.line is key:
del self.subcode[i]
elif key.__class__ is int:
del self.subcode[key]
答案 10 :(得分:1)
您可以在Maple(计算机代数语言)中执行此操作。与上面的许多答案不同,这些答案使用的编译语言只允许您在运行时创建和链接新代码,在这里您可以诚实地改善当前正在运行的程序的代码。 (正如其他回答者所指出的那样,Ruby和Lisp也允许你这样做;也可能是Smalltalk)。
实际上,它曾经是Maple的标准,大多数库函数都是小存根,它们会在第一次调用时从磁盘加载它们的“真实”自身,然后自我修改自己到加载的版本。由于库加载已虚拟化,因此不再是这种情况。
正如其他人所指出的那样:你需要一种具有强烈反思和具体化设施的解释性语言来实现这一目标。
我为Maple代码编写了一个自动规范化器/简化器,我继续在整个库上运行(包括它自己);因为我在所有代码中都不太谨慎,所以规范化程序确实修改了自己。我还写了Partial Evaluator(最近被SCP接受)称为MapleMIX - available on sourceforge - 但是不能完全将它完全应用到自身(这不是设计目标)。
答案 11 :(得分:0)
你看过Java吗? Java 6有compiler API,因此您可以编写代码并在Java VM中编译它。
答案 12 :(得分:0)
在Lua中,您可以“挂钩”现有代码,这允许您将任意代码附加到函数调用。它是这样的:
local oldMyFunction = myFunction
myFunction = function(arg)
if arg.blah then return oldMyFunction(arg) end
else
--do whatever
end
end
您也可以简单地使用函数,这样可以自动修改代码。
答案 13 :(得分:0)
Dlang的LLVM实现包含@dynamicCompile和@dynamicCompileConst函数属性,使您可以在编译时根据本机主机的指令集进行编译,并在运行时通过重新编译更改编译时常量。
https://forum.dlang.org/thread/bskpxhrqyfkvaqzoospx@forum.dlang.org
答案 14 :(得分:-1)