Interpreter (computing)

Software that executes encoded logic
W3sDesign Interpreter Design Pattern UML

In computing, an interpreter is software that executes source code without first compiling it to machine code. An interpreted runtime environment differs from one that processes CPU-native executable code which requires translating source code before executing it. An interpreter may translate the source code to an intermediate format, such as bytecode. A hybrid environment may translate the bytecode to machine code via just-in-time compilation, as in the case of .NET and Java, instead of interpreting the bytecode directly.

Before the widespread adoption of interpreters, the execution of computer programs often relied on compilers, which translate and compile source code into machine code. Early runtime environments for Lisp and BASIC could parse source code directly. Thereafter, runtime environments were developed for languages (such as Perl, Raku, Python, MATLAB, and Ruby), which translated source code into an intermediate format before executing to enhance runtime performance.

インタプリタで実行されるコードは、互換性のあるインタプリタを持つあらゆるプラットフォームで実行できます。プラットフォームごとに実行ファイルをビルドする必要はなく、同じコードをあらゆるプラットフォームに配布できます。各プログラミング言語は通常、特定の実行環境に関連付けられていますが、言語は異なる環境で使用できます。ALGOL FortranCOBOLCC++など、従来はコンパイルを伴う言語向けにインタプリタが構築されています

歴史

コンピュータの黎明期には、当時のハードウェアはインタープリタと解釈されたコードの両方をサポートできず、当時の典型的なバッチ環境ではインタープリタの利点が制限されていたため、インタープリタよりもコンパイラの方が一般的に見られ、使用されていました。[1]

インタプリタは、1952年という早い時期から、当時のコンピュータの限界(プログラム記憶領域の不足、浮動小数点数のネイティブサポートの欠如など)の中でプログラミングを容易にするために使用されていました。また、インタプリタは低水準機械語間の翻訳にも使用され、開発中のマシン向けにコードを記述し、既存のコンピュータでテストすることが可能になりました。[2]最初のインタプリタ型高水準言語はLispです。Lispは、 Steve RussellによってIBM 704コンピュータ上で初めて実装されました。RussellはJohn McCarthyの論文「Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I」を読み、Lispのeval関数を機械語で実装できることに(McCarthy自身も驚きましたが)気づきました。[3]その結果、Lispプログラムを実行できる、より正確には「Lisp式を評価」できるLispインタプリタが完成しました。

編集インタープリタの開発は、対話型コンピューティングのニーズに影響を受けました。1960年代には、タイムシェアリングシステムの導入により、複数のユーザーが同時にコンピュータにアクセスできるようになり、編集インタープリタはリアルタイムでのコード管理と変更に不可欠なものとなりました。最初の編集インタープリタは、メインフレームコンピュータ向けに開発されたと考えられており、プログラムをリアルタイムで作成・変更するために使用されていました。編集インタープリタの最も初期の例の一つは、1960年代後半にPDP-1コンピュータ向けに開発されたEDT(Editor and Debugger for the TECO)システムです。EDTは、コマンドとマクロを組み合わせてプログラムを編集・デバッグすることを可能にし、現代のテキストエディタや対話型開発環境への道を開きました。[要出典]

使用

通訳の注目すべき用途には以下が含まれます

コマンドとスクリプト
インタプリタは、コマンドスクリプトの実行に頻繁に使用されます
仮想化
インタプリタは仮想マシンとして機能し、インタプリタを実行しているハードウェアアーキテクチャとは異なるハードウェアアーキテクチャのマシンコードを実行します
エミュレーション
インタプリタ(仮想マシン)は、別のコンピュータシステムをエミュレートして、そのシステム用に記述されたコードを実行できます
サンドボックス
一部の種類のサンドボックスはオペレーティングシステムの保護に依存していますが、インタープリタ(仮想マシン)は、セキュリティルールに違反するコードをブロックするなどの追加の制御を提供できます。[要出典]
自己書き換えコード
自己書き換えコードはインタープリタ型言語で実装できます。これは、Lispと人工知能研究におけるインタープリタの起源に関連しています[要出典]

効率

解釈オーバーヘッドとは、ネイティブ(コンパイル済み)コードではなく、インタープリタを介してコードを実行する際の実行時コストです。インタープリタはネイティブコード内の同等の機能に対して複数のマシンコード命令を実行するため、解釈は遅くなります。特に、インタープリタでは変数へのアクセスが遅くなります。これは、識別子から記憶域へのマッピングをコンパイル時ではなく実行時に繰り返し行う必要があるためです [ 4]しかし、編集、ビルド、実行サイクルの短縮などの要因により、開発速度が速くなると、実行速度の速さの価値を上回る可能性があります。特に、編集、ビルド、実行サイクルが頻繁に行われるプロトタイプ作成やテストでは、その傾向が顕著です。[4] [5]

インタプリタは、高速な実行性能といった目標を達成するために、ソースコードからプログラムの中間表現(IR)を生成することがあります。コンパイラもIRを生成することがありますが、コンパイラは後で実行するための機械語を生成するのに対し、インタプリタはプログラムを実行する準備をします。これらの異なる目的により、IRの設計は異なります。多くのBASICインタプリタは、キーワードを1バイトの トークン置き換え、ジャンプテーブルで命令を見つけるのに使用します[4] PBASICインタプリタなどの一部のインタプリタは、バイト指向ではなくビット指向のプログラムメモリ構造を使用することで、さらに高度なプログラム圧縮を実現しています。この場合、コマンドトークンはおそらく5ビットを占有し、名目上は「16ビット」の定数は3、6、10、または18ビットを必要とする可変長コードに格納され、アドレスオペランドには「ビットオフセット」が含まれます。多くのBASICインタプリタは、独自のトークン化された内部表現を保存し、読み出すことができます。

インタプリタを用いた開発速度とコンパイラを用いた実行速度の間には、様々な妥協点があります。一部のシステム(一部のLispなど)では、インタプリタで実行されたコードとコンパイルされたコードが相互に呼び出し、変数を共有できます。つまり、あるルーチンをインタプリタでテストおよびデバッグした後は、コンパイルして他のルーチンを開発している間に実行速度を向上することができます。[要出典]

実装

解釈とコンパイルの初期段階は似ているため、インタプリタはコンパイラと同じ字句解析器パーサを使用し、結果として得られる抽象構文木を解釈する 場合があります

C++で書かれ た式インタープリタ

stdをインポートします 

std :: runtime_errorを使用します。std :: unique_ptrを使用します。std :: variant使用します 
 
 

// 抽象構文ツリーのデータ型
enumクラスKind : char { VAR CONST SUM DIFF MULT DIV PLUS MINUS NOT };     
     
     
     
     
     
     
     
     
     


// 前方宣言
クラスNode ; 

クラス変数{ public : int *メモリ; };   

      


クラス定数{ public : int; };  

      


クラスUnaryOperation { public : unique_ptr < Node > right ; };  

      


クラスBinaryOperation { public : unique_ptr < Node > left ; unique_ptr < Node > right ; };   

     
     


Expression = variant < Variable , Constant , BinaryOperation , UnaryOperation >を使用します      

クラスNode { public : Kind kind ;e ; };  

     
     


// インタープリター手順
[[ nodiscard ]] 
int executeIntExpression ( const Node & n ) { int leftValue ; int rightValue ; switch ( n -> kind ) { case Kind :: VAR : return std :: get < Variable > ( n . e ). memory ; case Kind :: CONST : return std :: get < Constant > ( n . e ). value ; case Kind :: SUM : case Kind :: DIFF : case Kind :: MULT : case Kind :: DIV : const BinaryOperation & bin = std :: get < BinaryOperation > ( n . e ); leftValue = executeIntExpression ( bin . left . get ()); rightValue = executeIntExpression ( bin . right . get ()); switch ( n . kind ) { case Kind :: SUM : return leftValue + rightValue ; case Kind :: DIFF : return leftValue - rightValue ; case Kind :: MULT : return leftValue * rightValue ; case Kind :: DIV : if ( rightValue == 0 ) { throw runtime_error ( "ゼロ除算" ); } return leftValue / rightValue    
     
     
      
         
             
         
             
         
         
         
         
                
              
              
              
                  
                       
                  
                       
                  
                       
                  
                        
                         
                    
                       ; 
} case Kind :: PLUS : case Kind :: MINUS : case Kind :: NOT : const UnaryOperation & un = std :: get < UnaryOperation > ( n . e ); rightValue = executeIntExpression ( un . right . get ()); switch ( n . kind ) { case Kind :: PLUS : return + rightValue ; case Kind :: MINUS : return - rightValue ; case Kind :: NOT : return ! rightValue ; } default : std :: unreachable (); } }            
          
          
         
                
              
              
                 
                     
                 
                     
                  
                     
            
         
            
    

ジャストインタイムコンパイル

ジャストインタイム(JIT)コンパイルとは、実行時に中間形式(バイトコードなど)をネイティブコードに変換するプロセスです。これによりネイティブコードが実行されるため、インタープリタを使用する際の実行時コストを回避しながら、インタープリタ開発につながる利点の一部を維持する方法です

バリエーション

制御表インタープリター
ロジックは表形式のデータとして指定されます
バイトコードインタプリタ
一部のインタプリタは、高水準言語からコンパイルされたロジックの中間形式であるバイトコードを処理します。例えば、 Emacs Lispはバイトコードにコンパイルされ、インタプリタによって解釈されます。このコンパイルされたコードは、インタプリタによって実装された仮想マシンのマシンコードであると言えるでしょう。このようなインタプリタは、コンプレタと呼ばれることもあります。[6] [7]
スレッドコードインタープリター
スレッドコードインタープリタはバイトコードインタープリタに似ていますが、バイトではなくポインタを使用します。各命令は関数または命令シーケンスを指すワードであり、パラメータが続く場合もあります。スレッドコードインタープリタは、命令をフェッチしてそれらが指す関数を呼び出すループを実行するか、最初の命令をフェッチしてそこにジャンプします。すべての命令シーケンスは、フェッチと次の命令へのジャンプで終了します。スレッドコードの一例として、Open Firmwareシステムで使用されるForthコードが挙げられます。ソース言語は「Fコード」(バイトコード)にコンパイルされ、仮想マシンによって解釈されます。[要出典]
抽象構文木インタープリタ
抽象構文木インタープリタは、ソースコードを抽象構文木(AST)に変換し、それを直接解釈するか、JITコンパイルによってネイティブコードを生成する。[8]このアプローチでは、各文は一度だけ解析する必要がある。バイトコードに対する利点として、ASTはグローバルなプログラム構造と文間の関係(バイトコード表現では失われる)を維持し、圧縮するとよりコンパクトな表現を提供する。[9]そのため、ASTの使用はバイトコードよりも優れた中間形式として提案されている。しかし、インタープリタにとって、ASTはバイトコードインタープリタよりもオーバーヘッドが大きい。これは、構文に関連するノードが役に立たないこと、表現が連続的でないこと(より多くのポインタのトラバーサルが必要)、そしてツリーを参照するオーバーヘッドのせいである。[10]
テンプレートインタープリター
テンプレートインタープリタは、ソフトウェアスタックやツリーウォーク上で動作しながら、あらゆるバイトコードを含む巨大なswitch文によってコード実行を実装するのではなく、対応するネイティブマシン命令に直接マッピングされたバイトコード(または効率的な中間表現)の大規模な配列を保持します。これらの命令は、ホストハードウェア上でキーと値のペア(またはより効率的な設計では、ネイティブ命令への直接アドレス)として実行できます。 [11] [12]これは「テンプレート」と呼ばれます。特定のコードセグメントが実行されると、インタープリタはテンプレート内のオペコードマッピングをロードまたはジャンプし、ハードウェア上で直接実行します。[13] [14]テンプレートインタープリタは、その設計上、従来のインタープリタというよりもJITコンパイラに非常によく似ています。しかし、コードセグメント全体から最適化されたCPU実行可能命令シーケンスを作成するのではなく、言語のコードを1オペコードずつネイティブ呼び出しに変換するだけなので、技術的にはJITではありません。インタプリタは、呼び出しを直接実装するのではなく、ハードウェアに直接渡すというシンプルな設計のため、バイトコードインタプリタを含む他のどのタイプよりもはるかに高速で、ある程度バグが発生しにくいですが、プラットフォームに依存しない仮想マシン/スタックではなく、複数の異なるアーキテクチャへの変換をサポートする必要があるため、トレードオフを維持するのが難しくなります。現在までに、広く知られている言語のテンプレートインタプリタ実装は、Javaの公式リファレンス実装であるSun HotSpot Java仮想マシン内のインタプリタ[11]と、Google V8 JavaScript実行エンジンのIgnitionインタプリタのみです。
マイクロコード
マイクロコードは、低レベルの機械語で機械語を実装するハードウェアインタープリタとして抽象化層を提供します。[15]マイクロコードは、高レベルの機械語命令を基盤となる電子回路から分離することで、高レベルの命令をより自由に設計および変更できるようにします。また、複雑なマルチステップ命令の提供を容易にし、コンピュータ回路の複雑さを軽減します。

参照

参考文献

  1. ^ 「なぜ最初のコンパイラは最初のインタープリタよりも先に書かれたのか?」Ars Technica、2014年11月8日。 2014年11月9日閲覧
  2. ^ Bennett, JM; Prinz, DG; Woods, ML (1952). 「解釈的サブルーチン」. ACM National Conference Proceedings, Toronto .
  3. ^ ポール・グラハム Hackers & Painters』 185ページによると、マッカーシーは次のように述べている。「スティーブ・ラッセルが、『なあ、このevalをプログラムしてみろよ』と言ったので、私は『おいおい、理論と実践を取り違えているじゃないか。このevalは読むためのものであって、計算のためのものではない』と言った。しかし、彼はそれを実行した。つまり、私の論文のevalをIBM 704のマシンコードにコンパイルし、バグを修正した後、これをLispインタープリタとして宣伝したのだ。実際、LispはLispインタープリタだった。つまり、この時点でLispは基本的に今日の形になっていたのだ。」
  4. ^ abcこの記事は、2008年11月1日より前に Free On-line Dictionary of ComputingのInterpreterから取得した資料に基づいており、 GFDLバージョン1.3以降 の「再ライセンス」条項に基づいて組み込まれています。
  5. ^ 「コンパイラとインタープリタ:説明と違い」IONOSデジタルガイド。 2022年9月16日閲覧
  6. ^ クラウス、キューネル (1987) [1986]. 「4. クラインコンピュータ - 固有シャフトとモーグリヒカイテン」 [4.マイクロコンピュータ - 特性と可能性]。ライナーのエルレカンフにて。メンク、ハンス=ヨアヒム(編)。Mikroelektronik in der Amapraxis [実用的なアマチュアのためのマイクロエレクトロニクス] (ドイツ語) (第 3 版)。ベルリン: Militärverlag der Deutschen Demokratischen Republik  [de]、ライプツィヒ。 p. 222.ISBN 3-327-00357-2. 7469332.
  7. ^ ハイン、R. (1984)。 「Basic-Compreter für U880」 [U880 (Z80) 用 BASIC コンプリッター]。radio-fernsehn-elektronik  [de] (ドイツ語)。1984 (3): 150–152
  8. ^ AST中間表現、Lambda the Ultimateフォーラム
  9. ^ Kistler, Thomas; Franz, Michael (1999年2月). 「Javaバイトコードのツリーベースの代替」(PDF) . International Journal of Parallel Programming . 27 (1): 21– 33. CiteSeerX 10.1.1.87.2257 . doi :10.1023/A:1018740018601. ISSN  0885-7458. S2CID  14330985. 2020年12月20日閲覧. 
  10. ^ Surfin' Safari - Blog Archive » Announcement SquirrelFish. Webkit.org (2008-06-02). 2013年8月10日閲覧。
  11. ^ ab "openjdk/jdk". GitHub。 2021年11月18日。
  12. ^ 「HotSpotランタイムの概要」。Openjdk.java.net 。 2022年8月6日閲覧
  13. ^ 「JVM の謎を解明する: JVM バリアント、Cppinterpreter および TemplateInterpreter」。metebalci.com
  14. ^ 「JVMテンプレートインタープリター」。ProgrammerSought
  15. ^ ケント、アレン、ウィリアムズ、ジェームズ・G.(1993年4月5日)。『コンピュータサイエンスとテクノロジー百科事典:第28巻 補足13』ニューヨーク:マルセル・デッカー社ISBN 0-8247-2281-720161月17日閲覧

出典

  • Aycock, J. (2003年6月). 「ジャストインタイムの簡潔な歴史」. ACM Computing Surveys . 35 (2): 97– 113. CiteSeerX  10.1.1.97.3985 . doi :10.1145/857076.857077. S2CID  15345671.
  • コロンビア大学のIBMカードインタープリタページ
  • 実践的な「完全関数型プログラミング」の理論的基礎(特に第7章)インタプリタとは何かを形式化する問題に取り組んだ博士論文
Retrieved from "https://en.wikipedia.org/w/index.php?title=Interpreter_(computing)&oldid=1324631384"