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 eval
niekoniecznie 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 eval
lub exec
jest.
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 eval
z 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 session
słownik, aby uwierzytelniony klucz ustawić na True. Aby temu zaradzić, wszystkie dane, które będą używane, eval
muszą zostać usunięte lub muszą być uruchamiane bez dostępu do potencjalnie szkodliwych funkcji.
Realizacja
W interpretowanych języków , eval
jest 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 eval
funkcji; czasami używane są oddzielne interpretery, chociaż powoduje to powielanie kodu .
Języki programowania
ECMAScript
JavaScript
W JavaScripcie , eval
jest 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 eval
jest parsowanie tekstu JSON , być może jako część frameworka Ajax . Jednak nowoczesne przeglądarki stanowią JSON.parse
bezpieczniejszą alternatywę dla tego zadania.
ActionScript
W ActionScript (języku programowania Flash) eval
nie 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 eval
języka ActionScript 3.
Seplenienie
Lisp był oryginalnym językiem, w którym wykorzystano eval
funkcję w 1958 roku. W rzeczywistości definicja eval
funkcji doprowadziła do pierwszej implementacji interpretera języka. Zanim eval
funkcja została zdefiniowana, funkcje Lisp były ręcznie kompilowane do instrukcji języka asemblerowego . Jednakże, gdy eval
funkcja 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 eval
funkcji Lisp zostały również zaimplementowane jako kompilatory.
eval
Funkcja 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 eval
funkcja. Na przykład, aby ocenić zawartość ciągu, ciąg musiałby najpierw zostać przekonwertowany na formę Lisp przy użyciu read-from-string
funkcji, 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 form1
zawiera 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 eval
określający kontekst oceny (podobny do opcjonalnych argumentów eval
funkcji 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 , eval
funkcja 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 eval
z ciągami w tym, że kod wewnątrz eval
bloków jest interpretowany w czasie kompilacji, a nie w czasie wykonywania, więc nie jest to znaczenie eval
użyte w tym artykule.
PHP
W PHP , eval
wykonuje 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 eval
musi 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 eval
zwrócenie wyniku tego wyrażenia.
W przeciwieństwie do niektórych języków, PHP eval
jest 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 loadstring
kompiluje 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 loadstring
na rzecz istniejącej load
funkcji, 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 exec
operator 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.
run
Operator 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 eval
funkcji w najprostszej postaci ocenia jeden wyraz.
eval
przykład (powłoka interaktywna):
>>> x = 1
>>> eval('x + 1')
2
>>> eval('x')
1
eval
Funkcja przyjmuje dwa argumenty opcjonalne, global
i locals
, które umożliwiają programiście skonfigurować środowisko ograniczony do oceny ekspresji.
exec
Oświadczenie (lub exec
funkcja 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ą mixin
instrukcję „ ”. 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 evaluate
funkcja 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 eval
funkcję 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, eval
moż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
: EVALUATE
i 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. Eval
jest 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.) Execute
wykonuje jedną lub więcej instrukcji oddzielonych dwukropkami, które mogą zmienić stan globalny.
Zarówno VBScript, jak i JScript eval
są 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 eval
moż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 eval
funkcję, 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
bs
wyrażenie. Funkcja jest przydatna do konwertowania ciągów liczbowych do wewnętrznej postaci numerycznej.eval
Mogą być również stosowane w postaci surowej postaci pośredni, jak poniżej (Należy zauważyć, że wbs
,_
(podkreślenie) jest operatorem konkatenacji.)name = "xyz" eval("++" _ name)co zwiększa zmienną
xyz
.Dodatkowo,
eval
poprzedzony operatorem odpytywania?
, pozwala użytkownikowi kontrolowaćbs
stany 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
goto
do etykietyL
(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. – Podręcznik poleceń ogólnych FreeBSD
Windows PowerShell
W Windows PowerShell The Invoke-Expression
komandletu 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ę EVAL
do 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.