Wtyczka Math

Ten dokument zgodny jest z NSIS 3.9


1. Wprowadzenie

Skrypt pisany jest w stylu języka C (a przynajmniej operatory).

Wskazówka 1: wtyczka sprawdza wielkości liter.

Wskazówka 2: wtyczka prawie wcale nie sprawdza błędów. Więc POWINIENEŚ sprawdzać swój skrypt dwa razy nim go uruchomisz :)

2. Sposób użycia

Uruchom plik MathTest.Exe i przekonaj się sam. Po kilku minutach testów powinieneś być w stanie sam napisać swój skrypt. Aby dołączyć go do skryptu NSIS po prostu wstaw poniższe wywołanie:

        Math::Script "TwójSkrypt1"
        Math::Script "TwójSkrypt2"
        Math::Script "TwójOstatniSkrypt"

Jak tego używać? Bardzo łatwo:

        Strcpy $0 "Brainsucker"
        Math::Script "a = 'Skrypt'; B = 'Math'; r0 += ' chce użyć ' + a + '::' + b +'!'"
        DetailPrint "$0"

Ten łańcuch znaków zapełni r0 jakimiś danymi.

Inne przykłady:

10! (factorial, r0 będzie zawierać '10! = 362880'):
     r0 = '10! = ' + (1*2*3*4*5*6*7*8*9)
  tak samo:
     a = b = 1; #{++a <= 10, b = b*a}; r0 = (a-1) + '! = ' + b
Kilka przykładów dla operacji zmiennoprzecinkowych:
     Strcpy $R0 "1e1"
     Math::Script "pi = 3.14159; R1 = 2*pi*R0; r0 = 'Obwód okręgu z promieniem ' + R0 + ' = ' + R1 + '.'"
     Detailprint "$0"

3. Zmienne

NSIS: r0-r9 -> $0-$9. R0-R9 -> $R0-$R9.

Również CL ($CMDLINE), ID ($INSTDIR), OD ($OUTDIR), LG ($LANG), ED ($EXEDIR). Definiowalne przez użytkownika: nazwy zaczynające się od znaku, przy długości do 28 liter.

4. Stos

Obsługiowane są dwa stosy: Stos NSIS oraz własny stos wtyczki. Nie widzę żadnego powodu, aby używać stosu wtyczki, ale jeśli będziesz chciał pamiętaj, że wtyczka przechowuje zmienne używane w funkcji przed wywołaniem tej funkcji i przywraca je po wykonaniu. Dlatego zalecam używanie stosu NSIS. Powinieneś używać go tylko dla operacji wejścia/wyjścia.

Jak go używać? Działanie opiera się na stylu zmiennych. Stos wtyczek jest powiązany ze zmienną S, a stos NSIS jest powiązany ze zmienną NS. Aby odłożyć na stos, użyj po prostu składni "S=0" lub "NS=0". Aby zdjąć ze stosu, użyj składni "a=S" lub "b=NS". Obsługiwane są również operacje złożone: "S += 1.5" zwiększy wartość na górze stosu o 1.5.

5. Typy danych

Obsługiwane typy: int (w rzeczywistości __int64), float (w rzeczywistości typ double), string (łańcuch znaków).

  • Int

    liczby, mogą zawierać znaki

  • Float

    -123.456, 123.456e-78, 123e-45

  • String

    Jakiś tekst w cudzysłowiu ("", '', ``)

Istnieje również typ tablicowy. Aktualnie jest typem referencyjnym, więc jeśli b jest tablicą i jeśli wpiszesz "a=b", a oraz b będą wskazywały na jedną tablicę. Aby utworzyć kopię tablicy, użyj funkcji ca: dest = ca(source). Tak przy okazji, nie możesz kontrolować rozmiaru tablicy - jest on przydzielany automatycznie.

Aby zadeklarować tablicę:

a = {};

Aby zadeklarować tablicę i zainicjować kilka jej elementów jakimiś wartościami:

{"Cześć!", "Użyj", "typów mieszanych", 1.01e23, "takich jak ten" ,1234};

Aby uzyskać dostęp do tablicy:

a[index] = "Fajnie";

Również operacje [] winne być używane w łańcuchach znaków. Str[x] daje ci pojedynczy znak z indeksem x (od zera) jako nowy łańcuch znaków. Str[-x] - to samo, co wyżej, ale x odlicza od końca łańcucha znaków (więc ostatnim znakiem łańcucha znaków jest -1). Str[x,y] daje ci znaki w zakresie x-y (włącznie z tymi znakami), zarówno x jak i y powinny być <0 - w takim przypadku są one odliczane od końca łańcucha znaków.

Poniższa funkcja powinna być przydatna - konwertuje typ tablicowy na łańcuch znaków i na odwrót.

Przykład:

a = a("Cześć"); str = s(a);

Po uruchomienu takiego skryptu tablica zawierać będzie 6 liczb całkowitych (znaków i zera na końcu - koniec łańcucha znaków), a str będzie zawierać twój łańcuch znaków.

6. Operatory

Operatory (niektóre binarne, niektóre jednoargumentowe):

>>= <<= -= += /= *= |= &= ^= %= -- ++ >> << && || <= =< >= => != == = + - * / % < > & | ^ ~ !

Tylko niektóre z nich odnoszą się do zmiennoprzecinkowych float (logiczne & arytmetyczne) oraz oczywiście łańcuch znaków string (+ oraz logiczne).

Inne przypadki: Operatory referencji/dereferencji (& oraz *). & da ci referencję do argumentu, który powinien być zmienną (NSIS, użytkownik, element tablicy, stos), a * skonwertuje to z powrotem na zmienną oryginalną. Na przykład (a=&b; *a=10) ustawi b na wartość 10. Wyrażenie (*&a) jest równe wyrażeniu (a).

Skrypt jest zbiorem wyrażeń (w większości matematycznych) rozdzielonych znakiem średnika ';'. Wykonywanie takiego skryptu następuje zgodnie z regułami matematycznymi (2+2*2 da w wyniku 6), operacje wykonywane są w kolejności zgodnej z C (pierwszeństwo).

7. Kontrola wykonania

        if-then-else like:     #[if-expression, then-expr, else-expr]
                przykład:
                        #[a==0, b=1; c=2, b *= (--c); c/=10]
                C eq:
                        if (a==0) { b=1; c=2;} else { b*=(c++);c-=10; }
        while (expr) do; like   #{expr, do}
                przykład:
                        #{(c<1.1e25)&&(b < 10), b++; c*=1.23}
                C eq:
                        while ((c<1.1e25)&&(b<10)) { b++; c*=1.23; }

UWAGA
Znak przecinka (,) oddziela if-expr, then-expr, oraz else-expr od siebie. Wszystkie podwyrażenia rozdzielane znakiem średnika (;) są częścią jednego wyrażenia, a wynik ostatniej z tych podwyrażeń jest wynikiem całego wyrażenia.
Wszystko inne (zmienne i funkcje) zostaną zachowane pomiędzy wywołaniami.

8. Funkcje

Konwersje typów:

    l(łańcuch_znaków)  Zwraca długość łańcucha znaków lub argument tablicy
    s(źródło)                 Konwertuje źródło na typ łańcucha znaków string
    i(źródło)                  Konwertuje źródło na typ całkowity int
    f(źródło)                 Konwertuje źródło na typ zmiennoprzecinkowy float
    c(źródło)                 Jeśli źródło jest łańcuchem znaków, zwraca wartość całkowitą int
                                       pierwszego znaku, jeśli źródło jest typu całkowitego int,
                                       zwraca łańcuch znaków pojedynczych znaków (źródło) (+0 znak końca).
    a(źródło)                 konwertuje źródło na tablicę (obsługiwane są tylko łańcuchy znaków)
    ff(float, format)       konwertuje typ zmiennoprzecinkowy float na łańcuch znaków string,
                                        z opcjami formatowania format.
Opcje = Precyzja + Flagi.

	Precyzja mówi o tym ile zer po przecinku zostanie pokazanych.

	Flagi:
		16 (lub 0x10) - Bez postaci wykładniczej (liczby wyświetlane jako 123.123)
		32 (lub 0x20) - Tylko postać wykładnicza (liczby wyświetlane jako 123.12e123)
		64 (lub 0x40) - Użyj znaku 'E' zamiast 'e'

Domyślnie wtyczka sama decyduje jak mają być wyświetlane liczby.

Math (opis wszystkich poniższych funkcji dostępny jest na MSDN.
   Aby je znaleźć użyj w zapytaniu drugiej podanej nazwy):

    sin(x),         sin     Sinus argumentu
    cos(x),        cos     Kosinus argumentu
    cel(x),         ceil    Najmniejsza liczba całkowita >= argumentowi (brak reszty)
    csh(x),        cosh    Kosinus hiperboliczny argumentu
    exp(x),        exp     Wykładnik
    abs(x),        abs     Wartość absolutna (uwaga: float)
    flr(x),          floor   Podstawa argumentu (brak reszty)
    asn(x),        asin    Arkus-sinus argumentu
    acs(x),        acos    Arkus-kosinus argumentu
    atn(x),        atan    Arkus-tanges argumentu
    ln(x),           log     Logarytm wykładniczy
    log(x),         log10   Logarytm dziesiętny
    snh(x),        sinh    Sinus hiperboliczny argumentu
    sqt(x),         sqrt    Pierwiastek argumentu
    tan(x),         tan     Tanges argumentu
    tnh(x),         tanh    Tanges hiperboliczny argumentu

Funkcje przyjmujące dwa argumenty

    at2(x, y)        atan2    Arkus-tanges wartości (y/x)
    pow(x, y)      pow      Potęga, x^y
    fmd(x, y)       fmod    Reszta liczby zmiennoprzecinkowej
    fex(x, o)        frexp    Pobiera mantyse (wynik = r) oraz wykładnik (o) liczby zmiennoprzecinkowej
                                        liczba (x): x = r*(2^o)
    mdf(x, o)       modf    Rozdziela wartość zmiennoprzecinkową na ułamkową i składającą się z części całkowitej.

9. Funkcje użytkownika

To jest bardzo proste. Przykład:

        test(a,b) (a+b);

Po tej operacji test(1,2) daje w wyniku 3.

        test2(a,b) (a=a+b; b *= a);

Wynik funkcji jest zawsze wynikiem ostatniego wyrażenia. Jak napisano wcześniej lepiej nie używać stosu (S) pomiędzy wywołaniami funkcji. Lepiej jest oprogramować funkcje z bezpiecznymi zmiennymi, np. funkcje, które nie psują zmiennych. Aby to zrealizować powinieneś raczej odłożyć/pobrać je ze stosu, lub zadeklarować jako dodatkowe argumenty, które nigdy nie zostana użyte. Przykład:

        test3(a,b,c) (c=10; #{--c > 0, a=sqrt(a*b)}; a)

Nie ważne jak wiele argumentów zostanie przypisanych funkcji, wartości wszystkich trzech zmiennych (a,b,c) zostana zachowane.

Niektóre funkcje chroniące zmienne powinny być rekursywne:

        Math::Script 'rec(a) (#[a > 0, rec(a-1), 0]+a);'
        Math::Script 'R1 = rec(10)'

ustawi R1 na prawidłowy wynik 55.

Niekiedy istnieje potrzeba, by funkcje zwracały więcej niż jedna wartość. W takim przypadku powinieneś zadeklarować argument jako referent (b na przykład):

        test4(a, &b) (*b = a*a; a*a*a)

W takim przypadku test4 zwróci a^3 i jeśli wywołamy ją jako test4(a,c), przypisze a^2 do c.

UWAGA
Powinieneś użyć dereferencji (*) ze zmienną, na przykład *b.

OSTRZEŻENIE
Nigdy nie używaj tej samej zmiennej jako zmiennej wewnętrznej referencji funkcji oraz zmiennej zewnętrznego argumentu (na przykład test4(a,b)). Użycie takiej składni na pewno nie powiedzie się. Również: jeśli zadeklarujesz argument jako referencję - nie powinieneś nigdy podawać stałego wyrażenia do niego. Może to być zarówno element tablicy (array[1]), rejestr NSIS R0, dowolna ze zmiennych użytkownika (poza zmiennymi o tych samych nazwach:), ale nigdy nie zmienna.

Inną, mogącą byc przydatną możliwością jest redeklaracja funkcji (zwyczajowa deklaracja w czasie gdy funkcja już zdefiniowana, wywoła tę funkcję). Dla takiego zadania powinieneś użyć "#name", jak "func()(1); #func()(2);". Ale uwaga, deklaracja funkcji następuje w czasie parsowania , więc nie jest możliwym wykonanie płynnie kontrolowanej deklaracji.

NIEMOŻLIWE: "#[a<0, #func()(1), #func()(2)]" PO PROSTU ZDEFINIUJE #func jako (2), jako ostatni wariant.

10. Autorzy

(c) Nik Medved (brainsucker)