Mechanizm pseudo-wyjątków w pawn

Wyjątki są zaimplementowane w wielu językach programowania np.

http://pl.wikibooks.org/wiki/C++/Obs%C5%82uga_wyj%C4%85tk%C3%B3w
http://msdn.microsoft.com/en-us/library/6dekhbbc(v=vs.80).aspx
http://php.net/manual/en/language.exceptions.php

http://pl.wikipedia.org/wiki/Wyj%C4%85tek

Wyjątek (ang. exception) jest mechanizmem przepływu sterowania używanym w mikroprocesorach oraz współczesnych językach programowania do obsługi zdarzeń wyjątkowych, a w szczególności błędów, których wystąpienie zmienia prawidłowy przebieg wykonywania programu. W momencie zajścia niespodziewanego zdarzenia generowany jest wyjątek, który musi zostać obsłużony poprzez zapamiętanie bieżącego stanu programu i przejście do procedury jego obsługi. W niektórych sytuacjach po obsłużeniu wyjątku można powrócić do wykonywania przerwanego kodu, korzystając z zapamiętanych informacji stanu. Przykładowo obsługa błędu braku strony pamięci polega najczęściej na pobraniu brakującej strony z pliku wymiany, co umożliwia kontynuowanie pracy programu, natomiast błąd dzielenia przez zero powoduje, że wykonywanie dalszych obliczeń nie ma sensu i musi zostać przerwane na trwałe.

Implementacja w pawn ma pewne ograniczenia ( stąd pseudo 😉 ) wynikające z sposobu jakie są one zaimplementowane.
Nie ma np. wyłapywania nie obsłużonych wyjątków wynika to z tego że implementacja takiego mechanizmu wymagała by użycia np. tasków a takie rozwiązanie było by bardzo podatne na błędy i samo w sobie potrafiło by generować sytuacje wyjątkowe ;).

Radził bym to traktować jaką pewnego rodzaju ciekawostkę ale nic nie stoi na przeszkodzie w używaniu tego w pluginach jednak lepiej przyswoić sobie wiedzę o wyjątkach z źródeł podanych na początku.

Download pliku inc na dole wpisu

Przykłady użycia :

Test1

#include <amxmodx>
#include <amxmisc>

#include <exceptions.inc>

#define PLUGIN    "New Plugin"
#define AUTHOR    "DarkGL"
#define VERSION    "1.0"

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)

    try(){
        testFunction();
    }
    catch("TestExcept"){
        new szName[ 256 ],
            szMessage[ 256 ];

        getExceptName( szName , charsmax( szName ) );
        getExceptMessage( szMessage, charsmax( szMessage ) );

        log_amx( "Print Except '%s' : %s" , szName , szMessage );
    }
}

public testFunction(){
    raise("TestExcept","Test Message");
}

Test2: można zagnieżdżać wyjątki

#include <amxmodx>
#include <amxmisc>

#include <exceptions.inc>

#define PLUGIN    "New Plugin"
#define AUTHOR    "DarkGL"
#define VERSION    "1.0"

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)

    try(){
        testFunction();
    }
    catch("TestExcept"){
        new szName[ 256 ],
        szMessage[ 256 ];

        getExceptName( szName , charsmax( szName ) );
        getExceptMessage( szMessage, charsmax( szMessage ) );

        log_amx( "Print Except '%s' : %s" , szName , szMessage );

        try(){
            testFunction2();
        }
        catch("TestExcept2"){
            new szName[ 256 ],
            szMessage[ 256 ];

            getExceptName( szName , charsmax( szName ) );
            getExceptMessage( szMessage, charsmax( szMessage ) );

            log_amx( "Print Except '%s' : %s" , szName , szMessage );
        }
    }
}

public testFunction(){
    raise("TestExcept","Test Message");
}

public testFunction2(){
    raise("TestExcept2","Test Message2");
}

Test3: można łapać kilka wyjątkow na raz

#include <amxmodx>
#include <amxmisc>

#include <exceptions.inc>

#define PLUGIN    "New Plugin"
#define AUTHOR    "DarkGL"
#define VERSION    "1.0"

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)

    try(){
        testFunction();
        testFunction2();
    }
    catch("TestExcept TestExcept2"){
        new szName[ 256 ],
        szMessage[ 256 ];

        getExceptName( szName , charsmax( szName ) );
        getExceptMessage( szMessage, charsmax( szMessage ) );

        log_amx( "Print Except '%s' : %s" , szName , szMessage );
    }
}

public testFunction(){
    raise("TestExcept","Test Message");
}

public testFunction2(){
    raise("TestExcept2","Test Message2");
}

i tutaj wychodzi pierwsze ograniczenie jeśli obie funkcje zgłoszą wyjątki to zostanie obsłużony tylko drugi czyli TestExcept2 , TestExcept zostanie w pamięci więc jeśli mamy taką sytuację powinniśmy wyczyścić pamieć z tych wyjątków w taki sposób.

poprawna implementacja

#include <amxmodx>
#include <amxmisc>

#include <exceptions.inc>

#define PLUGIN    "New Plugin"
#define AUTHOR    "DarkGL"
#define VERSION    "1.0"

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)

    try(){
        testFunction();
        testFunction2();
    }
    catch("TestExcept TestExcept2"){
        new szName[ 256 ],
        szMessage[ 256 ];

        getExceptName( szName , charsmax( szName ) );
        getExceptMessage( szMessage, charsmax( szMessage ) );

        log_amx( "Print Except '%s' : %s" , szName , szMessage );

        clearExcepts( "TestExcept TestExcept2" );
    }
}

public testFunction(){
    raise("TestExcept","Test Message");
}

public testFunction2(){
    raise("TestExcept2","Test Message2");
}

lub

#include <amxmodx>
#include <amxmisc>

#include <exceptions.inc>

#define PLUGIN    "New Plugin"
#define AUTHOR    "DarkGL"
#define VERSION    "1.0"

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)

    try(){
        testFunction();
        testFunction2();
    }
    catch("TestExcept TestExcept2"){
        new szName[ 256 ],
        szMessage[ 256 ];

        getExceptName( szName , charsmax( szName ) );
        getExceptMessage( szMessage, charsmax( szMessage ) );

        log_amx( "Print Except '%s' : %s" , szName , szMessage );

        clearExcept( "TestExcept" );
        clearExcept( "TestExcept2" );
    }
}

public testFunction(){
    raise("TestExcept","Test Message");
}

public testFunction2(){
    raise("TestExcept2","Test Message2");
}

jeżeli dwie funkcje zgłaszają ten sam wyjątek też warto to dodać 😉

#include <amxmodx>
#include <amxmisc>

#include <exceptions.inc>

#define PLUGIN    "New Plugin"
#define AUTHOR    "DarkGL"
#define VERSION    "1.0"

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)

    try(){
        testFunction();
        testFunction2();
    }
    catch("TestExcept"){
        new szName[ 256 ],
        szMessage[ 256 ];

        getExceptName( szName , charsmax( szName ) );
        getExceptMessage( szMessage, charsmax( szMessage ) );

        log_amx( "Print Except '%s' : %s" , szName , szMessage );

        clearExcept( "TestExcept" );
    }
}

public testFunction(){
    raise("TestExcept","Test Message");
}

public testFunction2(){
    raise("TestExcept","Test Message");
}

Kolejne ograniczenie to wywoływanie funkcji catch teoretycznie jeśli funkcja zgłosi wyjątek program powinien przejść od razu do bloku catch jednak nie tutaj. W naszym przypadku catch zostanie uruchomione dopiero gdy wszystkie funkcje w bloku try zostaną wykonane.

Przykład

#include <amxmodx>
#include <amxmisc>

#include <exceptions.inc>

#define PLUGIN    "New Plugin"
#define AUTHOR    "DarkGL"
#define VERSION    "1.0"

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)
    
    try(){
        testFunction();
        testFunction2();
    }
    catch("TestExcept"){
        new szName[ 256 ],
        szMessage[ 256 ];
        
        getExceptName( szName , charsmax( szName ) );
        getExceptMessage( szMessage, charsmax( szMessage ) );
        
        log_amx( "Print Except '%s' : %s" , szName , szMessage );
        
        clearExcept( "TestExcept" );
    }
}

public testFunction(){
    raise("TestExcept","Test Message");
}

public testFunction2(){
    //pass
}

funkcja testFunction() zgłosi wyjątek mimo to testFuncion2() się wykona dopiero wtedy catch złapie wyjątek

Download

exceptions.inc Download

Dodaj komentarz

This site uses Akismet to reduce spam. Learn how your comment data is processed.