web-dev-qa-db-ja.com

実装のためのチュートリアル/リソースVM

独学の目的で、動的言語用の単純な仮想マシンを実装したいのですが、Cを好みます。LuaVM、Parrot、またはPython VMですが、もっと単純です。良いリソースはありますか? /既存のVMのコードと設計ドキュメントを見る以外に、これを達成するためのチュートリアル?

編集:なぜ投票を閉じるのですか?わかりません-これはプログラミングではありません。私の質問に特定の問題がある場合はコメントしてください。

42
zaharpopov

単なるインタプリタではなく、仮想マシンが必要だと思います。それらは連続体の2つのポイントだと思います。インタプリタは、プログラムの元の表現に近いものに取り組みます。 A VMは、より原始的な(および自己完結型の)命令で機能します。これは、一方を他方に変換するためのコンパイル段階が必要であることを意味します。これで作業するかどうかはわかりません。最初に、または入力構文をまだ念頭に置いている場合。

動的言語の場合、データを(キーと値のペアとして)格納する場所と、それに作用するいくつかの操作が必要です。 VMはストアを維持します。ストアで実行されるプログラムは一連の命令(制御フローを含む)です。一連の命令を定義する必要があります。最初に簡単なセットをお勧めします。 、 お気に入り:

  • ストアへのアクセス、算術比較を含む基本的な算術演算
  • 基本的な制御フロー
  • ビルトインプリント

多くのVMと同様に、スタックベースの計算アプローチを使用して算術演算を行うことをお勧めします。上記ではまだあまりダイナミックではありません。そのためには、実行時に変数の名前を計算する機能(これは単に文字列操作を意味します)と、コードをデータとして扱う機能の2つが必要です。これは、関数参照を許可するのと同じくらい簡単かもしれません。

VMへの入力は、理想的にはバイトコードです。コンパイラをまだ持っていない場合、これは基本的なアセンブラ(VMの一部である可能性があります)から生成できます。

VM自体はループで構成されています:

1. Look at the bytecode instruction pointed to by the instruction pointer.
2. Execute the instruction:
   * If it's an arithmetic instruction, update the store accordingly.
   * If it's control flow, perform the test (if there is one) and set the instruction pointer.
   * If it's print, print a value from the store.
3. Advance the instruction pointer to the next instruction.
4. Repeat from 1.

計算された変数名の処理は難しい場合があります。命令は、計算された名前が含まれる変数を指定する必要があります。これは、入力で提供される文字列定数のプールを命令が参照できるようにすることで実行できます。

サンプルプログラム(アセンブリおよびバイトコード):

offset  bytecode (hex)   source
 0      01 05 0E         //      LOAD 5, .x
 3      01 03 10         // .l1: LOAD 3, .y
 6      02 0E 10 0E      //      ADD .x, .y, .x
10      03 0E            //      PRINT .x
12      04 03            //      GOTO .l1
14      78 00            //      .x: "x"
16      79 00            //      .y: "y"

暗黙の命令コードは次のとおりです。

"LOAD x, k" (01 x k) Load single byte x as an integer into variable named by string constant at offset k.
"ADD k1, k2, k3" (02 v1 v2 v3) Add two variables named by string constants k1 and k2 and put the sum in variable named by string constant k3.
"PRINT k" (03 k) Print variable named by string constant k.
"GOTO a" (04 a) Go to offset given by byte a.

変数が他の変数などによって名前が付けられている場合のバリアントが必要です(そして、間接参照のレベルは推論するのが難しいです)。アセンブラは、「ADD .x、.y、.x」のような引数を調べ、文字列定数(計算された変数ではない)から追加するための正しいバイトコードを生成します。

30
Edmund

ええと、それはCでVMを実装することではありませんが、この質問を見る前に開いた最後のタブだったので、 についての記事を指摘する必要があるように感じます表示に<canvas>タグを使用してJavaScriptでQBASICバイトコードコンパイラと仮想マシンを実装する これには、「ニブル」ゲームを実行するのに十分なQBASICを実装するためのすべてのソースコードが含まれています。コンパイラーとバイトコードインタープリターに関する一連の記事。これはVMについて説明しており、彼はコンパイラーについても説明する将来の記事を約束しています。

ちなみに、私はあなたの質問を閉じるために投票しませんでしたが、あなたが得た近い投票は、仮想マシンの実装について学ぶ方法についての 昨年からの質問 の複製でした。この質問(チュートリアルまたは比較的単純なものについて)は、開いたままにしておく必要がある質問とは十分に異なると思いますが、さらにアドバイスが必要な場合は、その質問を参照することをお勧めします。

9
Brian Campbell

注目すべきもう1つのリソースは、 Lua言語 の実装です。これはレジスタベースのVMで、パフォーマンスに定評があります。 ソースコード はANSI C89にあり、一般的に非常に読みやすくなっています。

ほとんどの高性能スクリプト言語と同様に、エンドユーザーには、読み取り可能で高レベルの動的言語が表示されます(クロージャ、テールコール、不変の文字列、数値、ハッシュテーブルなどの機能がプライマリデータタイプとして、関数がファーストクラスの値として機能します)。 。ソーステキストは、VM実装によって実行されるように、VMのバイトコードにコンパイルされます。そのアウトラインは、 Edmundの回答 で説明されているとおりです。

VM自体の実装を移植可能かつ効率的に保つために多大な努力が払われました。さらに高いパフォーマンスが必要な場合は、 ジャストインタイムコンパイラ from = VMネイティブ命令へのバイトコードは32ビットx86に存在し、64ビットのベータリリースです。

4
RBerteig

開始用(そうでなくても[〜#〜] c [〜#〜]、ただしC++muParser を見てください。

これは、simple仮想マシンを使用して操作を実行する数式パーサーです。あなたもすべてを理解するのに時間が必要だと思います。とにかく、このコードは完全なVMreal完全なプログラムを実行できるよりも単純です。(ちなみに、私は-を設計しています similar lib in C#-これは初期段階ですが、次のバージョンでは.NET/VM ILまたは新しい単純なVM muParserのように)。

もう1つの興味深い点は、 NekoVM (。nバイトコードファイルを実行する)です。これはオープンソースプロジェクトです Cで書かれています そしてその主要言語(.neko)は ソースからソースへのコンパイラ テクノロジーによって生成されると考えられています。最後のトピックの精神で、同じ著者からの Haxe を参照してください(オープンソースも)。

2
gsscoder

あなたと同じように、私も仮想マシンとコンパイラを研究してきました。私がお勧めできる良い本の1つは、 コンパイラの設計:仮想マシン です。命令型、機能型、ロジック、およびオブジェクト指向言語の仮想マシンについて、各VM)の命令セットと、そのVMに高級言語をコンパイルする方法のチュートリアルを提供することで説明します。命令型言語用にVM)を実装しただけで、すでに非常に便利な演習になっています。

始めたばかりの場合、私がお勧めできる別のリソースは PL101 です。これは、さまざまな言語のパーサーとインタープリターを実装するプロセスをガイドするJavaScriptのインタラクティブなレッスンセットです。

1
David K.