35
  • 私は最近、自己修正プログラムを書くことを考えています。それは強力で楽しいかもしれないと思います。そのため、現在、プログラム自体のコードを簡単に変更できる言語を探しています。
  • C# (回避策として) と実行時にコードをコンパイルして実行する機能について読みましたが、それはあまりにも苦痛です。
  • 組み立ても考えています。実行中のコードを変更する方が簡単ですが、それほど強力ではありません (非常に生)。

実行時のコード変更をサポートする強力な言語または機能を提案できますか?

これが、実行時にコードを変更するという意味です。

  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();
4

14 に答える 14

48

Malbolgeは、開始するのに適した場所です。すべての命令は自己修正型で、とても楽しい (*) 遊びです。

(*) 免責事項: 実際には面白くないかもしれません。

于 2010-06-16T22:00:55.307 に答える
23

Lispを強くお勧めします。Lisp データは、コードとして読み取り、実行できます。Lisp コードはデータとして書き出すことができます。

標準的な自己変更可能言語の 1 つと見なされます。

例のリスト (データ):

'(+ 1 2 3) 

または、データをコードとして呼び出す

(eval '(+ 1 2 3)) 

+ 関数を実行します。

その場でリストのメンバーに入って編集することもできます。

編集:

プログラムを動的に生成してその場で評価し、ベースラインと比較してどのようになったかを報告するプログラムを作成しました(0によるdivは通常のレポートでした.ha)。

于 2010-06-16T22:28:01.947 に答える
16

これまでのすべての回答はリフレクション/ランタイム コンパイルに関するものですが、あなたが言及したコメントでは、実際の自己変更コード(メモリ内で自分自身を変更するコード) に関心があります。

これを C#、Java、または (移植可能に) C で行う方法はありません。つまり、これらの言語を使用してロードされたメモリ内バイナリを変更することはできません。

一般に、これを行う唯一の方法はアセンブリを使用することであり、プロセッサに大きく依存します。実際、これはオペレーティング システムにも大きく依存しています。ポリモーフィック ウイルスから保護するために、ほとんどの最新のオペレーティング システム(Windows XP+、Linux、および BSD を含む) はW^Xを強制します。それらのオペレーティングシステム、それをまったく許可するもののために。

一部のインタープリター言語では、実行中にプログラムが独自のソース コードを変更する可能性があります。ただし、Perl、Python (こちらを参照)、および私が知っている Javascript のすべての実装では、これが許可されていません。

于 2010-06-16T22:51:52.307 に答える
10

Pythonを提案してもよろしいですか。これは、豊富なイントロスペクションが組み込まれている、非常に高度な動的言語です (たとえば、 の使用によってcompileevalまたは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では、​​関数スコープでのみ変更されていることに注意してください。

于 2010-06-16T22:16:39.667 に答える
10

個人的には、アセンブリが C# よりも扱いやすいと思うのは非常に奇妙です。アセンブリはそれほど強力ではないとあなたが考えているのは、さらに奇妙なことです。生の機械語よりも強力になることはありません。とにかく、それぞれに。

C# には優れたリフレクション サービスがありますが、それを嫌う場合は.. C または C++ に慣れている場合は、C/C++ を記述してコンパイラに発行するプログラムをいつでも作成できます。これは、ソリューションが迅速な自己書き換えターンアラウンド タイム (数十秒以上) を必要としない場合にのみ実行可能です。

Javascript と Python はどちらもリフレクションもサポートしています。強力でありながら技術的な要求がそれほど高くない新しい楽しいプログラミング言語を学習することを考えている場合は、Python をお勧めします。

于 2010-06-16T22:06:49.267 に答える
9

Common Lispは、この種のことを念頭に置いて設計されました。リフレクションを使用して実行中のコードを変更することが未知ではないSmalltalkを試すこともできます

どちらの言語でも、1 行のコードではなく、関数全体またはメソッド全体を置き換える可能性があります。Smalltalk メソッドは Lisp 関数よりも粒度が細かい傾向があるため、そこから始めるのがよいでしょう。

于 2010-06-16T22:40:22.523 に答える
7

多くの言語では、実行時にコードを評価できます。

  • 舌足らずの発音
  • パール
  • パイソン
  • PHP
  • ルビー
  • Groovy (GroovyShell 経由)
于 2010-06-16T22:28:01.027 に答える
4

実行時にコードをコンパイルして実行する高水準言語では、実際には自己変更コードではなく、動的なクラスの読み込みです。継承の原則を使用して、クラス Factory を置き換え、実行時にアプリケーションの動作を変更できます。

アセンブリ言語でのみ、コード セグメントに直接書き込むことによって、実際に真の自己変更を行うことができます。しかし、実用的な使い方はほとんどありません。挑戦したい場合は、自己暗号化型のポリモーフィック ウイルスを作成してください。楽しそう。

于 2010-06-16T22:47:17.070 に答える
3

Ruby で自己変更コードを実行することはめったにありませんがときどきあります。

使用しているデータ (遅延キャッシュなど) が適切に初期化されているかどうかがよくわからないメソッドがある場合があります。したがって、メソッドの開始時にデータが適切に初期化されているかどうかを確認してから、初期化する必要があります。ただし、実際にはその初期化を 1 回だけ行う必要がありますが、毎回確認します。

そのため、初期化を行い、それ自体を初期化コードを含まないバージョンに置き換えるメソッドを作成することがあります。

class Cache
  def [](key)
    @backing_store ||= self.expensive_initialization

    def [](key)
      @backing_store[key]
    end

    @backing_store[key]
  end
end

しかし、正直なところ、それだけの価値はないと思います。実際、恥ずかしいことに、その1 つの条件が実際に違いを生むかどうかを実際にベンチマークしたことはありません。(積極的に最適化するプロファイル フィードバック駆動型の JIT コンパイラを使用した最新の Ruby 実装では、おそらくそうではありません。)

「自己変更コード」をどのように定義するかによって、これが必要な場合とそうでない場合があることに注意してください。現在実行中のプログラムの一部を置き換えるので、…</p>

編集:考えてみると、その最適化はあまり意味がありません。とにかく、高価な初期化は一度だけ実行されます。変更によって回避される唯一のことは、条件付きです。小切手自体が高価な例を挙げたほうがいいのですが、思いつきません。

しかし、私は自己変更コードのクールな例を考えました: Maxine JVMです。Maxine は、完全に Java で記述された Research VM (開発者が互換性テストスイートを実行しないため、実際に「JVM」と呼ぶことは技術的に許可されていません) です。現在、それ自体で書かれた JVM はたくさんありますが、Maxine は、それ自体で動作することを私が知っている唯一のものです。これは非常に強力です。たとえば、JIT コンパイラは、それ自体を JIT コンパイルして、JIT コンパイルするコードのタイプに適合させることができます。

自己プログラミング言語用の VM であるKlein VMでも、非常によく似たことが起こります。

どちらの場合も、VM は実行時にそれ自体を最適化し、再コンパイルできます。

于 2010-06-16T23:30:30.033 に答える
1

これは、Maple (コンピューター代数言語) で行うことができます。実行時に新しいコードを作成してリンクすることしかできないコンパイル済み言語を使用する上記の多くの回答とは異なり、ここでは、現在実行中のプログラムのコードを正直に変更できます。(他の回答者が示しているように、RubyとLispでもこれを行うことができます。おそらくSmalltalkもそうです)。

実際、ほとんどのライブラリ関数は小さなスタブであり、最初の呼び出しでディスクから「実際の」自己をロードし、ロードされたバージョンに自身を自己変更することが Maple の標準でした。ライブラリのロードが仮想化されたため、これはもはや当てはまりません。

他の人が指摘しているように、これを達成するには、強力なリフレクションと具体化機能を備えたインタープリター言語が必要です。

Maple コード用の自動化されたノーマライザー/シンプリファイアーを作成し、ライブラリ全体 (それ自体を含む) で実行しました。また、すべてのコードであまり注意を払っていなかったため、ノーマライザーは自分自身を変更しました。私はまた、MapleMIXと呼ばれる (最近 SCP によって受け入れられた)部分評価器 (sourceforge で入手可能) を書きましたが、それ自体に完全に適用することはできませんでした (それは設計目標ではありませんでした)。

于 2010-06-17T00:28:56.023 に答える
0

Luaでは、既存のコードを「フック」することができます。これにより、関数呼び出しに任意のコードを添付できます。これは次のようになります。

local oldMyFunction = myFunction
myFunction = function(arg)
    if arg.blah then return oldMyFunction(arg) end
    else
        --do whatever
    end
end

また、関数を単純に耕すことができます。これにより、自己変更コードが得られます。

于 2010-06-19T02:19:01.140 に答える
0

Javaを見たことがありますか?Java 6 にはコンパイラ APIがあるため、コードを記述して Java VM 内でコンパイルできます。

于 2010-06-16T22:01:58.613 に答える
0

Dlang の LLVM 実装には @dynamicCompile および @dynamicCompileConst 関数属性が含まれているため、コンパイル時にネイティブ ホストの命令セットに従ってコンパイルし、再コンパイルによって実行時にコンパイル時の定数を変更できます。

https://forum.dlang.org/thread/bskpxhrqyfkvaqzoospx@forum.dlang.org

于 2019-09-05T22:58:43.997 に答える