PAWN jezik - Razni saveti

Započeo Dragi, Decembar 08, 2024, 04:22:39 PRE PODNE

prethodna tema - sledeća tema

0 članova i 1 gost pregledaju ovu temu.


PAWN jezik - Razni saveti


  • Rad sa karakterima i stringovima


Stringovi mogu biti u upakovanom i raspakovanom formatu. U upakovanom formatu, svaka ćelija obično sadrži 4 karaktera (u uobičajenim implementacijama, ćelija je 32-bitna, a karakter 8-bitni). U ovoj konfiguraciji, prvi karakter u "pakovanju" od 4 je najviši bajt ćelije, a ćetvrti karkater je u najnižem bajtu svake ćelije.

Ukratko: Upakovani string je array koji čuva podatke u svakom bajtu, umesto u ćeliji, za razliku od regularnih arraya. Upakovan string štedi skoro duplo memorije!

String mora biti sačuvan u nizu (Arrays). Za raspakovani string, array mora da bude dovoljno veliki da sadrži sve karaktere u stringu plus završnu nultu ćeliju. To jest, u primeru ispod, promenljiva ustring je definisana kao da ima pet ćelija, što je dovoljno da sadrži string kojim je inicijalizovana.

Listing: raspakovan string
new ustring[5] = "test"

U upakovanom stringu, svaka ćelija sadrži nekoliko karaktera i string se završava sa nultim karakterom. Char operator pomaže pri deklarisanju veličine stringa da sadrži potreban broj znakova. Primer ispod će dodeliti dovoljno ćelija da zadrži pet upakovanih karaktera. U tipičnoj implementaciji, u arrayu će biti dve ćelije.

Listing: upakovan string
new pstring[5 char] = !"test"

Drugim rečima, char operatori dele svoj levi operand brojem bajtova koji se uklapaju u ćeliju i zaokružuju nagore. Opet, u tipičnoj implementaciji, to znači deljenje sa četiri i zaokruživanje nagore.

Možete razviti procedure koje će raditi sa stringovima u upakovanom i raspakovanom formatu. Da biste saznali da li je string upakovan ili nije, pogledajte prvu ćeliju stringa. Ako je njena vrednost negativna ili premašuje maximalnu moguću vrednost za neupakovan karakter, string je upakovani. Inače je raspakovani string.

Donji isečak koda vraća vrednost true ako je ulazni string upakovan i vrednost false:

Listing: ispacked funkcija
bool: ispacked(string[])
    return !(0 <= string[0] <= ucharmax)

Raspakovani string završava se sa punom nultom ćelijom. Kraj upakovanog stringa označen je samo nulom. Pošto u 32-bitnoj ćeliji može biti do četiri znaka, ovaj nulti znak se može pojaviti na bilo kojoj od četiri pozicije u ,,pakovanju". Operator { } izdvaja znak iz ćelije u arrayu. U osnovi, koristi se operator indeksa ćelije ("[ ]") za raspakovane stringove i operator indeksa znakova ("{ }") za rad na upakovanim stringovima.

Na primer, postupak koja vraća dužinu u znakovima bilo kog stringa (upakovanog ili raspakovanog) je:

Listing: my_strlen funkcija
my_strlen(string[])
{
    new len = 0
    if (ispacked(string))
        while (string{len} != EOS)      /* get character from pack */
            ++len
    else
        while (string[len] != EOS)      /* get cell */
            ++len
    return len
}

Ako napravite da funkcije rade isključivo na upakovanim ili raspakovanim stringovima, dobra je ideja da dodate assertion da biste ispunili ovaj uslov:

Listing: strupper funkcija
strupper(string[])
{
    assert ispacked(string)
    
    for (new i=0; string{i} != EOS; ++i)
        string{i} = toupper(string{i})
}

Iako smo u prethodnim paragrafima pretpostavili da je ćelija široka 32 bita, a karakter 8 bita, na to se ne treba oslanjati. Veličina ćelije je definisana implementacijom; maksimalne i minimalne vrednosti su u unapred definisanim konstantama cellmak i cellmin. Postoje slične unapred definisane konstante za karaktere. Može se, međutim, sa sigurnošću pretpostaviti da su i veličina karaktera u bajtovima i veličina ćelije u bajtovima - stepen dvojke.

Char operator vam omogućava da odredite koliko upakovanih znakova stane u ćeliju, na primer:

#if 4 char == 1
    /* kod koji prisvaja 4 upakovana znaka po ćeliji */
#elseif 4 char == 2
    /* kod koji prisvaja 2 upakovana znaka po ćeliji */
#elseif 4 char == 4
    /* kod koji prisvaja 1 upakovan znak po ćeliji */
#else
    #assert 0 /* nepodržana veličina ćelije/karaktera */
#endif

Napomena od Dragija: Za olakšani rad sa upakovanim/raspakovanim stringovima postoji biblioteka (Autora Emmet_) za kojom sam još u potrazi. Može i na standardan način način da se radi prateći dokumentaciju kompajlera, ali onda rizikujete gubitak živaca i vremena. Bićete obavešteni kad pronađem, ako Bog da.  :D


  • Rad s tagovima


Sistem naziva oznaka (tagova) je izmišljen da se doda mehanizam ,,provere korišćenja" (usage checking) PAWN-u. Oznaka (tag) označava ,,svrhu" vrednosti ili promenljive, a kompajler izdaje dijagnostičku poruku kada se oznaka izraza ne podudara sa potrebnom oznakom za kontekst izraza.

Mnogi savremeni kompjuterski jezici nude tipove promenljivih, gde tip specificira raspored memorije i svrhu promenljive. Programski jezik zatim proverava ekvivalentnost tipa; PASCAL jezik je veoma striktan u proveri jednakosti tipova, dok je programski jezik C više oprostljiv. Jezik PAWN nema tipove: sve varijable imaju veličinu i layout ćelije, iako bitni prikazi u ćeliji mogu zavisiti od svrhe promenljive. Ukratko:

  • tip specificira raspored memorije i opseg promenljivih i rezultata funkcija
  • tagname označava svrhu promenljivih, konstanti i rezultata funkcije

Oznake u PAWN-u su uglavnom opcione. Program koji je bio ,,obogaćen" tagovima na deklaracijama promenljivih i konstanti će funkcionisati identično kada se uklone svi tagovi. Jedan izuzetak čine korisnički definisani (user-defined) operatori: pawn kompajler koristi oznake operanada da bira između bilo kojih korisnički definisanih operatora i standardnog operatora.

Isečak ispod deklariše tri varijable i obavlja tri dodele, od kojih dve daju dijagnostičku poruku ,,nepodudaranja oznaka" (tag mismatch):

new apple:elstar        /* varijabla "elstar" sa tagom "apple" */
new orange:valencia    /* varijabla "valencia" sa tagom "orange" */
new x                  /* neoznačena varijabla "x" */
elstar = valencia      /* tag mismatch */
elstar = x              /* tag mismatch */
x = valencia            /* ok */

Prvo dodeljivanje izaziva dijagnostiku ,,nepodudaranja oznaka" (tag mismatch) jer promenljivoj sa oznakom ,,apple" dodeljuje promenljivu označenu ,,orange". Drugo dodeljivanje stavlja neoznačenu vrednost x u označenu promenljivu, što ponovo izaziva dijagnostiku. Kada se neoznačena promenljiva nalazi na levoj strani operatora dodeljivanja, kao u trećem dodeljivanju, nema upozorenja ili poruke o grešci. Pošto je promenljiva x neoznačena, može prihvatiti vrednost bilo koje slabe oznake.

Povremeno je potrebno privremeno promeniti oznaku izraza. Na primer, sa deklaracijama prethodnog isečka koda, ako želite da uporedite jabuke sa narandžama (istraživanja često pokazuju da poređenja koja se čine neobičnima mogu imati svoje opravdanje), možete koristiti:

if (apple:valencia < elstar)
  valencia = orange:elstar

Test izraz if naredbe (između zagrada) upoređuje promenljivu valencia sa promenljivom elstar. Da bi se izbegla dijagnostika ,,tag mismatch", postavlja se oznaka koja nadjačava apple: na valencia — nakon toga, izrazi na levoj i desnoj strani operatora > imaju isto ime oznake: ,,apple:". Drugi red, dodeljivanje elstar na valencia, zamenjuje naziv oznake elstar ili orange: pre dodele. U dodeli, ne možete zameniti naziv oznake odredišta; tj. levo od operatora =. Greška je napisati ,,apple:valencia = elstar". U assgingmentu, valencia je ,,lvalue" i ne možete zameniti naziv oznake lvalue.

Kao što je ranije prikazano, kada leva ruka dodele sadrži neoznačenu promenljivu, izraz s desne strane može imati bilo koje slabo ime oznake. Kada se koristi kao lvalue, neoznačena promenljiva je kompatibilna sa svim slabim imenima oznaka. Ili bolje rečeno, slaba oznaka se tiho ispušta kada je dodeljena neoznačenoj promenljivoj ili kada se prosleđuje funkciji koja očekuje neoznačeni argument.
Kada ime oznake ukazuje na bitni obrazac ćelije, tiho ispuštanje slabe oznake može sakriti greške. Na primer, isečak ispod ima grešku koja nije odmah očigledna:

Listing: loš priemer korišćenja tagova
#pragma rational float

new limit = -5.0
new value = -1.0

if (value < limit)
    printf("Vrednost %f je ispod granice %f\n", value, limit)
else
    printf("Vrednost iznad granice\n")

Kroz ,,#pragma rational", svi racionalni brojevi dobijaju ,,float" naziv oznake i ovi brojevi su kodirani u 4-bajtnom IEEE 754 formatu. Ovo deklariše dve promenljive, limit i value, od kojih su obe neoznačene (ovo je greška). Iako su literalne vrednosti -5.0 i -1.0 implicitno označene sa float:, ova slaba oznaka se tiho ispušta kada se vrednosti dodeljuju neoznačenim simbolima limit i value. Sada, if naredba upoređuje value sa limit kao celim brojevima, koristeći ugrađeni standardni < operator (korisnički definisani operator bi bio prikladniji za upoređivanje dve IEEE 754 kodirane vrednosti). Kada se pokrene, ovaj isečak koda nam govori da je ,,Vrednost -1,000000 je ispod granice -5,000000" — što je, naravno, netačno.

Da biste izbegli da takve suptilne greške ostanu neotkrivene, trebalo bi da koristite jake oznake. Jaka oznaka je samo ime oznake koje počinje velikim slovom, kao što je Float: umesto float:. Jaka oznaka nikada nije automatski ,,ispuštena", ali ipak može biti eksplicitno zamenjena. Ispod je modifikovani isečak koda sa predloženim adaptacijama:

Listing: jake oznake su bezbednije
#pragma rational Float

new Float:limit = -5.0
new Float:value = -1.0

if (value < limit)
    printf("Vrednost %f e ispod granice %f\n", _:value, _:limit)
else
    printf("Vrednost iznad granice\n")

Zaboravljen Float: tagname u deklaraciji promenljivih limit ili value odmah daje dijagnostiku ,,tag mismatch", jer literalne vrednosti -5.0 i -1.0 sada imaju jako ime oznake.

Povremeno ćete možda želeti da proverite koju oznaku ima stvarni argument funkcije, kada argument prihvata oznake za množinu. Provera oznake formalnog argumenta (u telu funkcije) nije od koristi, jer će uvek imati prvu oznaku na listi oznaka u deklaraciji argumenta funkcije. Možete proveriti oznaku stvarnog argumenta dodavanjem dodatnog argumenta funkciji i postaviti njegovu podrazumevanu vrednost da bude ,,tagof" argumenta. Slično operatoru sizeof, operator tagof ima posebno značenje kada se primenjuje u podrazumevanoj vrednosti argumenta funkcije: izraz se vrednuje u tački poziva funkcije, umesto u definiciji funkcije. To znači da je ,,podrazumevana vrednost" argumenta funkcije stvarna oznaka parametra koji je prosleđen funkciji.

Unutar tela funkcije možete da uporedite oznaku sa poznatim oznakama koristeći operator tagof.


  • Povezivanje linija


PAWN je jezik slobodnog formata, ali direktive parsera moraju biti u jednom redu. Nizovi se takođe ne mogu odvijati preko nekoliko redova. Kada je ovo nezgodno, možete koristiti obrnutu kosu crtu (,,\") na kraju reda da ,,zalepite" tu liniju sa sledećim redom.

Na primer:
#define    max_path max_drivename + max_directorystring + \
            max_filename + max_extension

Takođe koristite znak za spajanje da biste presekli dugačke literalne nizove preko više linija. Imajte na umu da ,,\" jede sav završni beli prostor koji dolazi posle njega i vodeći beli prostor u sledećem redu. Primer ispod ispisuje ,,Hello world" sa jednim razmakom između dve reči (jer postoji razmak između ,,Hello" i obrnute kose crte):

print("Hello \
    world")
(Kraj dokuemntacije, 8.12.2024.)


Prevod i adaptacija na srpski jezik: Dragan Avdić (Dragi)


Literatura:

- "Pawn embedded scripting language - The Language" ITB CompuPhase, February 2006
Poslednja Izmena: Decembar 08, 2024, 05:08:27 PRE PODNE od Dragi