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