( uid_21365 | 2020. 11. 27., p – 16:00 )

vagy a "string" a nyelvedben a "void *" megfelelője (simán memóriaterület, igazából típus nélkül, azt dobálok bele, amit akarok;

Nagy vonalakban erről van szó, hiszen írtam is fentebb, a string nálam lényegében egy univerzális objektum, mert az elemei 8 bájtos egységek. Azaz bármit „beledobálhatsz” ezen elemekbe, számokat is, mely számok így nem kaarakterenként hanem rendesen bináris értékekként vannak kódolva. Hiszen 8 bájtba simán belefér egy signed vagy unsigned long long érték is, vagy egy double is...

A stringjeimnek természetesen van egy rakás metódusa, ezek nagy része simán működik akkor is ha nem karakterek hanem ilyen számok vannak eltárolva bennük. Más metódusok alkalmazásának nyilván csak akkor van értelme ha a string karaktereket tartalmaz, ilyen például a kiiratás. Azt hogy konkrétan MI van tárolva a string által lefoglalt memóriaterületen, a string nem tartja nyilván. Számára az mind csak ilyen 8 bájtos egységek sorozata.

Azt tehát hogy egy memóriaterületen, sőt, egy tetszőleges változóban épp milyen típusú adat van, azt nálam egyáltalán semmi se tárolja! Pontosabban, csak nagyon speciális esetekben van tárolva és rém kevés információ róla - nagyjából csak két ilyen dolog tárolt:

1. A stringem azt képes tárolni magában hogy ő egy stringtömb-e igazából, azaz hoghy az elemei más stringekre mutató pointerek-e.

2. Az is tárolva van egy ilyen stringtömbben, hogy „közönséges” módon történt-e a memóriafoglalása vagy a shared memory területén. Ez szükséges hogy tárolva legyen, mert ugye a memória felszabadítása mindegyik esetben másképp történik.

De az NINCS tárolva, hogy a stringben most épp karakterek vannak tárolva, vagy double számértékek vagy akármi más. Akár vegyes mindenfélék is lehetnek benne tárolva, az első bájton egy unsigned int, aztán egy double, aztán karakterek, vagy bármi amit akarsz. A stringnek mindegy.

Miután nagyon megkritizálnátok e módszert, sietve közlöm, nem is titkolom hogy a nyelvem jelentős ihleteket merített a FORTH-ból, s ott is az a helyzet hogy a stackban tárolt adatnak nincs valamiféle rögzített típusa! Nem kell külön castolni, stb. Az csak egy bájt vagy bájtok sorozata, a programozón múlik, mit kezd vele.

A Peri esetén a helyzet dettó ugyanez. Természetesen vannak mindenféle műveletek a különböző típusú elemi adatok megfelelő kezelésére, de nincs nyilvántartva a gép által, az az adat milyen típusú „igazából”. Minden a programozó felelőssége.

A Peri nem véd meg téged attól, hogy hülyeséget kövess el. A Peri nem uralkodni akar rajtad hanem kiszolgálni. A Peri készítésekor a filozófia az volt hogy 2 dolog fontos:

1. A nyelv legyen a lehető leggyorsabb, legalábbis interpreterekhez képest.

1. A nyelv legyen minél könnyebben bővíthető is, utólag, amikor már nagyjából „elkészült”, külső, C/C++ nyelven írható libekkel, hogy ahol mégis lassú lenne ott kisegítsük őt a natív kód sebességével, meg hogy új funkciókkal is felruházhassuk. Utóbbi érdekében a Peri direkt úgy lett konstruálva, hogy a külső libekben tárolt funkciókhoz könnyedén lehessen tetszőleges kulcsszavakat hozzárendelni, s ezek aztán a Peri kódban éppoly könnyen használhatóak legyenek mint ami a Core-ban van implementálva, pontosan ugyanolyan szintaxissal is ráadásul.

E két szempontnak lett alárendelve minden. Vagyis ami nem igazán volt szempont:

—memóriaspórolás (a RAM olcsó manapság)

—folyamatos aggódás az interpreter részéről hogy „kedves programozó, biztos ezt akarod-e, ez veszélyes”

—infix notation (lelassítaná az interpretert)

—Tulajdonképpen még a kód olvashatósága se volt igazán szempont. Azért nem, mert fentebb említettem hogy a Peri könnyedén bővíthető libek által új utasításokkal. Ezen utasításoknak tetszőleges nevet lehet adni, sőt még a szintaxisukat is meghatározhatod. A már elkészült libekben található függvényeknél is meghatározhatod ha neked úgy tetszik hogy ezentúl más néven hívd őket a Peri kódban, s ehhez még csak bele se kell nyúlnod abba a már elkészült libbe, mindössze egy headerfájlt kell szerkesztened, egy tök egyszerű szöveges fájlt! Íme egy példa erre:

{ „__alsalib__” }
{ „__ALSAflag__” }
@__ALSAflag__  inv { one __ALSAflag__
::: __alsalib__ "/Inanelib/libinanelib_alsa.so.1.0.1" // Load the external library
:getvolume __alsalib__ "getvolume"
:setvolume __alsalib__ "setvolume"
:mute      __alsalib__ "mute"
:unmute    __alsalib__ "unmute"
:getmute   __alsalib__ "getmute"
}

 

A fenti az alsa.uh headerfájlja. Kevés funkció van még benne perpillanat de ez most mindegy. A lényeg hogy a 3 darab kettősponttal kezdődő sor betölti a libet, az 1 darab kettősponttal kezdődő kulcsszavakba meg aztán betöltjük a megfelelő függvényt. Akinek tehát tegyük fel nem tetszik az unmute kulcsszó, annak elég e fájlt szerkesztenie úgy, hogy e sort:

:unmute    __alsalib__ "unmute"

kicseréli erre:

:némítás_feloldása    __alsalib__ "unmute"
 

és ezentúl a Peri programok mindegyikében ahova e headerfájlt includeolja be, ő használhatja a

némítás_feloldása

kulcsszót ha neki ez úgy tetszik!

Mindez gyakorlatilag minden olyan krikszkrakszra is vonatkozik, amit láthattok a programjaimban, s amit olvashatatlannak ítéltek. Akinek tehát ez nem tetszik, megváltoztathatja.

Van ugyan néhány szabály a tokenizáláskor, amit a tokenizáló figyel, például hogy a kulcsszavak elején vagy végén van-e felkiáltójel meg sok más ilyesmi, ezeknek megfelelően beállít bizonyos flageket, de szerencsére ez úgy működik hogy egy utasítás megírásakor nem kötelező figyelembe venni minden variációt. Végeredményben minden nkulcsszó a Periben annyi sokféle toldalékkal meg prefixummal ellátható, hogy több mint tizenhatezer variációban létezhet ha jól számolom... Nyilvánvaló, hogy képtelenség lekezelni minden lehetőséget egy függvény megírásakor! DE EZ NEM IS SZÜKSÉGES. Ott van például a fent említett unmute kulcsszó. Ez az egyetlen variációja amihez jelentést rendeltem hozzá az ALSA libben. Ez azt jelenti hogy hiába írjuk e variációkban:

unmute!

!unmute

!unmute!

?!unmute[]()

unmute[3]

unmute§label

inv arc ?!unmute@()[]?!#g[37]§label§

(igen, még e legutóbbi is lehetséges ELVILEG. Gyakorlatilag azonban nincs ilyesmi a nyelvemben, megnyugodhattok!)

szóval hiába írjuk le a fenti formák bármelyikében az unmute kulcsszót: minthogy ezen variációk nincsenek lekezelve a libraryban implementált függvényben, ez azt jelenti automatikusan, hogy MINDEGYIK variáció esetén pontosan ugyanaz történik mintha a legközönségesebb szimpla módon egyszerűen az

unmute

kulcsszót használnánk...

Ez tehát mind csak LEHETŐSÉG, amivel nem muszáj élni...

Akadnak dolgok, amik nem ilyen könnyen megváltoztathatóak, például a ciklusokkal kapcsolatos szimbólumok, de még azok is megváltoztathatóak, csak icipicit nehezebb azokkal a helyzet. Ott is egyetlen állományba kell belenyúlni, de ahhoz már aztán újra kell fordítani a Perit. De pofonegyszerű az is, egy stringtömbben kell átírni fordítás előptt a megfelelő kulcsszót és kész.

A Peri esetén tehát messzemenő gondot fordítottam arra, hogy mindenki személyre szabhassa a tetszése szerint! Nem érdemes tehát itt a HUP-on vérre menő vitákat folytatni a kulcsszavak felett. NEM ÉRDEMES. Amint közzéteszem, úgyis mindenki könnyedén kicserélheti őket a neki tetszőekre. Elárulom, a Peri annyira szélsőséges mértékben customizable, hogy mindössze külső library által még az egyesek által annyira óhajtott infix notation is beleerőltethető - nyilván persze ennek sebességlassulás lesz az ára. De megoldható.

A Peri ugyanis szándéka szerint egy meglehetősen „üres” nyelv, ami alig csinál többet mint a paramélterátadást biztosítja a minimális core és a libek közt. Ez az üresség egyfajta jelképe is a Perinek, ezért van az hogy e sorban a fenti példa esetén:

::: __alsalib__ "/Inanelib/libinanelib_alsa.so.1.0.1" // Load the external library

az a szó szerepel hogy "Inanelib" és nem "Perilib". Inane van ott, ami angolul ugye olyasmit jelent hogy „üres”. Mert arra utal, a libek nélkül a Peri „üres”, alig van benne valami.