A BETA programozási nyelv

Vezérlési szerkezetek



Deklarációk

A BETA-ban statikus és dinamikus referenciákat deklarálhatunk - mindkettőt kizárólag a minták deklarációs részeiben. A statikus referencia a program futása alatt rögzített módon kapcsolódik egyetlen objektumhoz, a dinamikus referencia viszont futási időben más-más objektumhoz is kapcsolható. Ebből az is látszik hogy a BETA-ban minden referencia, de a referencia nevének leírásával nem a pointerre, hanem az általa mutatott memóriaterületre hivatkozunk. A pointert speciálisan kell jelölni, mint már láttuk a jelöléseknél.

i: @integer; statikus referenciát jelöl
i : ^integerObject; dinamikus referenciát jelöl

Megjegyzés: Az alapmintáknak megfelelő típusú változók csak statikus referenciájúnak deklarálhatók, dinamikus referenciát a velük rokon Object végződésű predefinit mintákra (pl. integerObject, charObject, realObject stb.) alkalmazhatunk.

A deklarált változók mindig a deklarációjukat tartalmazó mintában, illetve az adott mintában deklarált mintákban láthatóak közvetlenül, ilyen szempontból a minta hagyományos értelemben vett blokként működik. A mintán belül deklarált értékekre kívülről csak a tagkiválasztó operátorral lehet hivatkozni: objektum_neve.tag_neve.

A minta hívása úgy történik, hogy a minta híváskor lemásolódik, megkapja az input változókat, valamint egy listán azokat a változókat, melyek láthatósági köre kiterjed rá.

Megfeleltetés - értékadás

A megfeleltetés jele a ->. A megfeleltetésekből tetszőleges hosszú láncot lehet fűzni. Ez használható a hagyományos értelemben vett értékadás helyett, valamint a paraméterek átadására, illetve átvételére is. Ha meggondoljuk, ez jogos, hiszen az értékadást a minta meghívásával hajtjuk végre, tehát valójában az értékadás a minta futtatása. Ennek megfelelően, ellentétben a megszokottal, az értékadás balról jobbra történik. A megfeleltetés általános példája:

(x,y) -> függvény -> (v,w)

Ilyenkor a függvény átveszi az x, y paramétereket, lefut, majd a visszatérési értékeit a v, w változókba tölti. Azt gondolhatnánk, hogy így szimultán értékadás is írható a függvény elhagyásával, de ez nem az, mert valójában megfelel két értékadás szekvenciájának, így például az (x, y)-> (y, x) értékadás esetén x és y értéke is x lesz.

2 -> i; (* i értéke 2 lesz *) x+dx -> x; (* x értéke x+dx lesz *)

Példa: Helloworld

Amennyiben pointer típusú változónak akarunk értéket adni vagy helyet foglalni, akkor ezt a következő módon tehetjük meg:

(# R: @T; R1: ^T; ... do R[] -> R1[]; (* Az R1 mint pointer rááll R-re. *) &T[] -> R1[]; (* Lefoglalódik egy T mintájú változó, és R1 rááll, de nem fut le. *) &T -> R1[]; (* Mint az előbb, de le is fut. *) ... #)

Példa: Referenciák

A megszokott vezérlési szerkezeteket kontrollstruktúrák segítségével valósították meg. A vezérlési szerkezeteknél a # jel helyett a vezérlőszerkezet neve áll, például: (if ... if).

Feltételes utasítás

A feltételes utasítás általános alakja:

(if <kifejezés> // <érték_1> then <utasítások_1> // <érték_2> then <utasítások_2> ... // <érték_n> then <utasítások_n> else <utasítások> if);

A kifejezés lehet logikai, egész vagy valós értékű; mivel a karakter értékek egész értékeknek felelnek meg, ezek is használhatók. (A valós értékű kifejezések egyenlőség-vizsgálata okozhat meglepetéseket a számábrázolás módja miatt.) Az if utasítás összehasonlítja a kifejezés értékét az egyes eseteknek megfelelő - a // jelek és a then kulcsszó közti - értékekkel. Ha egyik egyenlőségvizsgálat sem teljesül, akkor az else ág hajtódik végre. Ha több összehasonlítás is telejül, akkor ezek közül véletlenszerűen választ egyet, és azt az ágat futtatja le.
Sok más nyelvektől eltérően az egyes ágaknak megfelelő érték nem csak konstans, illetve azok listája lehet (mint például C/C++-ban a switch/case, illetve Adában a case/when esetén).

a, b: @integer; x, y: @real; ... do ... (if y<0 (* Szokásos kétirányú elágazás logikai kifejezés alapján. *) // true then ... else ... if); ... (if x<0 (* Lehet fordítva is :) *) // false then ... // true then ... if); ... (if true (* Így is lehet. *) // (x<0) and (b=42) then ... (* Használhatók a logikai műveletek. *) // (x>0) xor (a=-42) then ... (* Több igaz ág esetén véletlenszerűen dönt. *) // x>=0 then ... else ... if); ... (if a (* Elágazás egész értékű kifejezés alapján. *) // 42 then ... // 84 then ... // b-5 then ... (* Nem csak konstans szerepelhet! *) else ... if);

Ciklusok

For ciklusok

(for <range> repeat <utasítások> for);

A range egy egész érték; a for ciklus törzsében az utasítások range-szer hajtódnak végre.

(for <my_index>:<range> repeat <utasítások> for);

A my_index ciklusváltozó 1-től range-ig fut. Az utasítások között nem lehet a ciklusváltozót megváltoztatni, de értékül adni lehet. A ciklusváltozó csak a cikluson belül látható.

Példaprogram: Szorzótábla

A betaEnv könyvtárban találhatunk még egy "for típusú" ciklusmintát, a forTo-t:

forTo: (# low, high, inx: @integer; enter (low, high) do ... INNER; ... #);

Az inx ciklusváltozó fut lowtól highig. A következő példa bemutatja a forTo használatát; a négyzetszámokat írja ki 9-től 121-ig:

(3,11) -> forTo(# do inx*inx->putint; newline; #);

A cycle és loop ciklus

További ciklusmintákat is találhatunk a betaEnv könyvtárban: a cycle és a loop.

my_label: cycle (# <deklarációk> do <utasítások> #);

Ez egy végtelen ciklus, hacsak az utasítások között nem szerepel a leave my_label; utasítás.

loop (# while ::< booleanValue (# do <utasítások_1> #); until ::< booleanValue (# do <utasítások_2> #); <deklarációk> do ... #)

A while illetve az until blokkrész opcionális, nem szükséges mindkettőt megadni. Példa a használatára:

loop (# while ::< (# do getint->i; i>0->value #); until ::< (# do sum>1000->value #); sum,i: @integer; do i+sum->sum; #);

Az előző ciklus integer számokat olvas be mindaddig, amíg vagy egy nempozitív integer írunk be, vagy pedig a beolvasott számok összege meghaladja az 1000-t. A value változót látszólag sehol sem deklaráltuk, valójában a betEnv-ben van deklarálva. Szerepe: a while, illetve az until blokk eredményét kell tartalmaznia, vagyis az értékétől függ, hogy a ciklus ismét lefut-e.

Példa: Négyzetgyök

Blokk utasítás

my_label: (# do <utasítások> #)

Ez egy olyan blokk, melyben restart my_label; utasítással vissza lehet térni a blokk elejére, a leave my_label; utasítással pedig el lehet hagyni a blokkot. A címkére csak a blokkon belül lehet hivatkozni.

Láthatóság, élettartam, elérhetőség

Dinamikus helyfoglalás és felszabadítás

A dinamikus helyfoglalásra a new operátort kell használni, jele : &

Point: (# x,y: @real; enter (x,y) #); (* síkbeli pont *) refA: ^Point; (* dinamikus referencia deklarálása *) ... do (* (4.5, 6.7)->refA; Itt refA még nem mutat sehova; futási idejű hibát okozna. *) &Point[]->refA[]; (* Új din. ref. létrehozása, majd refA megkapja a címét. *) (* A [] jelentése: referenciára (nem értékre) való hivatkozás. *) (4.5, 6.7)->refA; (* Itt refA már használható. *) refA.y->putreal; (* Szelektor használata *)

A lefoglalt memória felszabadítása automatikus, ezt a garbage collector (szemétgyűjtő) végzi.

Láthatóság és az attribútumokhoz való hozzáférés

A BETA-ban nincsenek védett változók, minden minta láthat minden más mintában megadott változót.

Egyébként a láthatósági szabályokat a blokkstrukturált nyelvekben megszokott módon adták meg.

Az attribútumokhoz való hozzáférés a szokásos módon, a pont tagkiválasztó operátor (szelektor) segítségével történhet:

p: @Point; ... do 0.4 -> p.x; 1.2 -> p.y; p.x -> putreal;

A BETA-ban nyelvi szinten nem megoldott az adatok elrejtésének lehetősége, ezt csak a BETA-hoz készített programrendszer (A fragment-rendszer) segítségével lehet némileg szabályozni.