Értékadás
Értékadó operátorok
= |
&= |
|= |
^= |
<<= |
>>= |
+= |
-= |
*= |
/= |
%= |
Egyszerű értékadás (=)
Általában a jobb és bal oldali operandusnak azonos adattípusúnak kell
lennie. Az értékadás értéke az új bal oldali operandusa. Minden értékadó operátor jobbaszociatív.
Az =-vel jelölt közönséges értékadásban a jobb oldal értékét értékül adjuk a
bal oldali objektumnak. Az egyszerű értékadásoknál a bal oldali operandus lehet balértékek zárójelezett listája, a
jobb oldali operandus pedig sor, vagy olyan adt, melynek tagjai számosságban és típusban is megegyeznek a listabeli balértékekkel. A sor elemei, vagy az adt adattagjai sorban hozzá vannak rendelve a lista balértékeihez. Például:
p: Point;
x, y: int;
(x, y) = p;
az p pont koordinátáit
x és
y egészekre bontja.
Ezen szabályok rekurzívan hajtódnak végre, így ha a bal oldal valamely komponense balértékek zárójelezett listája, a
jobb oldalon szereplő megfelelő adt-hez vagy sorhoz lesz hozzárendelve.
Ha az egyszerű értékadás bal oldali operandusa egy adt, a jobboldali pedig egy sor, akkor az értékadás a
sor tagjainak értékét hozzárendeli az adt adattagjaihoz, ezeknek számosságban és típusnak egyeznie kell a sor tagjaival.
A konstans
nil értékül adható bármely referencia típusú balértéknek.
Az értékadásás bal oldalán is szerepelhet
nil, ami azt jelzi, hogy a neki megfelelő értéket figyelmen kívül hagyjuk. Ez
vonatkozik bal oldalon szereplő sor bármely balértékére. Az előző példánkat felhasználva:
(x, nil) = p;
a
p pont
x tagját az
x változó értékére állítja.
Egy speciális megfontolás érvényes a sztringekre. Ha egy Unicode karaktert tartalmazó
int-et adunk értékül egy indexelt sztringnek, az indexnek általában egyeznie
kell a sztringen belül. Speciális esetben az index értéke megegyezhet a sztring hosszával, ekkor a karaktert hozzáfűztük a sztringhez, és annak hossza eggyel növekedett.
Az
e1[e2:] alakú tömb szeletek is speciális esetet képeznek. Ilyen kifejezések az
= bal oldalán fordulhatnak elő. A jobb oldalnak az
e1 típusával megegyező tömbnek kell lennie, melynek hossza kisebb vagy egyenlő kell legyen mint
(
e1 hossza) -
e2. Ebben az esetben az
e1 elemei
e2 pozíciótól kezdődően kicserélődnek a
jobb oldali tömb elemeire. A tömb hossza változatlan marad.
Összetett értékadás (op=)
A legtöbb kétoperandusú operátor szerepelhet az értékadó
operátorban, melynek általános alakja op=. Ha e1 és e2
két kifejezés, akkor
e1 op= e2;
egyenértékű a
e1 = (e1) op (e2);
alakkal. A tömörebb forma előnye, hogy
e1 csak egyszer számolódik
ki.
Szekvencia
A ";" elválasztja az utasításokat, üres
utasítás is lehet.
Utasítások sorozatából alkothatunk egy összetett utasítást, blokkot.
A blokk kezdetét és végét "{" és "}"
jelzi. A blokkban elhelyezhetünk deklarációt, az ott deklarált változó láthatósága a blokk végéig tart.
Elágazás
Az egyirányú elágazás
általános formája:
if ( kifejezés ) utasítás(ok)
if ( kifejezés ) utasítás(ok) else utasítás(ok)
Ha a
kifejezés értéke, mely int típusú kell legyen, igaz (nem nulla), akkor az első utasítás vagy utasítások sorozata hajtódik végre. Ellenkező esetben a második. Például:
if(guess == randnum)
sys->print("Correct!\n");
else
sys->print("Oh, sorry.\n");
Az
if utasítás beágyazható. Az
else mindig az ugyanazon blokkban lévő legközelebbi
else-nélküli
if-hez tartozik. Például:
if(i == j) {
if(k == l) { ... }
if(m == n) {
...
} else { # ez az else
... # 'if(m == n)'-hez tartozik
}
} else { # ez az else
... # 'if(i ==j)'-hez tartozik
}
A
többirányú elágazás általános
alakja:
case kifejezés {
minősítő =>
utasítás
...
}
A
kifejezés int vagy
string típusú kell legyen. A
minősítő(k) lehet konstans illetve intervallum, és az értékek között nem lehet átfedés. Ha nincs megfelelő minősítő, és adva van az alapértelmezett ág (*), akkor ennek utasításai hajtódnak végre. Mindegyik minősítő és az őt követő utasítássorozat blokkot alkot.
A case utasítás szintaxisa a C/C++ switch utasításához hasonló. Például:
case i {
1 or 8 =>
sys->print("Begins with a vowel\n)";
0 or 2 to 7 or 9 =>
sys->print("Begins with a consonant\n");
* =>
sys->print("Sorry, didn't understand\n");
}
A C-vel ellentétben, a kiválasztott minősítőhöz tartozó blokk végrehajtása után a vezérlés nem csorog rá a kővetkező minősítőre. Nincs szükség explicit
break utasításra.
A case utasításoik egymásba ágyazhatóak, például:
case x {
1 =>
case y {
0 =>
...
1 =>
...
}
2 =>
...
}
Ciklus
A Limbo nyelvben három ciklus utasítás van: while, do és for ciklusok.
Mindegyik ciklusutasításhoz tartozhat egy címke, melyet a break és
continue ugró utasításokkal együtt használhatunk.
Ismert lépésszámú ciklus (for)
Általános alakja:
for(exp1; exp2; exp3)
mag;
A zárójelben lévő három kifejezés bármilyen érvényes Limbo kifejezés
lehet.A leggyakrabban használt kifejezések a következők:
*
exp1 az index változó inicializálása vagy rá vonatkozó értékadás
*
exp2 teszt a ciklus folytatásához
*
exp3 az index változó egyes iterációk során bekövetkező módosítása (csökkentése v. növelése)
A
mag lehet üres, egyszerű utasítás, vagy blokk. Például:
i: int;
for(i = 1; i <= 100; i++)
sys->print("%d ", i);
A fenti példában az
i indexváltozót a ciklus előtt inicializáltuk, de ez nem kötelező, a köv. kódrészlet is helyes:
for(i := 1; i <= 100; i++)
sys->print("%d ", i);
Nem ismert lépésszámú ciklusok
While
Általános alakja a következő:
while(feltétel)
utasítás;
Ha a
feltétel igaz, végrehajtódik az
utasítás. Az
utasítás
lehet üres, egyszerű utasítás, vagy blokk.
Példa:
n := 1;
while(n <= 100)
sys->print("%d ", n++);
Do... while
Az előző kettővel ellentétben, a
do... while hátultesztelős ciklus. Az iteráció végén ellenőrzi a feltétel teljesülését, így a ciklus magja legalább egyszer végrehajtódik.
Általános alakja a következő:
do
mag;
while(feltétel);
A
mag lehet üres, egyszerű utasítás vagy blokk. A
mag végrehajtása addig ismétlődik, amíg a
feltétel igaz.
Példa:
n := 1;
do {
sys->print("%d ", n++);
} while(n <= 100);
Ha a
mag egyetlen blokk utasításból áll, az olvashatóság végett azt is zárójelek közé (()) szokták tenni.
Vezérlésátadó utasítások
A nyelv két vezérlésátadó utasítással rendelkezik: break
és continue.
A kulcsszó után egyik esetben sem kötelező azonosítót megadni. Ha nem adunk meg azonosítót, a vezérlés átadódik a ciklus legbelső részutasítása végére, amelyben kulcsszó rézutasításként szerepel.
A break utasítás
Lehetővé teszi a ciklusok idő előtti elhagyását,
valamint a case és alt utasításokból való kilépést.
Ha a ciklus beágyazott, a break csak az őt tartalmazó blokkban lévő ciklust terminálja. Példa:
for(t:=1; t<=5; t++) {
i := 1;
for(;;) {
sys->print("%d ", i++);
if(i == 10)
break;
}
}
A fenti kódrészlet ötször kiírja a számokat 1-től 9-ig. A
break utasítás csak a belső
for ciklust terminálja.
A continue utasítás
A continue utasítás a break utasításhoz kapcsolódik. A
ciklusmagban található continue utasítás hatására azonnal (a ciklusmagból
még hátralévő utasításokat figyelelmen kívül hagyva) megkezdődik a következő
iterációs lépés.
Példa:
for(;;) {
n := sys->read(fd, buf, len buf);
if(n <= 0)
break;
if(int buf[0] != 'm' || n != 37)
continue;
}
A fenti kódrészlet bájtokat olvas folyamatosan egy fájlból, amíg
end-of-file
jelet nem talál.
Címkék
A címkék nevet adnak a for, while és do... while ciklusoknak, valamint a
case és alt utasításoknak. Felhasználhatjuk őket címkézett szerkezet belsejében lévő
break és continue utasításokban, hatásukra átadódik a vezérlés a címkézett blokk végére. Nincs
go to utasítás.
A címkéket két tipikus esetben használják. Az egyik, amikor belső ciklus számára lehetővé
teszik az őt befoglaló külső ciklusra break vagy continue kiadását. A másik felhasználás, amikor a ciklust befoglaló külső
utasítást megszakítják belső case vagy alt utasításból.
Tekintsük a következő példát. Az utasításokhoz egy vagy több opció is csatolható:
Args:
for(i := 0; i < len in; i++){
case in[i] {
'v' =>
opt |= Verbose;
's' =>
opt |= Suppress;
'o' =>
opt |= OutFile;
* =>
break Args;
}
}
Mindaddig, amíg az
in string
i. eleme érvényes opció (
v,
s vagy
o), a feldolgozás folytatódik, megkezdődik a for ciklus újabb iterációja. Mihelyt más karaktert talál, a
break utasítás terminálja a végrehajtást.
Ha a címkét nem
break utasítással használják, a for ciklus újabb iterációt hajt végre.
A következő példában láthatjuk, hogyan használható fel a címke többszörösen beágyazott ciklusból való kilépésre:
u := 0;
line := "<A HREF="
URL := "";
Outer:
for(i := 0; i < len line; i++)
if(line[i] == '<') {
while(line[++i] != '>') {
if(line[i:i+6] == "A HREF") {
i += 6;
if(line[i] == '=') {
i += 2;
while(line[i] != '"')
URL[u++] = line[i++];
}
}
break Outer;
}
}