równać - eval

W niektórych językach programowania , eval, skrót angielski ocenić , to funkcja , która ocenia ciąg jakby były wyrazem i zwraca wynik ; w innych wykonuje wiele wierszy kodu tak, jakby zostały dołączone zamiast wiersza zawierającego eval. Wejście do evalniekoniecznie jest ciągiem; może być ustrukturyzowaną reprezentacją kodu, taką jak abstrakcyjne drzewo składni (jak formularze Lisp ) lub specjalnego typu, jak code(jak w Pythonie). Analogiem instrukcji jest exec , który wykonuje ciąg (lub kod w innym formacie) tak, jakby był instrukcją; w niektórych językach, takich jak Python, oba są obecne, podczas gdy w innych tylko jeden z nich evallub execjest.

Oceniaj i stosuj to przypadki ewaluatorów metakołowych , tłumaczy języka, których można przywołać w samym języku.

Zagrożenia bezpieczeństwa

Korzystanie evalz danych z niezaufanego źródła może powodować luki w zabezpieczeniach. Na przykład, zakładając, że get_data()funkcja pobiera dane z Internetu, ten kod Pythona jest niepewny:

session['authenticated'] = False
data = get_data()
foo = eval(data)

Osoba atakująca może dostarczyć programowi ciąg znaków "session.update(authenticated=True)"jako dane, co zaktualizuje sessionsłownik, aby uwierzytelniony klucz ustawić na True. Aby temu zaradzić, wszystkie dane, które będą używane, evalmuszą zostać usunięte lub muszą być uruchamiane bez dostępu do potencjalnie szkodliwych funkcji.

Realizacja

W interpretowanych języków , evaljest niemal zawsze realizowane z tego samego tłumacza jako normalnego kodu. W językach kompilowanych ten sam kompilator używany do kompilowania programów może być osadzony w programach korzystających z evalfunkcji; czasami używane są oddzielne interpretery, chociaż powoduje to powielanie kodu .

Języki programowania

ECMAScript

JavaScript

W JavaScripcie , evaljest czymś w rodzaju krzyżówkę pomiędzy wyrażeń i wykonawca instrukcji. Zwraca wynik ostatniego ocenianego wyrażenia.

Przykład jako ewaluator wyrażeń:

foo = 2;
alert(eval('foo + 2'));

Przykład jako wykonawca instrukcji:

foo = 2;
eval('foo = foo + 2;alert(foo);');

Jednym z zastosowań JavaScript evaljest parsowanie tekstu JSON , być może jako część frameworka Ajax . Jednak nowoczesne przeglądarki stanowią JSON.parsebezpieczniejszą alternatywę dla tego zadania.

ActionScript

W ActionScript (języku programowania Flash) evalnie można używać do oceny dowolnych wyrażeń. Zgodnie z dokumentacją Flash 8, jego użycie jest ograniczone do wyrażeń, które reprezentują „nazwę zmiennej, właściwości, obiektu lub klipu filmowego do pobrania. Ten parametr może być ciągiem znaków lub bezpośrednim odniesieniem do instancji obiektu”.

ActionScript 3 nie obsługuje ewaluacji.

ActionScript 3 Eval Library i D.eval API to trwające projekty rozwojowe mające na celu stworzenie odpowiedników evaljęzyka ActionScript 3.

Seplenienie

Lisp był oryginalnym językiem, w którym wykorzystano evalfunkcję w 1958 roku. W rzeczywistości definicja evalfunkcji doprowadziła do pierwszej implementacji interpretera języka. Zanim evalfunkcja została zdefiniowana, funkcje Lisp były ręcznie kompilowane do instrukcji języka asemblerowego . Jednakże, gdy evalfunkcja została już ręcznie skompilowana, była następnie używana jako część prostej pętli odczytu-oceny-drukowania, która stanowiła podstawę pierwszego interpretera Lisp.

Późniejsze wersje evalfunkcji Lisp zostały również zaimplementowane jako kompilatory.

evalFunkcja w Lisp spodziewa formą zostać ocenione i wykonywane jako argument. Wartość zwrócona z danego formularza będzie wartością zwróconą wywołania eval.

Oto przykładowy kod Lisp:

; A form which calls the + function with 1,2 and 3 as arguments.
; It returns 6.
(+ 1 2 3)
; In lisp any form is meant to be evaluated, therefore
; the call to + was performed.
; We can prevent Lisp from performing evaluation
; of a form by prefixing it with "'", for example:
(setq form1 '(+ 1 2 3))
; Now form1 contains a form that can be used by eval, for
; example:
(eval form1)
; eval evaluated (+ 1 2 3) and returned 6.

Wiadomo, że Lisp jest bardzo elastyczny, podobnie jak evalfunkcja. Na przykład, aby ocenić zawartość ciągu, ciąg musiałby najpierw zostać przekonwertowany na formę Lisp przy użyciu read-from-stringfunkcji, a następnie wynikowa forma musiałaby zostać przekazana do eval:

(eval (read-from-string "(format t \"Hello World!!!~%\")"))

Jednym z głównych punktów nieporozumień jest pytanie, w jakim kontekście będą oceniane symbole w formie. W powyższym przykładzie form1zawiera symbol +. Ocena tego symbolu musi zawierać funkcję dodawania, aby przykład działał zgodnie z przeznaczeniem. Tak więc niektóre dialekty lisp pozwalają na dodatkowy parametr evalokreślający kontekst oceny (podobny do opcjonalnych argumentów evalfunkcji Pythona - patrz niżej). Przykład w dialekcie Scheme of Lisp (R 5 RS i nowsze):

;; Define some simple form as in the above example.
(define form2 '(+ 5 2))
;Value: form2

;; Evaluate the form within the initial context.
;; A context for evaluation is called an "environment" in Scheme slang.
(eval form2 user-initial-environment)
;Value: 7

;; Confuse the initial environment, so that + will be
;; a name for the subtraction function.
(environment-define user-initial-environment '+ -)
;Value: +

;; Evaluate the form again.
;; Notice that the returned value has changed.
(eval form2 user-initial-environment)
;Value: 3

Perl

W Perl , evalfunkcja jest czymś w rodzaju krzyżówkę pomiędzy wyrażeń i wykonawca instrukcji. Zwraca wynik ostatniego ocenianego wyrażenia (wszystkie instrukcje są wyrażeniami w programowaniu Perla) i pozwala na opuszczenie ostatniego średnika.

Przykład jako ewaluator wyrażeń:

$foo = 2;
print eval('$foo + 2'), "\n";

Przykład jako wykonawca instrukcji:

$foo = 2;
eval('$foo += 2; print "$foo\n";');

Perl posiada również eval bloki , które służą jako mechanizm obsługi wyjątków (zobacz Składnia obsługi wyjątków#Perl ). Różni się to od powyższego użycia evalz ciągami w tym, że kod wewnątrz evalbloków jest interpretowany w czasie kompilacji, a nie w czasie wykonywania, więc nie jest to znaczenie evalużyte w tym artykule.

PHP

W PHP , evalwykonuje kod w ciąg niemal dokładnie tak, jak gdyby zostały wprowadzone w pliku zamiast wywołania eval(). Jedynym wyjątkiem jest to, że błędy są zgłaszane jako pochodzące z wywołania funkcji eval(), a instrukcje return stają się wynikiem funkcji.

W przeciwieństwie do niektórych języków, argument to evalmusi być ciągiem jednego lub więcej kompletnych instrukcji, a nie tylko wyrażeń; jednak można uzyskać formę "wyrażenia" eval, umieszczając wyrażenie w instrukcji return, co powoduje evalzwrócenie wyniku tego wyrażenia.

W przeciwieństwie do niektórych języków, PHP evaljest raczej "konstrukcją językową" niż funkcją, a więc nie może być używany w niektórych kontekstach, w których mogą być funkcje, jak funkcje wyższego rzędu.

Przykład przy użyciu echa:

<?php
$foo = "Hello, world!\n";
eval('echo "$foo";');
?>

Przykład zwracania wartości:

<?php
$foo = "Goodbye, world!\n";  //does not work in PHP5
echo eval('return $foo;');
?>

Lua

W Lua 5.1 loadstringkompiluje kod Lua w funkcję anonimową.

Przykład jako ewaluator wyrażeń:

loadstring("print('Hello World!')")()

Przykład wykonania oceny w dwóch krokach:

a = 1
f = loadstring("return a + 1") -- compile the expression to an anonymous function
print(f()) -- execute (and print the result '2')

Lua 5.2 jest przestarzała loadstringna rzecz istniejącej loadfunkcji, która została rozszerzona o akceptowanie łańcuchów. Ponadto umożliwia bezpośrednie udostępnienie środowiska funkcji, ponieważ środowiska są teraz upvalues .

print(load("print('Hello ' .. a)", "", "t", { a = "World!", print = print })())

Postscriptum

PostScript jest execoperator pobiera argument - jeśli jest to proste dosłowny to popycha ją na stosie. Jeśli jednak weźmie się ciąg znaków zawierający wyrażenie PostScript, można go przekonwertować na plik wykonywalny, który następnie może zostać wykonany przez interpreter, na przykład:

 ((Hello World) =) cvx exec

konwertuje wyrażenie PostScript

 (Hello World) =

który zdejmuje ze stosu łańcuch "Hello World" i wyświetla go na ekranie, aby mieć typ wykonywalny, a następnie jest wykonywany.

runOperator PostScript jest podobny pod względem funkcjonalności, ale zamiast tego interpreter sam interpretuje wyrażenia PostScript w pliku.

(file.ps) run

Pyton

W Pythonie The evalfunkcji w najprostszej postaci ocenia jeden wyraz.

eval przykład (powłoka interaktywna):

>>> x = 1
>>> eval('x + 1')
2
>>> eval('x')
1

evalFunkcja przyjmuje dwa argumenty opcjonalne, globali locals, które umożliwiają programiście skonfigurować środowisko ograniczony do oceny ekspresji.

execOświadczenie (lub execfunkcja w Pythonie 3.x) wykonuje instrukcje:

exec przykład (powłoka interaktywna):

>>> x = 1
>>> y = 1
>>> exec "x += 1; y -= 1"
>>> x
2
>>> y
0

Najbardziej ogólną formą oceny instrukcji/wyrażeń jest użycie obiektów kodu. Można je utworzyć, wywołując compile()funkcję i mówiąc jej, jaki rodzaj danych wejściowych ma skompilować: instrukcja " exec", instrukcja " eval" lub instrukcja " single":

compile przykład (powłoka interaktywna):

>>> x = 1
>>> y = 2
>>> eval (compile ("print 'x + y = ', x + y", "compile-sample.py", "single"))
x + y =  3

re

D jest językiem kompilowanym statycznie i dlatego nie zawiera instrukcji „ eval” w tradycyjnym sensie, ale zawiera pokrewną mixininstrukcję „ ”. Różnica polega na tym, że gdy „ eval” interpretuje ciąg jako kod w czasie wykonywania, z „ mixin” ciąg jest kompilowany statycznie jak zwykły kod i musi być znany w czasie kompilacji. Na przykład:

import std.stdio;

void main() {
    int num = 0;
    mixin("num++;");
    writeln(num);  // Prints 1.
}

Powyższy przykład skompiluje się do dokładnie tych samych instrukcji asemblerowych jak gdyby " num++;" zostało napisane bezpośrednio zamiast wmieszać. Argument mixin nie musi być literałem ciągu, ale dowolnymi wyrażeniami dającymi wartość ciągu, w tym funkcję wywołania, które można ocenić w czasie kompilacji.

Zimna fuzja

ColdFusion „s evaluatefunkcja pozwala ocenić wyrażenie tekstowe w czasie wykonywania.

<cfset x = "int(1+1)">
<cfset y = Evaluate(x)>

Jest to szczególnie przydatne, gdy musisz programowo wybrać zmienną, z której chcesz czytać.

<cfset x = Evaluate("queryname.#columnname#[rownumber]")>

Rubin

Do programowania Ruby język tłumacza oferuje evalfunkcję podobną do Python lub Perl, a także pozwala na zakres lub wiązanie , które zostaną określone.

Oprócz określenia powiązania funkcji, evalmoże być również używany do oceny wyrażenia w ramach określonego powiązania definicji klasy lub powiązania instancji obiektu, umożliwiając rozszerzenie klas o nowe metody określone w ciągach.

a = 1
eval('a + 1') #  (evaluates to 2)

# evaluating within a context
def get_binding(a)
  binding
end
eval('a+1',get_binding(3)) # (evaluates to 4, because 'a' in the context of get_binding is 3)
class Test; end
Test.class_eval("def hello; return 'hello';end") # add a method 'hello' to this class
Test.new.hello                    # evaluates to "hello"

Naprzód

Większość standardowych implementacji Forth ma dwa warianty eval: EVALUATEi INTERPRET.

Przykład kodu Win32FORTH:

  S" 2 2 + ." EVALUATE \ Outputs "4"

PODSTAWOWY

REALbasic

W REALbasic istnieje klasa o nazwie RBScript, która może wykonywać kod REALbasic w czasie wykonywania. RBScript jest bardzo piaskownicą — są tam tylko najbardziej podstawowe funkcje językowe i musisz zezwolić mu na dostęp do rzeczy, które chcesz mieć. Opcjonalnie można przypisać obiekt do właściwości context. Dzięki temu kod w RBScript może wywoływać funkcje i korzystać z właściwości obiektu kontekstu. Jednak nadal ogranicza się tylko do zrozumienia najbardziej podstawowych typów, więc jeśli masz funkcję, która zwraca Dictionary lub MySpiffyObject, RBScript nie będzie mógł jej użyć. Możesz także komunikować się ze swoim RBScript poprzez zdarzenia drukowania i wprowadzania.

VBScript

VBScript firmy Microsoft, który jest językiem interpretowanym, ma dwie konstrukcje. Evaljest ewaluatorem funkcji, który może zawierać wywołania funkcji zdefiniowanych przez użytkownika. (Te funkcje mogą mieć skutki uboczne, takie jak zmiana wartości zmiennych globalnych.) Executewykonuje jedną lub więcej instrukcji oddzielonych dwukropkami, które mogą zmienić stan globalny.

Zarówno VBScript, jak i JScript evalsą dostępne dla programistów skompilowanych aplikacji Windows (napisanych w językach, które nie obsługują Eval) poprzez kontrolkę ActiveX o nazwie Microsoft Script Control, której metodę Eval można wywołać przez kod aplikacji. Aby obsłużyć wywoływanie funkcji zdefiniowanych przez użytkownika, należy najpierw zainicjować kontrolkę metodą AddCode, która ładuje ciąg (lub zasób ciągu) zawierający bibliotekę funkcji zdefiniowanych przez użytkownika w wybranym przez użytkownika języku, przed wywołaniem Eval .

Visual Basic dla aplikacji

Visual Basic for Applications (VBA), język programowania pakietu Microsoft Office, to język maszyny wirtualnej, w którym środowisko wykonawcze kompiluje i uruchamia p-code . Jego smak Eval obsługuje tylko ocenę wyrażeń, gdzie wyrażenie może zawierać funkcje i obiekty zdefiniowane przez użytkownika (ale nie zdefiniowane przez użytkownika nazwy zmiennych). Warto zauważyć, że ewaluator różni się od VBS, a wywoływanie pewnych funkcji zdefiniowanych przez użytkownika może działać inaczej w VBA niż identyczny kod w VBScript.

Pogawędka

Ponieważ klasy kompilatorów Smalltalk są częścią standardowej biblioteki klas i zwykle są obecne w czasie wykonywania, mogą one zostać użyte do oceny ciągu kodu.

Compiler evaluate:'1 + 2'

Ponieważ definicje klas i metod są również implementowane przez wysyłanie komunikatów (do obiektów klas), możliwe są nawet zmiany kodu:

Compiler evaluate:'Object subclass:#Foo'

Tcl

Język programowania Tcl ma polecenie o nazwie eval, które wykonuje kod źródłowy dostarczony jako argument. Tcl reprezentuje cały kod źródłowy jako ciągi, z nawiasami klamrowymi działającymi jako znaki cudzysłowu, dzięki czemu argument do evalmoże mieć takie samo formatowanie jak każdy inny kod źródłowy.

set foo {
	while {[incr i]<10} {
		puts "$i squared is [expr $i*$i]"
	}
}
eval $foo

bs

bs ma evalfunkcję, która przyjmuje jeden argument w postaci łańcucha. Funkcja jest zarówno ewaluatorem wyrażeń, jak i executorem instrukcji. W tej ostatniej roli może być również używany do obsługi błędów. Poniższe przykłady i tekst pochodzą ze strony podręcznika bs man, jaka znajduje się w Podręczniku programisty systemu UNIX System V wydanie 3.2.

Argument ciągu jest oceniany jako bswyrażenie. Funkcja jest przydatna do konwertowania ciągów liczbowych do wewnętrznej postaci numerycznej. evalMogą być również stosowane w postaci surowej postaci pośredni, jak poniżej (Należy zauważyć, że w bs, _(podkreślenie) jest operatorem konkatenacji.)

name = "xyz"
eval("++" _ name)

co zwiększa zmienną xyz.

Dodatkowo, evalpoprzedzony operatorem odpytywania ?, pozwala użytkownikowi kontrolować bsstany błędów. Na przykład:

?eval("open(\"X\", \"XXX\", \"r\")")

zwraca wartość zero, jeśli nie ma pliku o nazwie „XXX” (zamiast zatrzymywania programu użytkownika).

Następujące polecenie wykonuje a gotodo etykiety L(jeśli istnieje):

label = "L"
if !(?eval("goto " _ label)) puterr = "no label"

Interpretery wiersza poleceń

Powłoki Uniksa

Polecenie eval jest obecne we wszystkich powłokach Unix , w tym w oryginalnym "sh" ( powłoka Bourne'a ). Łączy wszystkie argumenty ze spacjami, a następnie ponownie analizuje i wykonuje wynik jako polecenie. sh(1) –  Podręcznik poleceń ogólnych FreeBSD

Windows PowerShell

W Windows PowerShell The Invoke-Expressionkomandletu służy temu samemu celowi co eval funkcji w programowaniu w językach takich jak JavaScript, PHP i Python. Polecenie cmdlet uruchamia dowolne wyrażenie programu Windows PowerShell, które jest dostarczane jako parametr polecenia w postaci ciągu i wyświetla wynik określonego wyrażenia. Zwykle dane wyjściowe polecenia cmdlet są tego samego typu, co wynik wykonania wyrażenia. Jeśli jednak wynik jest pustą tablicą, zwraca $null. W przypadku, gdy wynikiem jest tablica jednoelementowa, wyprowadza ten pojedynczy element. Podobnie jak w JavaScript, Windows PowerShell pozwala na opuszczenie ostatniego średnika.

Przykład jako ewaluator wyrażeń:

PS  > $foo = 2
PS  > invoke-expression '$foo + 2'

Przykład jako wykonawca instrukcji:

PS  > $foo = 2
PS  > invoke-expression '$foo += 2; $foo'

Mikrokod

W 1966 r. IBM Conversational Programming System (CPS) wprowadził mikroprogramowaną funkcję EVALdo wykonywania „interpretacyjnej oceny wyrażeń zapisanych w zmodyfikowanej notacji polsko-łańcuchowej ” na IBM System/360 Model 50 . Mikrokodowanie tej funkcji było „znacznie więcej” niż pięć razy szybsze w porównaniu z programem, który interpretował instrukcję przypisania .

Teoria

W informatyce teoretycznej powszechnie dokonuje się starannego rozróżnienia między ewaluacją a zastosowaniem . Eval jest rozumiany jako etap konwersji łańcucha w cudzysłowie na funkcję wywoływalną i jej argumenty, podczas gdy apply to faktyczne wywołanie funkcji z danym zestawem argumentów. Rozróżnienie to jest szczególnie widoczne w językach funkcjonalnych oraz językach opartych na rachunku lambda , takich jak LISP i Scheme . Tak więc na przykład w Scheme rozróżnia się między

(eval '(f x) )

gdzie formularz (fx) ma być oceniany, oraz

(apply f (list x))

gdzie funkcja f ma być wywołana z argumentem x .

Oceń i zastosuj to dwa współzależne elementy cyklu ewaluacja -zastosowanie , który jest esencją ewaluacji Lisp, opisanej w SICP .

W teorii kategorii The eval morfizmem służy do zdefiniowania zamkniętą kategorię monoidal . I tak na przykład kategoria zbiorów , z funkcjami przyjętymi jako morfizmy i iloczynem kartezjańskim jako iloczynem , tworzy zamkniętą kategorię kartezjańską . Tutaj eval (lub, właściwie mówiąc, zastosowanie ) wraz z jego prawej adjoint , currying , tworząc po prostu wpisane rachunek lambda , który może być interpretowany w ten sposób być morfizmami kartezjańskiego zamknięte kategorie.

Bibliografia

Linki zewnętrzne