一部のプログラミング言語では、eval(英語のevaluateの略)は、文字列を言語の式であるかのように評価し、結果を返す関数です。他の言語では、 を含む行の代わりに複数行のコードが含まれているかのように、それらを実行します。 への入力は必ずしも文字列である必要はありません。抽象構文木(Lispフォームなど)などのコードの構造化表現、または (Pythonの場合)などの特殊な型の場合もあります。文に相当するのはexecで、これは文字列(または他の形式のコード)を文であるかのように実行します。Pythonなどの一部の言語では両方が存在しますが、他の言語ではまたはのいずれか一方のみが存在します。
evalevalcodeevalexec
セキュリティリスク
信頼できないソースからのデータを使用するとeval、セキュリティ上の脆弱性が生じる可能性があります。たとえば、get_data()関数がインターネットからデータを取得すると仮定すると、次のPythonコードは安全ではありません。
セッション[ 'authenticated' ] = False
データ = get_data ()
foo = eval ( data )
攻撃者は、文字列をデータとしてプログラムに提供し"session.update(authenticated=True)"、session辞書を更新して認証キーを True に設定する可能性があります。これを解決するには、使用されるすべてのデータをevalエスケープするか、潜在的に有害な機能にアクセスせずに実行する必要があります。
実装
インタプリタ言語では、evalはほとんどの場合、通常のコードと同じインタプリタで実装されます。コンパイル言語では、プログラムのコンパイルに使用されたのと同じコンパイラが、 関数を使用するプログラムに埋め込まれることがありますeval。別のインタプリタが使用されることもありますが、これによりコードが重複します。
プログラミング言語
ECMAスクリプト
JavaScript
JavaScriptでは、はeval式評価子とステートメント実行子のハイブリッドのようなものです。最後に評価された式の結果を返します。
式評価子としての例:
foo = 2 ;アラート( eval ( 'foo + 2' ));
ステートメントエグゼキュータとしての例:
foo = 2 ; eval ( 'foo = foo + 2;alert(foo);' );
JavaScript の用途の 1 つは、おそらくAjaxフレームワークの一部としてJSONevalテキストを解析することです。ただし、最新のブラウザでは、このタスクに対してより安全な代替手段が提供されています。
JSON.parse
アクションスクリプト
ActionScript (Flash のプログラミング言語)では、eval任意の式を評価するために使用することはできません。Flash 8 のドキュメントによると、その使用は「取得する変数、プロパティ、オブジェクト、またはムービー クリップの名前を表す式に限定されます。このパラメータは、文字列またはオブジェクト インスタンスへの直接参照のいずれかになります。」[1]
ActionScript 3 は eval をサポートしていません。
ActionScript 3 Evalライブラリ[2]とD.eval API [3]evalは、ActionScript 3で同等のものを作成するための開発プロジェクトでした。Adobe Flash Playerのサポートが終了したため、両方とも終了しました。
リスプ
Lisp は1958 年に関数を利用した最初の言語でした。eval実際、eval関数の定義は言語インタープリタの最初の実装につながりました。[4]eval関数が定義される
前は、Lisp 関数はアセンブリ言語ステートメントに手動でコンパイルされていました。しかし、関数が手動でコンパイルされると、それは最初の Lisp インタープリタの基礎となった
単純な読み取り、評価、印刷のループevalの一部として使用されました。
Lispeval関数の後のバージョンもコンパイラとして実装されています。
Lisp の関数evalは、フォームが引数として評価されることを想定しています。指定されたフォームの結果の値は、 の呼び出しの戻り値になりますeval。
これは Lisp コードの例です。
; 1、2、3 を引数として + 関数を呼び出すフォーム。
; 6 を返します。
( + 1 2 3 ) ; Lisp ではどのフォームも評価されることが想定されているため、; + の呼び出しが実行されました。; フォームの前に "'" を付けることで、Lisp がフォームを評価しないようにすることができます。たとえば、次のようになります。 ( setq form1 ' ( + 1 2 3 )) ; これで、form1 には eval で使用できるフォームが含まれます。たとえば、次のようになります。( eval form1 ) ; eval は (+ 1 2 3) を評価し、6 を返しました。
Lisp は非常に柔軟であることでよく知られていますが、関数も同様ですeval。たとえば、文字列の内容を評価するには、まず関数を使用して文字列を Lisp 形式に変換しread-from-string、その結果の形式を に渡す必要がありますeval。
( eval (文字列からの読み取り"(format t \"Hello World!!!~%\")" ))
混乱を招く大きなポイントの 1 つは、フォーム内のシンボルがどのコンテキストで評価されるかという点です。上記の例では、 にはform1シンボル が含まれています+。このシンボルを評価すると、例が意図したとおりに動作するためには、関数 の加算が生成される必要があります。したがって、Lisp の一部の方言ではeval、評価のコンテキストを指定するために の追加パラメータが許可されます (Python の関数のオプション引数と同様- 以下を参照)。Lisp のScheme方言 (R 5 RS 以降)
evalの例:
;; 上記の例のように簡単なフォームを定義します。
( define form2 ' ( + 5 2 )) ;値: form2
;; 初期コンテキスト内でフォームを評価します。
;; 評価のコンテキストは、Scheme の用語では「環境」と呼ばれます。
( eval form2 user-initial-environment ) ;値: 7
;; 初期環境を混乱させて、
減算関数の名前を + にします。
( environment-define user-initial-environment '+ - ) ;値: +
;; フォームを再度評価します。
;; 返された値が変更されていることに注意してください。
( eval form2 user-initial-environment ) ;値: 3
パール
Perlでは、このeval関数は式評価機能と文実行機能のハイブリッドのようなものです。最後に評価された式の結果を返します (Perl プログラミングではすべての文が式です)。最後のセミコロンを省略できます。
式評価子としての例:
$foo = 2 ; eval ( '$foo + 2' )、"\n"を出力します。
ステートメントエグゼキュータとしての例:
$foo = 2 ; eval ( '$foo += 2; print "$foo\n";' );
Perl には例外処理メカニズムとして機能するeval ブロックもあります(例外処理構文#Perlを参照)。これは、ブロック内のコードは実行時ではなくコンパイル時に解釈される点で、上記の文字列でのの使用とは異なります。したがって、この記事で使用されている
の意味ではありません。evalevaleval
PHP の
PHPでは、evalの呼び出しではなく、ファイルに記述されている場合とほぼ同じように、文字列内のコードが実行されますeval()。唯一の例外は、エラーが の呼び出しから発生したものとして報告されeval()、 return ステートメントが関数の結果になることです。
一部の言語とは異なり、 の引数はeval単なる式ではなく、1 つ以上の完全なステートメントの文字列である必要があります。ただし、eval式を return ステートメントに配置することで、 の「式」形式を取得できます。これにより、 はevalその式の結果を返します。
一部の言語とは異なり、PHP はeval関数ではなく「言語構造」であるため、[5]、高階関数などの関数が使用できるコンテキストでは使用できません。
echo を使用した例:
<?php
$foo = "Hello, world! \n " ;
eval ( 'echo "$foo";' );
?>
値を返す例:
<?php
$foo = "さようなら、世界!\n " ; //PHP5 では動作しません
echo eval ( 'return $foo;' );
?>
ルア
Lua 5.1では、 loadstringLua コードを匿名関数にコンパイルします。
式評価子としての例:
loadstring ( "print('Hello World!')" )()
2 つのステップで評価を行う例:
a = 1
f = loadstring ( "return a + 1" ) -- 式を匿名関数にコンパイルします
print ( f ()) -- 実行します (結果 '2' を出力します)
Lua 5.2 では、文字列を受け入れるように拡張されたloadstring既存のload関数が推奨されなくなりました。さらに、環境がアップバリューになったため、関数の環境を直接提供できるようになりました。
ロード( "print('Hello ' .. a)" 、 "" 、 "t" 、 { a = "World!" 、 print = print })()
ポストスクリプト
PostScriptのexec演算子はオペランドを受け取ります。オペランドが単純なリテラルである場合は、それをスタックに戻します。ただし、PostScript 式を含む文字列を受け取る場合は、その文字列を実行可能ファイルに変換して、インタープリタで実行することができます。例:
((こんにちは世界) =) cvx exec
PostScript式を変換する
(こんにちは世界) =
これは、文字列「Hello World」をスタックからポップし、実行可能タイプとして画面に表示してから実行されます。
PostScript のrun演算子は機能的には似ていますが、インタープリターがファイル内の PostScript 式自体を解釈します。
(file.ps)実行
パイソン
Pythonでは、eval最も単純な形式の関数は単一の式を評価します。
eval例 (対話型シェル):
>>> x = 1
>>> eval ( 'x + 1' )
2
>>> eval ( 'x' )
1
このeval関数は 2 つのオプション引数globalとを取りますlocals。これにより、プログラマーは式の評価のための制限された環境を設定できます。
ステートメントexec(またはexecPython 3.x では関数) は、次のステートメントを実行します。
exec例 (対話型シェル):
>>> x = 1
>>> y = 1
>>> exec "x += 1; y -= 1"
>>> x
2
>>> y
0
ステートメント/式を評価する最も一般的な形式は、コード オブジェクトを使用することです。これらは、関数を呼び出してcompile()、コンパイルする入力の種類 (" exec" ステートメント、" eval" ステートメント、または " single" ステートメント) を指示することで作成できます。
compile例 (対話型シェル):
>>> x = 1
>>> y = 2
>>> eval ( compile ( "print 'x + y = ', x + y" , "compile-sample.py" , "single" ))
x + y = 3
だ
D はeval静的にコンパイルされる言語であるため、従来の意味での" " ステートメントは含まれませんが、関連する " mixin" ステートメントは含まれます。違いは、 " eval" が実行時に文字列をコードとして解釈するのに対し、 " mixin" では文字列が通常のコードのように静的にコンパイルされ、コンパイル時に認識される必要があることです。例:
std.stdioをインポートします。
void main () { int num = 0 ; mixin ( "num++;" ); writeln ( num ); // 1 を出力します。 }
上記の例は、" " がミックスインではなく直接記述された場合とまったく同じアセンブリ言語命令にコンパイルされますnum++;。 mixin への引数は文字列リテラルである必要はなく、コンパイル時に評価できる関数呼び出しを含む文字列値を生成する任意の式である必要があります。
コールドフュージョン
ColdFusionのevaluate関数を使用すると、実行時に文字列式を評価できます。
<cfset x = "int(1+1)" >
<cfset y = 評価( x ) >
これは、読み取り元の変数をプログラムで選択する必要がある場合に特に便利です。
<cfset x = Evaluate ( "クエリ名. #列名# [行番号]" ) >
ルビー
Rubyプログラミング言語インタープリターは、Python や Perl に似た機能を提供しeval、スコープまたはバインディングを指定することもできます。
関数のバインディングを指定すること以外に、eval特定のクラス定義バインディングまたはオブジェクト インスタンス バインディング内の式を評価するためにも使用できます。これにより、文字列で指定された新しいメソッドを使用してクラスを拡張できるようになります。
a = 1 eval ( 'a + 1' ) # (2 と評価されます)
# コンテキスト内で評価
def get_binding ( a ) binding end eval ( 'a+1' , get_binding ( 3 )) # (get_binding のコンテキスト内の 'a' は 3 なので、4 と評価されます)
class Test ; end Test.class_eval ( "def hello ; return 'hello';end" ) #このクラスにメソッド 'hello' を追加します Test.new.hello # " hello "と評価されます
4番目
Forthのほとんどの標準実装には、evalとの 2 つEVALUATEのバリエーションがありますINTERPRET。
Win32FORTH コード例:
S" 2 2 + . " EVALUATE \ 出力は "4"
ベーシック
リアルベーシック
REALbasicには、実行時に REALbasic コードを実行できるRBScriptというクラスがあります。RBScript は高度にサンドボックス化されており、最もコアな言語機能のみが用意されており、必要な機能へのアクセスを許可する必要があります。オプションで、オブジェクトをコンテキスト プロパティに割り当てることができます。これにより、RBScript のコードから関数を呼び出し、コンテキスト オブジェクトのプロパティを使用できます。ただし、最も基本的な型のみの理解に限定されているため、Dictionary または MySpiffyObject を返す関数がある場合、RBScript ではその関数を使用できません。また、Print イベントと Input イベントを介して RBScript と通信することもできます。
VBスクリプト
インタープリタ言語である Microsoft の VBScript には、2 つの構成要素があります。Evalは、ユーザー定義関数の呼び出しを含めることができる関数評価子です。 (これらの関数には、グローバル変数の値を変更するなどの副作用がある場合があります。) は、Executeグローバル状態を変更できる、コロンで区切られた 1 つ以上のステートメントを実行します。
VBScript と JScript はどちらも、evalEval をサポートしない言語で記述されたコンパイル済み Windows アプリケーションの開発者が、Microsoft Script Control と呼ばれる ActiveX コントロールを通じて使用できます。このコントロールの Eval メソッドは、アプリケーション コードから呼び出すことができます。ユーザー定義関数の呼び出しをサポートするには、まず AddCode メソッドを使用してコントロールを初期化する必要があります。このメソッドは、Eval を呼び出す前に、選択した言語で定義されたユーザー定義関数のライブラリを含む文字列 (または文字列リソース) を読み込みます。
Visual Basic アプリケーション
Microsoft Office のプログラミング言語であるVisual Basic for Applications (VBA) は、ランタイム環境がp-code をコンパイルして実行する仮想マシン言語です。その Eval は式の評価のみをサポートしており、式にはユーザー定義の関数とオブジェクト (ユーザー定義の変数名ではない) を含めることができます。注意すべき点は、評価子が VBS と異なるため、特定のユーザー定義関数の呼び出しが VBA では VBScript の同一コードとは動作が異なる場合があります。
雑談
Smalltalkのコンパイラ クラスは標準クラス ライブラリの一部であり、通常は実行時に存在するため、コード文字列を評価するために使用できます 。
コンパイラの 評価: '1 + 2'
クラスとメソッドの定義もメッセージ送信 (クラス オブジェクトへの) によって実装されるため、コードの変更も可能です。
コンパイラ の評価: 'オブジェクトのサブクラス:#Foo'
Tcl
Tclプログラミング言語には、引数として指定されたソース コードを実行する というコマンドがあります。Tcl はすべてのソース コードを文字列として表し、中括弧は引用符として機能します。そのevalため、 への引数はeval他のソース コードと同じ形式にすることができます。
set foo { while {[ incr i ] < 10 } { puts "$i の 2 乗は [expr $i*$i]" } } eval $foo
bs
bsevalには、1 つの文字列引数を取る関数があります。この関数は、式の評価とステートメントの実行の両方を行います。後者の役割では、エラー処理にも使用できます。次の例とテキストは、 UNIX System V Release 3.2 プログラマーズ マニュアルのbs マニュアル ページからの抜粋です。 [6]
文字列引数は
bs式として評価されます。 関数は、数値文字列を数値内部形式に変換するのに便利です。 はeval、次のように、大まかな間接形式として使用することもできます ( ではbs、_(アンダースコア) は連結演算子であることに注意してください)。名前= "xyz" eval ( "++" _名前)変数を増分します
xyz。さらに、
eval問い合わせ演算子 を前に付けると、?ユーザーはbsエラー状態を制御できます。例:?eval ( "open(\"X\", \"XXX\", \"r\")" )「XXX」という名前のファイルが存在しない場合は、値 0 を返します (ユーザーのプログラムを停止する代わりに)。
以下は
gotoラベルL(存在する場合)に対して a を実行します。label = "L" if ! ( ?eval ( "goto " _ label )) puterr = "ラベルなし"
コマンドラインインタープリター
Unix シェル
evalコマンドは、オリジナルの「sh」( Bourne シェル) を含むすべてのUnix シェルに存在します。このコマンドは、すべての引数をスペースで連結し、その結果をコマンドとして再解析して実行します。 – FreeBSD一般コマンドマニュアル
Windows PowerShell
Windows PowerShellでは、Invoke-Expressionコマンドレットは JavaScript、PHP、Python などのプログラミング言語の eval 関数と同じ目的で使用されます。コマンドレットは、文字列の形式でコマンド パラメーターとして提供される任意の Windows PowerShell 式を実行し、指定された式の結果を出力します。通常、コマンドレットの出力は、式を実行した結果と同じ型になります。ただし、結果が空の配列の場合は、 を出力します$null。結果が単一要素の配列の場合は、その単一要素を出力します。JavaScript と同様に、Windows PowerShell では最後のセミコロンを省略できます。
式評価子としての例:
PS > $foo = 2
PS >呼び出し式 '$foo + 2'
ステートメントエグゼキュータとしての例:
PS > $foo = 2
PS >呼び出し式 '$foo += 2; $foo'
マイクロコード
1966年にIBM 会話型プログラミングシステム(CPS)は、IBM System/360 Model 50上で「修正ポーランド語文字列記法で書かれた式の解釈的評価」を実行するマイクロプログラム機能を導入しました。[7]この機能をマイクロコーディングすると、代入文を解釈するプログラムに比べて「大幅に」5倍以上高速になりました。[8]EVAL
理論
理論計算機科学では、 eval とapply は厳密に区別されるのが一般的です。eval は引用符で囲まれた文字列を呼び出し可能な関数とその引数に変換するステップと理解されていますが、apply は指定された引数セットで関数を実際に呼び出すことです。 この区別は、関数型言語や、LISPやSchemeなどのラムダ計算に基づく言語で特に顕著です。 たとえば、Scheme では、次の区別があります。
( eval ' ( f x ) )
ここで、フォーム(fx)が評価され、
( f (リストx )を適用)
ここで関数fは引数xで呼び出されます。
evalとapplyは、SICPで説明されているLispの評価の本質であるeval-applyサイクルの相互依存する2つの要素です。[9]
圏論では、eval 射は閉じたモノイド圏を定義するために使用されます。したがって、たとえば、関数を射としてとり、直積を積としてとった集合の圏は、直積の閉じた圏を形成します。ここで、eval (または、正確にはapply ) とその右随伴であるカリー化は、単純に型付けされたラムダ計算を形成し 、これは直積の閉じた圏の射として解釈できます。
参照
参考文献
- ^ 「Flash 8 LiveDocs」 2006-10-10。2006-10-10時点のオリジナルよりアーカイブ。
- ^ ActionScript 3 評価ライブラリ
- ^ 「D.eval API」。2013年3月14日時点のオリジナルよりアーカイブ。
- ^ ジョン・マッカーシー、「Lisp の歴史 - Lisp の実装」
- ^ 「PHP: eval - マニュアル」。PHP .net 。 2015年9月10日閲覧。
- ^ 「第 1 巻 コマンドとユーティリティ」。UNIX プログラマーズ マニュアル(PDF)。AT&T。1986 年。41 ページ。
- ^ Allen-Babcock. 「Draft EVAL Microprogram」(PDF) . Bitsavers.org . 2016年1月17日閲覧。
- ^ Rochester, Nathaniel. 「会話型プログラミングシステムの進捗レポート」(PDF) . Bitsavers.org . 2016年1月17日閲覧。
- ^ メタサーキュラー評価器 (SICP セクション 4.1)
外部リンク
- ANSI および GNU Common Lisp ドキュメント: eval 関数
- Python ライブラリ リファレンス: eval 組み込み関数
- Jonathan Johnson が RBScript にクラスを公開する方法について語る
- Rosetta Codeにおける複数の言語でのランタイム評価の例
