ALGOL-M

Tartalom

1. Bevezetés
1.1. Az ALGOL 60 nyelv története, szintjei
1.2. Alapfogalmak

2. Aritmetikai és logikai kifejezések
2.1. Bevezetés
2.2. Számok
2.3. Változók és azonosítók
2.4. Aritmetikai műveletek
2.5. Feltétlen aritmetikai kifejezések
2.6. Logikai műveletek
2.7. Relációk
2.8. Feltétlen logikai kifejezések

3. Utasítások
3.1. Bevezetés
3.2. Értékadó utasítások
3.3. Címkék és vezérlésátadó utasítások
3.4. Feltételes utasítások és feltételes kifejezések
3.5. Összetett utasítások
3.6. Indexes változók
3.7. Ciklusutasítások
3.8. Kiválasztó utasítás

4. A program kísérő információi
4.1. Bevezetés
4.2. Típusdeklarációk
4.3. Tömbdeklarációk
4.4. A címkék hatásköre
4.5. Magyarázó megjegyzések a programban

5. Eljárások
5.1. Bevezetés
5.2. Eljárás deklaráció és eljárás utasítás
5.3. Függvényeljárások
5.4. Rekurzív eljárások és rekurzív függvénybehívások

6. A perifériális egységekre hivatkozó I/O utasítások
6.1.Bevezetés
6.2. A READ és WRITE utasítások
6.3. File-műveletek

7. A program fordítása, futtatása
7.1 Hibakódok

1. Bevezetés

1.1. Az ALGOL 60 nyelv története, szintjei
Az ALGOL - a betűszó, az ALGOrithmic Language (algoritmikus nyelv) elnevezés rövidítése - a FORTRAN után elterjedt második magas szintű programozási nyelv. A rá vonatkozó formális és értelmezési szabályokat 1955-ben kezdte kidolgozni egy európai és amerikai, számítástechnikával foglalkozó tudósokból álló bizottság. A nyelv első, nemzetközileg még el nem fogadott változatát 1958-ban (ALGOL 58, de hívták IAL-nak is), végleges definícióját 1960-ban tették közzé (ALGOL 60). 1963-ban publikálták a nyelvnek egy módosított definícióját, amely az időközben kiderült kisebb hiányosságokat és pontatlanságok javította. A 60-as szám az elnevezésben az elfogadás évére utal; annak ellenére, hogy az 1963-ban elfogadott módosított verziót nevezzük ALGOL 60-nak.
A hivatkozási nyelv konkrét realizációit egyes számológépeken gépi reprezentánsoknak nevezzük. A gépi reprezentánsok kisebb-nagyobb eltéréseket mutatnak a hivatkozási nyelvhez képest. Az eltéréseket az illető gép fordítóprogramjához mellékelt kézikönyvek sorolják fel. Az ALGOL 60 hivatkozási nyelv - a FORTRAN-nál jobban olvasható listái - használhatók számítási eljárások, számológép-programok publikálására is. Ilyen esetben megengedhető az ALGOL-ban írt "szöveg" tipográfiai célszerűség miatti átrendezése. Az ALGOL nyelv szerzői azt követelik meg a publikációs nyelvek alkalmazóitól, hogy a publikációs nyelvek jelöléseiken kívül semmiben ne különbözzenek a hivatkozási nyelvtől, és hogy a publikációs nyelvekről világos áttérési szabály legyen megadható a hivatkozási nyelvre. A hivatkozási, a publikációs és a gépi reprezentációs nyelvek az ALGOL három szintjét alkotják.
Az ALGOL 60 hivatkozási nyelvből hiányoznak azok az utasítások, amelyek a számológépek perifériális egységeire (kiíró, beolvasó, mágnesszalagos stb. egységek) tartalmaznának hivatkozást. Emiatt az egyes implementációk nem igazán voltak kompatibilisek egymással. 1968-ban az IFIP kiadott egy új nyelvet Algol 68 néven. Az új nyelv szinte semmiben sem hasonlított a korábbi ALGOL-okhoz, és erősen kritizálták amiatt, hogy egy teljesen új nyelv az ALGOL 60-ból örökölt absztrakciók nélkül, ráadásul a fordítót nagyon nehéz megvalósítani. Ezáltal az ALGOL 60 vonala lényegében megszakadt.
Az eredetileg nagyszámítógépekre készült (akkor más még nem létezett) ALGOL egyik 8 bites (8080)-as processzorra készült) implementációja az ALGOL-M, amit John P. Flynn és Mark S. Moranville dolgozott ki 1977-re. Mindketten a Monterey-i Haditengerészeti Posztgraduális Iskola számítástechnikai mesterképzésén vettek rész, és a szakdolgozatukhoz fejlesztették ki a fordítót. Szakdolgozati tanácsadójuk Dr. Gary Kildall volt, a CP/M fejlesztője... Noha az ALGOL-M az ALGOL 60 mintájára készült, fejlesztésekor nem volt szándék, hogy a nyelvnek formális részhalmazává tegyék, egy kisméretű, mikrogépekre optimalizált, jól használható fordító elkészítése volt a cél. Ez volt az első magas szintű blokk-strukturált nyelv, amelyet mikrogépeken használható volt. Bár az implementációból sok funkció kimaradt, mégis széles körben elterjedt, köszönhetően egyrészt hiánypótló jellegének, másrészt mert ingyenes programként terjedt.
Az ALGOL-M alapstruktúrája elég hasonló az ALGOL-60-hoz ahhoz, hogy lehetséges legyen a programok egyszerű konvertálása egyik nyelvről a másikra. Ezt különösen hasznosnak tűnt, mert a szabványos publikációs nyelv akkoriban még mindíg az ALGOL 60 volt, és rengeteg alkalmazási program és könyvtári eljárás létezett, amelyek könnyen konvertálhatók ALGOL-M alatti végrehajtásra.

1.2. Alapfogalmak
Ebben a fejezetben - anélkül, hogy pontos matematikai definíciókra törekednénk - röviden ismertetjük azokat a fogalmakat, amelyeket a későbbi tárgyalás folyamán használunk.
Valamely programozási nyelv szintaxisán azoknak a formális szabályoknak összességét értjük, amelyeknek feltétlenül teljesülniük kell ahhoz, hogy egy jelsorozatnak, mint e programozási nyelven (esetünkben az ALGOL-ban) írt programnak értelmet lehessen tulajdonítani. Formális szabály például, hogy egy aritmetikai kifejezésben (formulában) nem következhet egymás után két műveleti jel. Egy jelsorozatról azt mondjuk, hogy valamely szintaktikus egységbe tartozik, ha eleget tesz azoknak a formális szabályoknak, amelyekkel az illető szintaktikus egységet definiáljuk. Így például a+b-c eleget tesz az aritmetikai kifejezések (formulák) szintaktikus egységére érvényes formális szabályoknak, ezért beletartozik ebbe a szintaktikus egységbe.
Egy programozási nyelv szemantikai szabályainak összességén azoknak az értelmezési szabályoknak összességét értjük, amelyek meghatározzák az egyes - szintaktikusan eleve helyesnek feltételezett - jelsorozatok értelmét. A szemantikai szabályok azt fejezik ki, hogy egy adott program hatására mit hajt végre a számítógép. Egy program lehet szintaktikusan helyes, és ugyanakkor szemantikusan hibás, aminthogy mondhat valaki egy nyelvtanilag teljesen hibátlan mondatot, amely teljesen mást fejez ki, mint amit az illető közölni akart.
Minden számológépprogram bizonyos meghatározott jelkészletből (ábécéből) vett jelek véges sorozata. Azokat a jeleket, amelyeket valamely programozási nyelven (pl. ALGOL-ban) írt programok összeállítása során használni szabad, az illető programozási nyelv alapjeleinek nevezzük. Az alapjelek tartalmazhatják pl. a latin ábécé betűit, számjegyeket, matematikai jeleket, írásjeleket stb. Az ALGOL alapjelei:

Az ALGOL-jelentés megemlíti, hogy az angol ábécé alkalmazása nem kötelező a felhasználók részére; az egyes reprezentánsokban az ábécé tetszés szerint szűkíthető vagy bővíthető. Végső soron az alkalmazott ábécét a gép beviteli jelkészlete (a gépbe bevihető szimbólumok összesége) szabja meg, és ez lényegében műszaki kérdés.
A szövegfüzér (karakterlánc) típusú konstansok karaktersorozatokat képviselnek. A szövegfüzér két idézőjel közötti karaktersorozatból áll. A két idézőjel között levő karaktersorozatban tetszőleges látható karakterek (a szóközt is beleértve) fordulhatnak elő; az idézőjel karaktert pedig egy idézőjel-pár képviseli. Az ALGOL alapjeleitől eltérő ASCII karakter csak szövegfüzérben fordulhat elő egy programban.
A szövegfüzéreken értelmezett egyetlen művelet azok összefűzése. ennek operátora: || (két függőleges vonal). pl:

s1 || ", world"

Foglalt szavak (szó-alapjelek):

AND ARRAY BEGIN CASE
CLOSE COMMENT DECIMAL DO
ELSE END FILE FUNCTION
GO GOTO IF INTEGER
NOT OF ONENDFILE OR
PROCEDURE READ STEP STRING
TAB THEN TO UNTIL
WHILE WRITE WRITEON  

Az ALGOL-ban egy sorban több utasítást is írhatunk egymás után. Az utasítások egymástól való elkülönítésére a pontosvessző szolgál. (Hasonló hatása van egy másik alapjelnek is: az else-nek. Ezekkel később foglalkozunk.) Az összetartozó programrészek egyes utasításait ez választja el egymástól.
Gyakran használjuk a továbbiakban a változó fogalmát, amit a számológép operatív memóriájának egy rekeszével azonosíthatunk. Az operatív memória rekeszei egy-egy számadat időleges tárolására szolgálnak. Minden olyan esetben, amikor ebbe a memóriarekeszbe valamely számadat kerül beírásra, a memóriarekesz korábbi tartalma törlődik. Ennek megfelelően, a programozásban használt változók felvehetnek bizonyos értékeket - a rekesz pillanatnyi tartalmát (mint a későbbiekben majd látjuk, ez az érték nem okvetlenül szám érték) - és a program végrehajtása során ez az érték többször megváltozhat. Minden egyes értékváltozáskor a változó új értéke lép a régi helyébe, és a korábbi érték törlődik. Értékváltozás bekövetkezhet a számítógép perifériális egységeivel való adatcsere következtében, vagy pedig oly módon, hogy egy megfelelő programutasítás segítségével arra utasítjuk a gépet, hogy a számítás valamely közbülső eredményét adja át egy meghatározott változónak. Az e célra szolgáló utasításokat értékadó utasításnak nevezzük. Például, az

A: x:=x+y+2

matematikai egyenlőségre emlékeztető formula az ALGOL-ban azt jelenti, hogy az x és y változók pillanatnyi - vagy ahogy az ALGOL-lal kapcsolatban gyakrabban mondani szokták, aktuális - értékével ki kell számítani az x+y+2 kifejezés számszerű értékét, és ezt az értéket át kell adni az x változónak. Ha x pillanatnyi értéke 1.2 és y pillanatnyi értéke 2.5, akkor az adott kifejezés értéke 5.7. A felírt értékadó utasítás hatására a számológép kiszámítja ezt a számértéket, és az eredményt átadja az x változónak, aminek következtében x korábbi értéke törlődik, és a következőkben x aktuális értéke már 5.7. A formulában szereplő : = jel az ALGOL egyik alapjele, és az értékadást jelöli. Az értékadó utasítások a program legfontosabb alkotóelemei, mert segítségükkel tudjuk a közbülső és a végső eredményeket kiszámítani.

A számítógépprogram egyes utasításait a gép általában felírásuk sorrendjében hajtja végre. Ha ettől a természetes sorrendtől el kívánunk térni, külön utasításokat kell felírnunk, amelyek kijelölik a soron következő utasítást. Az ilyen utasításokat vezérlésátadó utasításoknak nevezzük. A vezérlésátadás (vagyis a soron következő utasítás kijelölése) lehet feltétel nélküli, vagy pedig valamely logikai döntés eredményétől függő. Logikai feltétel lehet pl. két mennyiség egymáshoz való viszonyának vizsgálata: ha - mondjuk - az x mennyiség kisebb, mint y, akkor a természetes sorrend marad érvényben, ha pedig nagyobb vagy egyenlő vele, akkor következőként át kell térni egy meghatározott utasításra. A vezérlésátadó utasításokban valami módon meg kell nevezni azt az utasítást, amellyel a program végrehajtását folytatni kívánjuk. Ebből a célból a megfelelő utasítást ún. címkével látjuk el, és a vezérlésátadó utasításban erre a címkére hivatkozunk. Az ALGOL-ban a címkét a hozzá tartozó utasítástól kettőspont választja el. Az előbbi értékadó utasítás, címkével ellátva, az ALGOL 60 szintaktikus szabályainak megfelelően, a következő alakot öltheti:

A: x:=x+y+2

Itt a nagy A betű az utasítás címkéje, és ez a címke lehetővé teszi, hogy a program más helyén egy vezérlésátadó utasítás hivatkozzék erre az utasításra. A

go to A

utasítás hatására például a vezérlés feltétel nélkül átadódik az A címkével ellátott utasításra, azaz következőként a gép ezt az utasítást hajtja végre. Az értékadó és vezérlésátadó utasításokat részletesen a harmadik fejezetben tárgyaljuk.

Gyakran találkozunk a későbbiekben az azonosító fogalmával. Az azonosítók a program különböző objektumainak elnevezésére szolgálnak. Így például az x betűvel a program egy meghatározott változóját jelöljük, és ennek segítségével különböztetjük meg ezt a változót a program összes többi változójától. Hasonló szerepe van az előbbi példában az A betűnek, amely az adott értékadó utasítás megnevezésére szolgál. Azonosítóval látjuk el a programban nemcsak a változókat és a címkéket, hanem a program egyéb objektumait is, pl. vektorokat, mátrixokat, a program egyes önmagában zárt egységeit, az ún. eljárásokat stb.
A fordítóprogramnak ahhoz, hogy az ALGOL-ban írt programot le tudja fordítani a számológép elemi utasításainak sorozatára (belső kódjára), szüksége van bizonyos felvilágosításokra a programban szereplő azonosítók jellegére, felhasználásuk módjára, a programban betöltött szerepére vonatkozólag. Ilyen felvilágosítás pl. az, hogy az azonosító a program milyen objektumát (egyszerű változó, vektor, mátrix, címke stb.) jelöli meg; vektorváltozók esetén a vektor elemeinek száma; a változók által felvehető értékek típusa (pl. csak egész) stb. A program elején, vagy meghatározott egyéb helyein - de mindenesetre az illető azonosító felhasználása előtt - az egyes azonosítókat különböző szempontok szerint csoportosítva felsorolják, és az ily módon keletkező listákból a fordítóprogram útmutatást kap az illető azonosító kezelésére vonatkozólag. Az ilyen listákat az azonosítók deklarációinak nevezzük. A deklarációk megszerkesztésével a negyedik fejezetben foglalkozunk.
Befejezésül előzetes példaként bemutatunk egy egészen rövid ALGOL-programot kamatos kamat számítására, bemutatandó az ALGOL-M néhány lehetőségét, hiányosságát.

BEGIN % Kamatos kamat %
DECIMAL OSSZEG,KAMATLAB;
INTEGER I,EV;
  WRITE("Kamatos kamat szamitas eves bontasban");
  WRITE("Osszeg:");READ(OSSZEG);
  WRITE("Kamatlab (%):");READ(KAMATLAB);
  WRITE("Ev:");READ(EV);
  WRITE("");
  FOR I:=1 STEP 1 UNTIL EV DO
    WRITE(I," ev vegen az osszeg:",(OSSZEG:=OSSZEG*(1.+KAMATLAB/100.)));
END

A programot a BEGIN és az END utasításpár határolja. A programot lezáró END után egy üres sor (ENTER) is szükséges a fordítónak. A BEGIN-t követi a deklarációs rész, azaz a programban szereplő azonosítók (címkék, változók) listaszerű felsorolása. A DECIMAL szó arra utal, hogy a felsorolt változók tetszőleges valós számot felvehetnek értékként. Ezután kiírjuk a program címét, majd bekérjük a számításhoz szükséges értékeket. Fontos tudni, hogy a DECIMAL típusú értékekben a tizedespont megadása szükséges egész értékek esetén is! Még megjegyezzük, hogy a WRITE és READ utasítások nem részei az ALGOL 60 hivatkozási nyelvnek, de a gépi reprezentációs nyelvek ilyen és ehhez hasonló utasításokkal ki szokták egészíteni a hivatkozási nyelvet. A ki- és bevitel, valamint a perifériális egységekkel való adatcsere kérdéseire a 6. fejezetben térünk ki.

2. Aritmetikai és logikai kifejezések

2.1. Bevezetés
Az ALGOL-utasítások leggyakrabban használt elemei, építőkövei az aritmetikai és logikai kifejezések. Ezek önmagukban még nem utasítások, de mivel bármely ALGOL-utasítás tartalmazhat kifejezéseket, megszerkesztési és értelmezési szabályaikkal az utasítások tárgyalása előtt külön foglalkozunk.
Az aritmetikai kifejezés számokból és változókból áll, és a számokon, valamint a változók aktuális értékein végzett aritmetikai műveletek eredményeként, egyetlen számértéket állít elő. Ezt a számértéket az aritmetikai kifejezés aktuális értékének nevezzük. A kifejezés aktuális értéke a benne szereplő változók értékeinek függvénye. Ezért mindig feltesszük, hogy a kifejezés egy program kiragadott darabja, és hogy ez a program értéket adott a kifejezést felépítő változóknak, mielőtt annak kiszámítására sor kerülne. Ha egy aritmetikai vagy logikai kifejezésben van olyan változó, amelynek a program a kifejezést megelőzőleg nem adott értéket, akkor ez a kifejezés nem számítható ki az adott pillanatban, és aktuális értéke nincs definiálva.
Az említett feltételezés magában foglalja azt is, hogy kiszámítás után a kapott aktuális értékkel még történik valami. Az ALGOL-ban egy kifejezés értéke ugyanis valami módon mindig felhasználásra kerül (pl. ha a kifejezés értékadó utasítás jobb oldalán áll, akkor ezzel az értékkel egyenlővé tétetik a bal oldali változó). A kifejezések tárgyalása során sem azt nem vizsgáljuk, hogy mi módon kapták a benne szereplő változók az értéküket, sem azt, hogy a kiszámítás után mi lesz az aktuális érték sorsa.
A logikai kifejezés fogalma kevésbé közismert, mint az aritmetikai kifejezésé. A logikai kifejezések valamely igennel vagy nemmel megválaszolható kérdésre adnak választ. Logikai feltételeknek főként a programok feltételes elágaztatásainál van szerepük. Később látni fogjuk, hogy az aritmetikai és a logikai kifejezések között minden szempontból szoros analógia van, és mindaz, amit aritmetikai kifejezésekről elmondunk, a logikaiakra is érvényes, természetesen helyenként értelemszerű változtatásokkal. Logikai kifejezés aktuális értéke az a válasz ("igaz" vagy "hamis"), amit a kifejezés a feltett kérdésre ad. A logikai kifejezések tárgyalásakor ugyanazon feltevésekkel élünk, mint az aritmetikaiaknál.

2.2. Számok
Aritmetikai kifejezések, képletek felírásakor igen gyakran van szükség számkonstansok alkalmazására. Formulákban a betűváltozók mellett csaknem mindig előfordulnak konkrét számok is. Ezért az ALGOL nyelvnek lehetőséget kell biztosítania arra, hogy a programokban számkonstansok szerepelhessenek. A számkonstans nem változtatja értékét, és nem írható értékadó utasítás bal oldalára.
Az ALGOL szempontjából kétféle típusú számértéket különböztetünk meg: "egész" és "valós" számértékeket. Az egész típusú mennyiségek - mint a nevük is mutatja - csak egész számokat vehetnek fel értékként. Megköveteljük tőlük, hogy a köztük végzett aritmetikai műveletek pontosak legyenek, tehát a gép belsejében ábrázolt eredménynek nem szabad különböznie az eredmény matematikai értékétől. A valós típusú mennyiségek - amelyek értékként tetszőleges, a gépben ábrázolható számot felvehetnek - mindig kerekített értéknek tekintendők, és valós típusú mennyiségek között végzett aritmetikai művelet eredménye a művelet eredményének matematikai értékétől eltérést mutathat. A valós és egész típusú mennyiségek gépi ábrázolása eltérő, és a valós típusú mennyiségek ábrázolási határai rendszerint jóval tágabbak, mint az egész típusú mennyiségeké. A hivatkozási nyelvben nincs megkötés a számábrázolás határaira, és ott a valós mennyiségeket is végtelen pontosnak tekintjük. A valós és egész típusú mennyiségek megkülönböztetése a gépi reprezentáció szempontjai miatt szükséges. Algol-M-ben az egész számok értéke -16 383 és +16 383 között lehet, a valós számok legfeljebb 18 számjegy pontosságúak.
A szárnkonstansok is kétfélék: egészek és valósak. Az egész számkonstansok 1-5 számjegyből (-16 383 ... +16 383 értéktarmányban) és előjelből állnak. Pozitív egészek előjele tetszés szerint kiírható vagy elhagyható. Az egész számok elé tetszés szerinti számban írhatunk "értéktelen" zérusokat.
Példa egész típusú konstansokra:

1
+1
-133
08
0008
92
+1965
16383

A valós típusú számoakat az ALGOL-M binárisan kódolt decimális módon (BCD) ábrázolja. Ezzel a módszerrel a számok konverziója és megjelenítése lényegesen egyszerűbbé válik. A valós számok legfeljebb 18 számjegyűek lehetnek, és három részből állhatnak: egészrész, tizedespont, törtrész. A tizedespontot mindenképen ki kell rakni (ez jelzi a fordítónak a konstans típusát), az egészrész vagy a törtrész elhagyható. Példák valós konstansokra:

.1
0.1
1.
0290.
290.
16384.
-1234567890.12345678

Az exponenciális alak nincs implementálva.

2.3. Változók és azonosítók
Az ALGOL nyelvben alapjelként használhatók az angol ábécé kis- és nagybetűi. A betűket az ALGOL nyelvben főként azonosítók képzésére használjuk. Azonosítóval vannak ellátva a változók, eljárások és függvények. Azonosító lehet bármely betűkből és számokból álló, betűvel kezdődő jelsorozat, de nem lehet foglalt szó (ld. 1.2. pont). A jelsorozat hossza nincs korlátozva, 48 karaktert még elfogad a fordító, a kis- és nagybetűket pedig azonosnak tekinti. A gyakorlatban 20 karakternél hosszabb azonosítóneveket az olvashatóság miatt nem érdemes használni. Példák azonosítókra: A3, COUNTER, X5Y

Az ALGOL-M nyelvben egész (INTEGER), valós (DECIMAL) és szövegfüzér (STRING) típusú változókat különböztetünk meg. Az egész típusú változók csak egész számokat vehetnek fel értékként, a valós típusúak bármely valós számot. A DECIMAL típusnál deklarációkor megadható a tárolt számjegyek száma. Egy DECIMAL típusú változó - ha másként nem rendelkezünk - tíz számjegyet tud tárolni, maximum 18 számjegy írható elő. A változó helyfoglalása a tárolni kívánt számjegyek függvénye. A karakterláncok maximum 255 karakter hosszúak lehetnek. Az ALGOL nyelv logikai típusú változója nincs implementálva, és INTEGER típusú változó sem lehet fel logikai típusú értéket: logikai kifejezés nem szerepelhet értékadó utasításban, csak feltételes utasításban. Az ALGOL-ban nemcsak magukban álló skaláris változókat használunk, hanem dolgozhatunk összetartozó változócsoportokkal, ún. tömbökkel: vektoroknak, mátrixoknak, stb. elemeivel is. Ezeknek az egy csoportba tartozó változóknak közös azonosítójuk és egy vagy több megkülönböztető indexük van. A tömbök legfeljebb 255 dimenziót tartalmazhatnak, mindegyik dimenzió indexe 0 és 16383 között lehet. Ez persze csak elméleti korlát, a megcímezhető memória természetesen nem tesz lehetővé ekkora 3 dimenziós tömb deklarálását.
Azt, hogy egy meghatározott azonosítóval megjelölt változó egész, valós vagy logikai típusú-e, a program deklarációs részéből tudjuk meg. ALGOL-programban csakis deklarált változók fordulhatnak elő. A deklarációk megadásának szabályaival, és a deklarációkra vonatkozó egyéb kérdésekkel a 4. fejezetben foglalkozunk. A könyvnek ebben és a következő fejezetében minden előforduló változóról feltesszük, hogy deklarálva van.

2.4. Aritmetikai műveletek
Az aritmetikai kifejezések tárgyalásának további előkészítéseként ebben a pontban az ALGOL 60 nyelvben definiált, aritmetikai műveleteket ismertetjük.
Mielőtt a különféle aritmetikai műveletek részletes tárgyalására térnénk, előrebocsátjuk, hogy egy aritmetikai művelet eredménye az ALGOL-ban akkor van egyértelműen definiálva, ha számértékével együtt a típusát (valós vagy egész) is megadjuk. A továbbiakban több szabályt fogunk megismerni arra nézve, hogy milyen esetekben milyen típusú eredmény keletkezik.
Az ALGOL-M nyelvben ötféle aritmetikai művelet van definiálva. Ezek a következők:

  1. Összeadás. Jele: +
  2. Kivonás. Jele: -
  3. Szorzás. Jele: *
  4. Osztás. Jele: /
  5. Hatványozás. Jele: **

A felsorolt valamennyi műveleti jel ALGOL-alapjel.
Az összeadás, a kivonás és a szorzás a megszokott módon vannak definiálva. Eredményük akkor és csak akkor egész típusú, ha mindkét műveleti komponens egész típusú; minden más esetben valós. A / jellel jelölt osztási művelet valós eredményt állít elő, ha bármelyik tag valós típusú. Az osztást két tizedesjegyig végzi el az interpreter. Ha mindkét komponens egész típusú, egész osztás történik. Ezt a fontos szabályt a gyakorlatlan programozók sokszor elfelejtik, és ez néha rendkívül nehezen felderíthető programhibákra vezet. A 0-val való osztás nincs értelmezve, ilyen esetben a program futtatása közben a gép hibaüzenettel megáll. Pl.:

22/7 = 3
22/7. = 3.14

A hatványozás csak INTEGER típusra értelmezett! Egész kitevős hatványozást ismételt szorzásokkal (negatív kitevő esetén ismételt szorzásokkal és reciprok-képzéssel) kell végezni.

2.5. Feltétlen aritmetikai kifejezések
Ebben a pontban az aritmetikai kifejezésekkel kapcsolatos szintaktikai és szemantikai szabályokat tárgyaljuk. Először az aritmetikai kifejezések egyes szűkebb osztályait ismertetjük, majd a tárgyalás folyamán fokozatosan bővítjük a vizsgált fogalomkört.
Először olyan aritmetikai kifejezéseket tekintünk, amelyek nem tartalmaznak sem zárójelet, sem függvényoperációt, sem indexes változót.
A fenti kikötésnek eleget tevő aritmetikai kifejezések szintaktikus szempontból operandusok és aritmetikai műveleti jelek váltakozó sorozatai. Operanduson számkonstanst vagy változó-azonosítót értünk. Az aritmetikai kifejezés vagy egy operandussal kezdődik, vagy a + és - előjelek valamelyikével. Példa:

-x/y+zr-zt+1
alfa+beta/gamma**3

A fenti típusú jelsorozatok értelmezési szabályok értelmezéséhez az elemi algebrából jól ismert szabályokat kell - a szokásosnál kissé precízebben megfogalmazva - átültetnünk az ALGOL terminológiájára. Az ötféle műveleti jelet (lásd a 2.4. pontot) három csoportba soroljuk. Az egyes csoportokon belül a műveleti jelek egyenrangúak. Különböző csoportba tartozó műveleti jelek között elsőbbségi (idegen szóval: precedencia-) szabályok vannak értelmezve. Az egyes műveletcsoportok a következők:

  1. Elsődleges műveleti jel a hatványozás jele: **
  2. Másodlagosak az ún. multiplikatív műveleti jelek: *, /
  3. Harmadlagosak az ún. additív műveleti jelek: +, -

A precedenciaszabály értelmében egy aritmetikai kifejezésben minden operandus a vele szomszédos operandusok közül ahhoz tartozik, amelyhez a magasabb precenenciájú műveleti jel kapcsolja. Ez a szabály megfelel az ismert elemi szabálynak; pl. az

a+b*c

kifejezésben a b operandus a vele szomszédos a és c operandusok közül c-hez tartozik, mert a szorzásjel mint multiplikatív műveleti jel, magasabb precedenciájú az additív + jelnél. Az aritmetikai kifejezések elején és végén álló operandusokat úgy kell tekinteni, mintha "külső" oldalukon elsőbbségi szempontból még az additívnál is gyengébb műveleti jel állna.
Az egyenlő precedenciájú műveleti jelek esetéről egy második szemantikai szabály rendelkezik, az ún. "balról jobbra" szabály. Ennek értelmében egy operandus, melynek két oldalán egyenértékű műveleti jelek állnak, a tőle balra levő operandushoz tartozik.
A precedenciaszabály és a balról jobbra szabály együttesen bármely (ideiglenes megszorításainknak eleget tevő) aritmetikai kifejezés kiszámítására tartalmaz utasítást. A teljes kiszámítási szabály röviden úgy szól, hogy balról jobb felé tartó sorrendben végig kell vizsgálni az aritmetikai kifejezés műveleti jeleit, és vagy a balról jobbra szabály, vagy a precedenciaszabály szerint kell a műveleteket végezni, aszerint, hogy a szomszédos műveleti jelek azonos vagy különböző precedenciájúak-e.

Példa. Tekintsük a következő aritmetikai kifejezést:

a + b + c*d**2

Legyen az összes változó valós típusú, és legyenek az aktuális értékek rendre: a=2, b=3, c=4 és d=2. Kiszámítása a következőképpen megy végbe: vizsgáljuk rendre a kifejezés műveleti jeleit: a, mint bal szélső változó, automatikusan b-hez tartozik, b két oldalán azonos precedenciájú + jelek állnak. Itt a balról jobbra szabály érvényesül: összeadjuk a-t és b-t. Az eredmény 5. A c változó bal oldalán + , jobb oldalán * jel áll; az utóbbi magasabb rendű, és így c-t a jobb oldali szomszédjához kell kapcsolni. Azonban a jobb oldali szomszéd, d, jobb oldalán még magasabb rendű műveleti jel áll, a hatványozás jele, így d is jobb oldali szomszédjához tartozik a precedenciaszabály értelmében. Ez a jobb oldali szomszéd a 2-es, ennek jobb oldalán nincs műveleti jel. Ily módon a d**2 művelet elvégezhető, az eredmény 4. Ezt a számot összeszorozhatjuk c-vel, az eredmény 16, és ezt hozzáadva a+b=5-höz, végeredményként 21-et kapunk. Az összes közbülső művelet eredménye, és a végeredmény is valós típusú.
Az elsőbbségi és a balról jobbra szabályokról mondottakat másképpen is megfogalmazhatjuk.
Mint mondottuk, az aritmetikai kifejezés operandusok és aritmetikai műveleti jelek váltakozó sorozata. Egy adott aritmetikai kifejezést feloszthatunk több részkifejezésre oly módon, hogy különválasztjuk az eredeti kifejezésnek azon részeit, amelyek nem tartalmaznak additív (harmadlagos) műveleti jelet. Egy ilyen, additív műveleti jelet nem tartalmazó részkifejezést tagnak nevezünk. Az aritmetikai kifejezés tagokból és az ezeket összekapcsoló additív műveleti jelekből áll. Természetesen előfordulhat, hogy egy aritmetikai kifejezés egyáltalán nem tartalmaz additív műveleti jelet, ebben az esetben egyetlen tagból áll. Például a példában szereplő kifejezés három tagból áll, ezek rendre a, b, c*d**2.
Az egyes tagokon belül ismét elhatárolhatunk olyan részeket, amelyek nem tartalmaznak multiplikatív (másodlagos) műveleti jelet, ezeket tényezőnek nevezzük. Minden tag tényezőkből és az őket összekapcsoló multiplikatív műveleti jelekből áll. Ha egy tag egyáltalában nem tartalmaz multiplikatív műveleti jelet, akkor egyetlen tényezőből áll. Így a kifejezés tagjai közül csak a harmadik áll egynél több tényezőből: ezek c és d**2.
Az egyes tényezők még mindig tartalmazhatnak elsődleges műveleti jelet. Két szomszédos elsődleges műveleti jel között azonban már nem állhat semmiféle műveleti jel, csak operandus. Az operandusokat másképpen elsődleges kifejezésnek nevezzük.
Az aritmetikai kifejezések kiszámítása úgy történik, hogy balról jobbra tartó sorrendben kiszámítjuk az egyes tagokat, és az újonnan kiszámított tagot hozzáadjuk az előző (tőle balra levő) tagok részösszegéhez. Az egyes tagokon belül is balról jobbra tartó sorrendben halad a számítás: egyenként kiszámítjuk az egyes tényezőket, és ezeket rendre "hozzászorozzuk" az előző (balra levő) tényezők részletszorzatához. Minden egyes tényező kiszámításán belül, balról jobbra haladó sorrendben végzett hatványozásokon keresztül jutunk el a tényező aktuális értékéhez.

Az aritmetikai kifejezések eddig vizsgált osztályát most ki kellene bővítenünk az ún. standard függvényekkel, de ilyenek nincsenek. Standard függvényen az ALGOL-ban azokat a leggyakrabban előforduló függvényeket értjük, amelyeket az ALGOL egyezményes azonosítóval lát el, és amelyeknek minden ALGOL-fordítóprogramban rendelkezőre kellene állniuk, anélkül, hogy külön definiálni kellene őket: sin(x), cos(x), ln(x), exp(x), sqrt(x), arctan(x), abs(x), entier(x), sign(x). Az Algol-M-ben ezeket szükség esetén a programozónak kell definiálni. A függvények argumentumát az ALGOL-ban minden esetben zárójelbe kell tenni, még akkor is, ha egyetlen operandusból áll. Az argumentum lehet tetszőleges aritmetikai kifejezés. A függvények argumentumukkal együtt az aritmetikai kifejezésekben teljesen úgy viselkednek, mint 1 az operandusok, tehát a változók vagy a számkonstansok. Ezt úgy is kifejezhetjük, hogy egy függvény az argumentumával együtt elsődleges kifejezést alkot.

A zárójeles kifejezések
Az elemi matematikából ismeretes, hogy a zárójel a műveletek "természetes" precedenciájának megváltoztatására használatos. Az a+b*c kifejezésről például mondottuk, hogy az a (b*c) szorzatnak a-val való összeadását írja elő. Ha ettől eltérő műveleti sorrendet kívánunk előírni, akkor zárójelet kell alkalmaznunk:

(a+b)*c

A zárójel "ellene mond" a szorzás jel magasabb precedenciájának, és a természetes elsőbbségi szabálytól eltérő műveleti sorrendet ír elő. Az elemi matematikában meg van engedve fölösleges, redundáns zárójelek alkalmazása: Írhatjuk azt is, hogy a+(b*c).
Az elemi matematikának ezeket a zárójelezési szabályait szinte minden változtatás nélkül visszük át az ALGOL-ba. A zárójelezés célja itt is a természetes precedencia-sorrendtől eltérő műveleti sorrend előírása, és megengedett fölösleges, redundáns zárójelek alkalmazása is, ALGOL-ban azonban aritmetikai kifejezések zárójelezésére csakis kerek zárójelek alkalmazhatók. A kerek zárójeleket: "(" és ")", a függvényekkel kapcsolatban vezettük be új alapjelként. A szögletes zárójelet később majd szintén bevezetjük mint ALGOL-alapjelet, azonban nem aritmetikai zárójelként fogjuk használni. A "kapcsos" zárójel nem szerepel az ALGOL-ban.
Az aritmetikai kifejezések zárójélezéséről az alábbi egyszerű szabály rendelkezik: bármely aritmetikai kifejezés, ha kerek zárójelbe zárják, elsődleges kifejezéssé változik, és közönséges operandussal (számkonstanssal vagy változóval) válik egyenértékűvé. Ha tehát bármilyen bonyolult aritmetikai műveletsorozat eredményével további aritmetikai műveleteket kívánunk végezni, nem kell mást tennünk, mint a megfelelő kifejezést zárójelbe zárnunk, és mint egyetlen operandust kezelnünk. Az aritmetikai zárójelek tetszőleges mélységben egymásba skatulyázhatok. Minthogy a zárójelbe zárt kifejezés egyetlen operandust képvisel, ahhoz, hogy egy ilyen kifejezéssel további aritmetikai műveletet végezhessünk, előbb ennek aktuális értékét kell ismernünk. A zárójeles kifejezések bevezetésével tehát az előzőkben megismert - az elsőbbségi és a balról jobbra szabályon alapuló - kiszámítási algoritmus csak annyiban bővül, hogy ha egy aritmetikai művelet valamelyik operandusa zárójeles kifejezés, akkor előbb ki kell számítani a zárójelen belüli kifejezés aktuális értékét, és azután kell elvégezni a kijelölt műveletet. Mivel a zárójelek akárhányszoros mélységben egymásba skatulyázhatok, ezt a szabályt általában rekurzíve kell értelmeznünk.
Hosszabb képleteknek ALGOL-kifejezéssé való átírásánál nagyon kell ügyelni arra, hogy minden megkezdett zárójel be legyen zárva. A programozás során leggyakrabban felmerülő szintaktikus hiba a zárójelek téves elhelyezése. Szerencsére ezt a hibát a fordítóprogram még a fordítás stádiumában jelzi.
E helyen fel kívánjuk hívni a figyelmet a következőre: az ALGOL-fordítóprogram tevékenysége az aritmetikai kifejezések fordításával kapcsolatban arra korlátozódik, hogy az ALGOL-programot lefordítja az adott konkrét gép nyelvére, azaz olyan gépi utasításokat generál, amelyek végrehajtása esetén kiszámítódik az aritmetikai kifejezés aktuális értéke. Tehát a fordítóprogram nem számítja ki ezt az értéket, és ezért csakis arra képes, hogy megállapítsa egy kifejezésről, formálisan helyes-e, de annak szemantikai hibáit csak a célprogram működése közben lehet észrevenni. A kifejezések kiszámítása közben nem választottuk szét élesen, hogy abból, amit csinálunk, mi tartozik a fordítóprogram hatáskörébe, és mi a célprograméba. A kifejezés elemzése, szétbontása tagokra, tényezőkre, elsődleges kifejezésekre, az esetleges számkonstansoknak elhelyezése a memóriában, és általában mindaz, ami nem igényli a változók aktuális értékének ismeretét, a fordítóprogram dolga. Így többek között a balról jobbra szabály és az elsőbbségi szabály is a fordítóprogram megszerkesztésére vonatkozó utasítás. Ezzel szemben az aritmetikai műveletek numerikus elvégzése a célprogram működése közben történik.
Befejezésül felhívjuk a figyelmet néhány két gyakori szintaktikus hibára, amelyeket a programozók aritmetikai kifejezések felírásakor szoktak elkövetni.

  1. Zárójelekkel kapcsolatban: nem egyenlő számú kezdő- és végzárójel. Szögletes vagy kapcsos zárójel alkalmazása. Függvény argumentumánál a kötelező zárójel elmulasztása.
  2. Két aritmetikai műveleti jel kerül egymás mellé. Ez különösen a hatványozás műveletének helytelen felírásánál fordul elő: a hatványozás jele után a kitevő előjeleként még egy műveleti jelet írunk, pl. a**-3. Ilyen esetben feltétlenül zárójelet kell alkalmazni: a**(-3).

2.6. Logikai műveletek
A logikai kifejezés aktuális értékként nem számokat, hanem ún. logikai értékeket vesz fel: ez lehet FALSE (hamis) vagy TRUE (igaz). A logikai értékek tehát nem számok; számváltozó nem vehet fel értékként logikai értéket. Az aritmetikai kifejezésekhez hasonlóan, a logikai kifejezések tárgyalása előtt a logikai értékek között értelmezett műveleteket kell ismertetnünk.
Az ALGOL nyelvben háromféle logikai művelet van értelmezve. Ezek a következők:

AND Logikai szorzás (konjunkció, olvasva: "és"),
OR Logikai összeadás (diszjunkció, olvasva: "akár")
NOT Negáció (tagadás) (olvasva: "nem")

A logikai értékek közötti műveleteket ún. igazság-érték-táblázatok segítségével értelmezzük; ezek a művelet paramétereinek minden lehetséges kombinációjára megadják a művelet eredményét.

A logikai szorzás (AND) eredménye minden olyan esetben false, amikor a paraméterek közül legalább az egyik false.

TRUE FALSE
TRUE TRUE FALSE
FALSE FALSE FALSE

A logikai összeadás (OR) eredménye minden olyan esetben true, amikor a paraméterek közül legalább az egyik értéke true.

TRUE FALSE
TRUE TRUE TRUE
FALSE TRUE FALSE

A negáció - az előző két logikai művelettel ellentétben - egyparaméteres művelet, és a logikai érték tagadását, ellenkezőre fordítását jelenti.

TRUE FALSE
NOT FALSE TRUE

2.7. Relációk
Ebben a pontban a logikai kifejezések egy további fontos alkotórészét, a reláció fogalmát ismerjük meg. Szintaktikus szempontból a reláció két feltétlen aritmetikai kifejezés (lásd 2.5. pont), relációjellel összekapcsolva. A relációjelek a következők:

Valamennyi relációjel ALGOL-alapjel.
Egész-egész, valós-egész, valós-valós, egész-valós és karakterlánc-karakterlánc összehasonlítás megengedett. Egész-valós és valós-egész számok összehasonlítása esetén az egész értéket az összehasonlítás előtt valós értékké konvertálja a rendszer. A karakterlánc-értékek összehasonlításának eredménye karakterenkénti összehasonlítástól függ, ahol az első nem egyenlő karakter első előfordulása határozza meg a logikai eredményt. Az egyes karakterek értéke ASCII-kódjuknak megfelelő sorrendben növekszik.
Magában álló változó vagy számkonstans aritmetikai kifejezésnek számít, így az x >= 3 szintaktikus szempontból korrekt reláció. Sőt, éppen ez az egyszerű típusú reláció kerül az ALGOL-ban leggyakrabban felhasználásra.
Szemantikai szempontból a relációnak mindig egy logikai értéket tulajdonítunk, melyet a változók aktuális értéke határoz meg. A reláció aktuális értéke true, ha a jobb és bal oldali aritmetikai kifejezés aktuális értéke között a relációjel által kijelölt egyenlőtlenség (= jel esetén egyenlőség) valóban fennáll, és false, ha a relációjel által kijelölt egyenlőtlenség (egyenlőség) nem áll fenn.
Nincs kikötve, hogy a reláció jobb és bal oldalán álló kifejezések aktuális értéke azonos típusú legyen. A jobb és bal oldali kifejezéseknek azonban kiszámíthatóknak kell lenniük, azaz bennük csakis deklarált, és értékkel rendelkező változók szerepelhetnek.

2.8. Feltétlen logikai kifejezések
Amint arra korábban már utaltunk, az aritmetikai és a logikai kifejezések között messzemenő analógia áll fenn, és minden, amit az aritmetikai kifejezésekről elmondottunk, értelemszerű változtatásokkal átvihető a logikaiakra. A továbbiakban ez az analógia lesz a tárgyalás vezérfonala.
A tárgyalást itt is a zárójelet nem tartalmazó kifejezésekkel kezdjük. Szintaktikus szempontból egy zárójelet nem tartalmazó logikai kifejezés műveleti jelek és operandusok váltakozó sorozata. Műveleti jelen itt a kétparaméteres logikai műveletek műveleti jeleit értjük: AND, OR. Példa feltétlen logikai kifejezésekre:

X >= 2.5 and x < 3.3

A kifejezés két operandusból áll, mindkettő reláció.
A logikai kifejezések szemantikáját ugyanazok a törvények szabályozzák, mint az aritmetikaiakét, nevezetesen a precedenciaszabály és a balról jobbra szabály. A logikai műveleti jelek precedenciasorrendje a következő:

Mint láttuk, a negáció egy paraméteres művelet, amely az utána álló operandus értékét ellenkezőjére fordítja (tagadja). A negáció jele valamennyi logikai művelet jelénél magasabb precedenciát élvez.
Az aritmetikai kifejezések kiszámítása úgy megy végbe, hogy amint azt az 2.5. pontban láttuk, felbontjuk a kifejezést tagokra, tényezőkre és elsődleges kifejezésekre, és ezek kiszámításánál a balról jobbra szabály szerint járunk el. A logikai kifejezések esetében a kiszámítási szabály hasonló.
Az aritmetikai kifejezésekkel fennálló analógia alapján könnyén áttérhetünk a zárójeles kifejezésekre is. A zárójel most is elsősorban a precedenciaszabály megtörésére való: olyankor alkalmazzuk, amikor valamely operandust a gyengébben kötő műveleti jelhez akarunk csatolni. Mielőtt egy zárójeles kifejezés aktuális értékével további műveletet végeznénk, előzőleg a zárójelen belüli összes műveletet el kell végeznünk. A zárójeles kifejezések bevezetésével az eddig megismert számítási szabályok csak az elemi algebrából ismert zárójelfelbontási szabállyal bővülnek. A zárójelek tetszőleges mélységben egymásba skatulyázhatok, és egymásba skatulyázott zárójelek esetén a zárójelfelbontási szabályt rekurzíve kell alkalmazni. Redundáns zárójelek tetszés szerint alkalmazhatók.
Pl.:

(X=Y) AND (Y=Z OR Z=10)

Egy logikai kifejezés aktuális értékének meghatározásához bizonyos esetekben szükségtelennek látszik végigszámolni a teljes kifejezést. Ha pl. egy logikai szorzási művelet első komponense false értékű, akkor a második komponens aktuális értékétől függetlenül a kifejezés aktuális értéke false lesz. Hasonló esetek előfordulnak a logikai összeadás műveleteivel kapcsolatban is. Az efféle lehetőségeknek géppel való vizsgáltatása azonban körülményes, nem éri meg a fordító- és a célprogram bonyolítását. Ezenfelül az ALGOL hivatkozási nyelv kategorikusan meg is tiltja a kifejezések kiszámításának ilyenfajta lerövidítését. A tilalom okát a későbbiekben (5. fejezet, 4. pont) fogjuk megismerni.

3. Utasítások

3.1. Bevezetés
Ebben a fejezetben az ALGOL nyelv különböző utasítástípusait fogjuk megismerni. Az egyes utasítástípusokat egy-egy külön pontban tárgyaljuk. Az ALGOL nyelvben a következő utasítástípusok vannak definiálva:

  1. Értékadó utasítás (3.2. pont);
  2. Vezérlésátadó utasítás (3.3. pont);
  3. Feltételes utasítás (3.4. pont);
  4. Üres utasítás (3.4. pont);
  5. Összetett utasítás (3.5. pont);
  6. Ciklusutasítás (3.7. pont);
  7. Kiválasztó utasítás (3.8. pont)
  8. Blokk;
  9. Eljárásutasítás.

A blokkokat a 4. fejezetben, az eljárásutasításokat az 5. fejezetben több pontban tárgyaljuk.

3.2. Értékadó utasítások
Az 1. fejezet 2. pontjában megismertük az értékadó utasítás fogalmát, amely általában egy bal oldali változóból, és egy aritmetikai kifejezésből áll. Az értékadó utasítás végrehajtása közben kiszámításra kerül a jobb oldali kifejezés aktuális értéke, és ezt az értéket felveszi a bal oldali változó, esetleges korábbi értékének egyidejű törlése mellett.
Az ALGOL nyelvben - mint azt az előzőkben láttuk - aritmetikai és szövegfüzér (STRING) típusú változók vannak definiálva. Ennek megfelelően megkülönböztetünk aritmetikai szövegfüzér értékadó utasításokat. Az aritmetikai értékadó utasítások jobb oldali kifejezése aritmetikai kifejezés, és bal oldali változója INTEGER vagy DECIMAL típusú változó. A szövegfüzér értékadó utasításokban a jobb oldalon szövegfüzér, a bal oldali változó STRING típusú.
Az értékadás jelölésére az ALGOL-ban külön alapjelet vezettek be, a := (olvasva: kettőspont-egyenlő) jelet.
Legegyszerűbb esetben az értékadó utasítás egy bal oldali változóból, az értékadás jeléből és egy jobb oldali (aritmetikái vagy logikai) kifejezésből áll:

V := K

Ha K aritmetikai kifejezés, akkor a bal oldali V változónak aritmetikai típusúnak (integer vagy decimal) kell lennie, ha pedig K szövegfüzér vagy szövegfüzéren értelmezett művelet (összefűzés), akkor V string típusú változó.
Példa értékadó utasításokra:

x := a*x**2 + 2*b*x*y + c*y**2

A példában a jobb oldali kifejezés kiszámítása után törlődik az x változó meglevő értéke, és helyébe íródik a jobb oldali kifejezés aktuális értéke.
Mint tudjuk, aritmetikai változó kétféle van: egész és valós. Definiáljuk most a V := K értékadó utasítás szemantikáját arra az esetre, amikor K aritmetikai kifejezés, és a bal oldali változó típusa különbözik a jobb oldali kifejezés aktuális értékének típusától!

Valamennyi, a programban deklarált változónak értéket kell adni, mielőtt kifejezésekben használnánk. Ennek elmulasztását nem jelzi a fordító, de az első értékadásig a deklarált változók értéke határozatlan marad!
Az ALGOL nyelvben egy értékadó utasításnak nemcsak egy, hanem akárhány bal oldali változója lehet. Például:

x:= y:= z:= p+q*x

Az ilyen utasításban az egyes bal oldali változók azonosítóit az értékadás jelével választjuk el egymástól. Az utolsó értékadási jel után következik a jobb oldali kifejezés. Az ilyen típusú utasítások szemantikája a következő: a Jobb oldali kifejezés kiszámításával kapott aktuális értéket át kell adni valamennyi bal oldali változónak. Fontos tudnunk, hogy a jobb oldali kifejezés az értékadó utasítás végrehajtása során csak egyszer számítódik ki. Ha több változónak adunk egy értékadó utasítással értéket, be kell tartanunk még egy szintaktikus szabályt. Nevezetesen, a bal oldali változóknak mind azonos típusúaknak kell lenniük: vagy mindegyik egész, vagy mindegyik valós típusú. Más szóval, a bal oldali változók listáján nem szabad összekeverni az egész és a valós típusú változókat.

Egy további megjegyzés. Tekintsük a következő ALGOL-utasításcsoportot:

x:=p+q+r; y:=p+q+r; z:=p+q+r;

Legyenek a p, q, r változók aktuális értékei egyaránt 3.0-val egyenlők. A 3 utasítás az x, y, z változóknak egyformán a 9.0 értéket adja, és helyettesíthető egyetlen értékadó utasítással:

x:=y:=z:=p+q+r;

Több azonos jobb oldali kifejezéssel bíró értékadó utasítást azonban nem minden esetben szabad eggyé összevonni. Tekintsük pl. a következő utasításcsoportot:

x:=x+y+z; y:=x+y+z; z:=x+y+z;

Legyenek x, y, z kezdeti aktuális értékei ismét 3.0-val egyenlők! Az első utasítás 9.0-t ad értékként x-nek. A második utasítás már x megváltozott aktuális értékével kerül végrehajtásra, és y-nak 15.0 értéket ad. A harmadik utasítás végrehajtása után z értéke 27.0 lesz. Ezzel szemben az

x:=y:=z:=x+y+z;

utasítás mindhárom változónak egyaránt 9.0 értéket ad, mivel a jobb oldali kifejezés csak egyszer kerül kiszámításra.
Az ALGOL-M lehetővé teszi az értékadó utasítás egy speciális formáját, az úgynevezett menet közbeni értékadást. Az értékadás ezen formája bármely kifejezésben megengedett. Általános lakja:

( változó := { változó := } ... kifejezés )

Az egyetlen különbség az értékadás alapesetétől az a mellékhatás, hogy a kifejezésben szereplő értékadás a kifejezés egy köztes eredményét is tárolja, ami a program egy későbbi pontjában felhasználható anélkül, hogy azt újra kellene számítani.
Példa:

A:=(B:=C+5)*2;

Ha C értéke 10, akkor B értéke 15 (10+5) lesz, A értéke pedig 30 (15*2).
Menet közbeni értékadás bármilyen kifejezlsben megengedett, és a kifejezésben többszörös értékadás is szerepelhet:

IF (B:=C:=D+5) > 10 THEN WRITE(B);

Ha B értéke 6, akkor B és C a 11 (6+5) értéket veszi fel. A feltételes utasítás (ld. 3.4. pont) végrehajtódik, mert a kifejezés értéke nagyobb, mint tíz.

3.3. Címkék és vezérlésátadó utasítások
A címkék fogalmát az 1. fejezet 2. pontjában ismertük meg. Emlékeztetünk rá, hogy a címkék az utasítások megnevezésére szolgálnak, és a vezérlésátadó utasításokkal kapcsolatban van fontos szerepük.
Az ALGOL nyelvben címkeként tetszőleges azonosítót vagy előjel nélküli egész számot használhatunk. A címkékkel kapcsolatban bevezetünk egy új alapjelet, a kettőspontot. Ez választja el a címkét az utasítás többi részétől. Bármely ALGOL-utasítás viselhet akárhány címkét. Ha egy utasításnak több címkéje van, akkor ezeket a címkéket is kettőspont választja el egymástól. Például az

L2: Ro: 3: x:= k+2*i;

utasításban L2, Ro és 3 címkék; L2 és Ro azonosító, 3 pedig előjeltelen egész.

A vezérlésátadó utasítás szerepét a GO TO vagy GOTO utasítás tölti be. A GO TO alapszópár a közte levő szóközzel együtt egyetlen alapjelnek tekintendő, tehát a GO és a TO nem külön-külön alapjelek. Miután a GO TO-nak egybe-, illetve különírása állandó vita tárgya, az ALGOL-M így is, úgy is elfogadja, vagyis a GO TO és GOTO utasítás hatása ugyanaz.
A GO TO utasítás legegyszerűbb változatában a GO TO alapjel után valamely címke áll:

GO TO L

Az utasítás hatására a vezérlés megkeresi azt az utasítást, amely az L címkét viseli, és a program végrehajtását ennél az utasításnál folytatja. A GOTO utasítások csak az aktuális blokkon belüli vagy egy külső blokkon belüli elágazásra használhatók.
A GO TO utasítások is viselhetnek címkét. Speciálisan, ha egy GO TO utasítás ugyanazt a címkét viseli, mint amelyre ugrat, akkor, ha egyszer rákerült erre az utasításra, ettől kezdve mindig ugyanezt fogja ismételni a végtelenségig. Ilyen utasítás a következő:

L: go to L;

Ezt a szituációt végtelen ciklusnak nevezzük. Szándékosan nem szokás előidézni, legalábbis ALGOL-programokban nem. (Bizonyos gépek belső kódjában nincs megállási utasítás, és ezért ezeken a gépeken a megállást szándékosan előidézett végtelen ciklussal imitálják.) Annál gyakrabban előfordul programozási hiba következtében, hogy a gép olyan programhurokba kerül, amelyből nincs kijárat.

3.4. Feltételes utasítások és feltételes kifejezések
Az alábbiakban szükségünk lesz három újabb szóalapjelre. Ezek a következők: IF (ha), THEN (akkor) és ELSE (egyébként).
Az if és a then alapjelek segítségével definiálunk egy fontos szintaktikus egységet, amelynek az ALGOL nyelvben rendkívül nagy szerepe van. Ez a szintaktikus egység a logikai feltétel. Logikai feltételt akkor kapunk, ha az if és a then alapjelek közé egy logikai kifejezést írunk. A logikai feltétel általános alakja tehát a következő:

if L then

ahol L tetszőleges logikai kifejezés.
Összhangban a szokásos szóhasználattal, egy logikai feltételről akkor mondjuk, hogy teljesül, ha a benne szereplő L logikai kifejezés aktuális értéke true, vagyis igaz, és azt mondjuk, hogy nem teljesül, ha L aktuális értéke false, vagyis hamis.
A logikai feltételek első alkalmazásaként megismerjük most a feltételes utasítás fogalmát. A feltételes utasításnak két alaptípusa van, mégpedig:

if L then U1 else U2

és

if L then U

Itt L tetszőleges logikai kifejezés, U1, U2 és U pedig ALGOL-utasítások.
Az if L then U1 else U2 utasítás végrehajtási szabálya a következő:

  1. Megvizsgálandó, hogy a feltételes utasításban szereplő logikai feltétel teljesül-e.
  2. Ha a feltétel teljesül, akkor végrehajtandó az U1 utasítás.
  3. Ha a feltétel nem teljesül, akkor végrehajtandó az U2 utasítás.
  4. A logikai feltételnek megfelelő U1, ill. U2 utasítás végrehajtása után, a feltételes utasítást a felírás sorrendjében követő ALGOL-utasításra kell áttérni, hacsak a végrehajtott (U1, ill. U2) utasítás ettől eltérően nem rendelkezik.

Az else alapjel az ALGOL-ban végjel értékű alapjel, és ezért külön pontosvesszőre előtte nincs szükség, sőt, else elé nem is szabad pontosvesszőt írni.
Megjegyzés: Egy if ... then ... else ... típusú utasítás végrehajtása során az U1 és U2 utasítások közül mindig csakis az egyiket kell végrehajtani. Az ALGOL nyelv szabályai megengedik, hogy a másik utasítás az adott pillanatban szemantikusan értelmetlen legyen, például értékkel nem bíró változó szerepeljen benne, vagy az őt felépítő kifejezések ne legyenek kiszámíthatók (zérus nevező, gyök alatti negatív mennyiség stb. miatt). Az utasításnak azonban szintaktikusan rendben levőnek kell lennie. Egy szemantikai rendellenesség "rendbe jöhet", mire a gépen a kérdéses utasítás végrehajtására sor kerül, ha ugyan egyáltalán valaha is sor kerül rá, de egy szintaktikus hiba nem jön rendbe, és a fordító-program le sem fordítja a programot, ha az szintaktikusan hibás.

Az if L then U szemantikailag még egyszerűbb. A szabályok a következők:

  1. Megvizsgálandó a logikai feltétel teljesülése.
  2. Ha teljesül, végrehajtandó az U utasítás.
  3. Ha nem teljesül, át kell térni a soron következő utasításra.
  4. Amennyiben az U utasítás eltérően nem rendelkezik, annak végrehajtása után szintén a soron következő utasítással kell folytatni a program végrehajtását.

Az ALGOL szintaktikus szabályai megengedik, hogy a feltételes utasításban U2 maga is feltételes utasítás legyen. Ebben az esetben az else alapjel után újabb if következik. A második else után következhet egy harmadik if stb. Ilyen módon tetszőleges hosszúságú, ún. láncolt feltételes utasítások jöhetnek létre. A lánc akkor ér véget, amikor egy else után feltétlen, vagy if L then U típusú feltételes utasítás következik. Az alábbi jelsorozatok három tagból álló feltételláncokat mutatnak be:

if L1 then U1 else if L2 then U2 else if L3 then U3 else U4; V;
If L1 then U1 else if L2 then U2 else if L3 then U3; V;

Az első példánál feltesszük, hogy U4 feltétlen utasítás, és a lánc valóban véget ér a harmadik tag után. A második példa harmadik tagja if ... then ... típusú, és így a lánc továbbfolytatására nincs lehetőség. Mindkét esetben V a következő utasítást jelenti.
Hozzá tartozik a feltételes utasítások szemantikájához a címkék kérdése is. Az U1, U2, ... utasítások bármelyike viselhet címkét. Szabad erre a címkére ráugratni. Amikor a feltételláncokat tárgyaltuk, mindig csak az else után engedtünk meg újabb feltételes utasítást. Logikusan azt várná az ember, hogy ha az else után szabad újabb feltételes utasítást kezdeni, akkor szabad a then után is. Ez azonban nem így van. Az ALGOL-ban then után if-et semmilyen körülmények között nem szabad írni!
Bemutatunk most egy példát ennek indoklására. Ha meg lenne engedve, hogy a then után is írhassunk if-et, akkor szintaktikusan helyes lenne az alábbi ALGOL-utasítás:

if i=k then if p=q then x:=y else u:=v

Azonban ez az utasítás nem lenne szemantikailag értelmezhető, mert nem lehetne megállapítani, hogy az egyetlen else a két then közül melyikhez tartozik. A then utáni if tilalmának megkerülésére több lehetőség kínálkozik. if . then . else . típusú utasítások esetén, ha U1 feltételes utasítás lenne, de U2 nem, akkor egyszerűen a feltételt ellenkezőjére fordítjuk, és kicseréljük U1-et U2-vel. Tehát

if L then U1 else U2

helyett írhatjuk:

if not L then U2 else U1

Néha célravezető a logikai műveletek alkalmazása. Tegyük fel például, hogy a következő utasítás felírására volna szükség:

if x=1 then if y=2 then x:=2*y

Itt a then utáni if eltüntethető a logikai szorzás műveletének segítségével:

if x=1 and y=2 then x:=2*y

Ha a fentiekhez hasonló fogások nem vezetnek eredményre, akkor az ún. utasítás-zárójelek alkalmazásához kell folyamodnunk. Ezekről a következő pontban lesz szó.
Bevezetünk most még egy fogalmat, amelyet az ALGOL-ban elég gyakran használnak. Üres utasításnak nevezünk egy olyan ALGOL-utasítást, amely nem áll másból, mint egy magában álló végjel értékű jelből, amilyen pl. egy magában álló pontosvessző. Az üres utasítás teljesen hatástalan. Viselhet az üres utasítás címkét is, ebben az esetben a végjel közvetlenül a címkét lezáró kettőspont után áll. Példa üres utasításra:

alfa : ;

Hasonló konstrukciót főként az end alapjellel kapcsolatban szoktunk alkalmazni.
Az üres utasításnak a szabatos beszédmód szempontjából is van jelentősége. Ha egy utasításról azt akarjuk mondani, hogy bizonyos feltételek teljesülése esetén hatástalan, ezt úgy is kifejezhetjük, hogy "hatásában egyenértékű egy üres utasítással". Így például a if L then U utasítás hatása egyenértékű az üres utasítással, ha a benne szereplő logikai feltétel nem teljesül.

A fejezet elején megismert "logikai feltétel" szintaktikus kategóriájának segítségével a feltételes utasításokon kívül, más jelsorozatokat is képezhetünk. Az alábbiakban megismerjük a feltételes kifejezés fogalmát. A feltételes kifejezések lehetnek aritmetikai és logikai típusúak. A 2. fejezetben megismert feltétlen kifejezésekhez hasonlóan, a feltételes kifejezések is egy szám-, illetve logikai értéket határoznak meg, amely a kifejezésben szereplő változók aktuális értékeinek függvénye. Következésképpen a feltételes kifejezések, akárcsak a feltétlenek, nem utasítások, hanem csak utasítások alkatrészei. Azért tárgyaljuk őket mégis az utasítások között, mert szemantikájuk igen sok tekintetben hasonló a feltételes utasításokéhoz.
Szintaktikus szempontból, a feltételes aritmetikai kifejezés általános alakja a következő:

if L then A1 else A2

Itt L tetszőleges logikai kifejezés, A1 és A2 aritmetikai kifejezések. A kifejezés kiértékelése közben az A1 és A2 aritmetikai kifejezések közül mindig csakis az egyiket kell kiszámítani. Ugyanebben az időpillanatban a másik kifejezés szemantikailag értelmetlen is lehet.
Példák feltételes kifejezésekre:

if A and B then x-y else a**2-b**2
if i<>j then a*b else 1/a

A feltételes aritmetikai kifejezések kiszámítási szabálya messzemenő analógiát mutat a feltételes utasítások végrehajtási szabályával. Eszerint:

  1. A kifejezés kiszámítását a logikai feltétel kiértékelésivel kell kezdeni.
  2. Ha a logikai feltétel teljesül, akkor kiszámítandó a then utáni A1 aritmetikai kifejezés aktuális értéke, és ez az érték lesz a feltételes kifejezés aktuális értéke is.
  3. Ha a logikai feltétel nem teljesül, akkor kiszámítandó az else utáni A2 aritmetikai kifejezés aktuális értéke, és ez az érték adja a feltételes kifejezés értékét.

Példa:
Írjunk olyan értékadó utasítást, amely 1-et ír az y változóba, ha x kívül van a [-1, +1] intervallumon, és 1+x**2-et, ha x az említett intervallum belsejében vagy határán van!

y:= if -1<=x and x<=1 then 1+x**2 else 1

A feltételes aritmetikai kifejezések főként - de nem kizárólag - értékadó utasítások jobb oldali kifejezéseiként fordulnak elő. A feltételes utasításokkal ellentétben, mindig szerepel bennük az else alapjel. Az else nélküli feltételes utasításoknak sem a feltételes aritmetikai, sem a feltételes logikai kifejezések körében nincs megfelelője.
A feltételes utasításokhoz hasonlóan, feltételes kifejezésekből is képezhetünk láncokat. Feltételláncok úgy jönnek létre, hogy egy feltételes kifejezés else utáni kifejezése maga is feltételes kifejezés. Ilyenkor az else után újabb if következik. Tetszőleges hosszúságú láncok megengedettek. A következő jelsorozat három tagból álló láncot mutat be:

if L1 then A1 else if L2 then A2 else if L3 then A3 else A4

Az ilyen típusú feltételes kifejezések kiszámítási szabálya az ismert szabály rekurzív alkalmazásával nyerhető. E szabály szerint, a feltételes kifejezés aktuális értéke az Ai aritmetikai kifejezés aktuális értékével egyenlő, ha a láncban szereplő első i-1 logikai feltétel nem teljesül, de az i-edik teljesül, és a legutolsó else utáni aritmetikai kifejezés aktuális értékével egyenlő, ha a logikai feltételek egyike sem teljesül.

Feltételláncok alkalmazásaként oldjuk meg a következő feladatot:
Legyenek a, b, c, d, e, f, x és m valós típusú változók. Feltesszük, hogy az x változó aktuális értékére az

a <= x <= b,
c <= x <= d,
e <= x <= f

egyenlőtlenségek közül egy és csakis egy teljesül. Írjunk ALGOL értékadó utasítást, amely az m változóba helyezi el a, c, ill. e értékét aszerint, hogy a három egyenlőtlenség közül rendre az első, a második, ill. a harmadik teljesül-e. Megoldásként alkalmas a következő utasítás:

m := if a<=x and x<=b then a else if c<=x and x<=d then c else e

A harmadik egyenlőtlenség teljesülését már nem kell vizsgálnunk, mert ha az első kettő nem teljesül, akkor a feladat feltevéseinek értelmében a harmadiknak biztosan teljesülnie kell.
A feltételes kifejezések esetében hasonlóan a feltételes utasításokhoz, szintén fennáll a then utáni if tilalma, tehát csak az else után állhat ismét feltételes kifejezés. A then utáni if a feltételes utasításokra ismertetett módon itt is elhárítható, azonban a problémát teljes általánosságban megoldja az a fontos szemantikai szabály, amely szerint bármely feltételes kifejezés elsődleges kifejezésnek számít, ha zárójelbe zárjuk. Ez azt jelenti, hogy ha a feltételes kifejezést, amelyet a then után kívánunk elhelyezni, kerek zárójelbe zárjuk, ezáltal megszüntettük feltételes jellegét, tehát baj nélkül alkalmazhatjuk. Igaz: most már nem if következik a then után, hanem kezdőzárójel, amit már megenged a szintaxis.
Feltételes kifejezés nem lehet semmiféle kétparaméteres művelet operandusa. Szintaktikusan hibás például a következő jelsorozat:

a + if x<y then b else c

Mivel azonban minden feltételes kifejezés elsődleges kifejezéssé válik, ha zárójelbe helyezzük, és elsődleges kifejezés már lehet operandus aritmetikai műveletben, a példában szereplő feltételes kifejezést zárójelbe zárva, már a szintaxissal összeférő jelsorozatot kapunk:

a + (if x<y then b else c)

Első pillanatban nem tűnik érthetőnek, hogy az előbbi alakot miért nem lehet megengedni? Az értelmezésével nem is lenne semmi baj. Azonban cseréljük fel a jelsorozat két tagját, és máris olyan jelsorozatot kapunk, amelynek szemantikája nem állapítható meg egyértelműen:

if x<y then b else c+a

ezt érthetnénk akár így:

if x<y then b else (c+a)

akár így:

(if x<y then b else c)+a

Azzal, hogy a feltételes kifejezést zárójelbe zárjuk, minden esetben egyértelmű jelsorozatot kapunk. Igaz, hogy ezáltal tiltottá válnak olyan jelsorozatok is, amelyeket lehetett volna értelmezni. Viszont ha ezt el akarnánk kerülni, a szintaxis bonyolultabb lenne, mert pontosan körül kellene határolni, hogy mely esetben engedhető meg operandusként feltételes kifejezés, és mely esetben nem.

A továbbiakban az aritmetikai kifejezés legáltalánosabb esetének a feltételes kifejezést tekintjük. Ez azt jelenti, hogy mindenütt, ahol aritmetikai kifejezések kerülnek szóba, beleértjük ezek közé a feltételes kifejezéseket is, hacsak ennek ellenkezőjét külön ki nem kötjük.
Nincs megengedve feltételes aritmetikai kifejezések alkalmazása relációk jobb és bal oldalán. A 2. fejezet 7. pont elején, a reláció közölt definíciójában tehát lényeges szerepe van annak, hogy relációk képzésénél feltétlen kifejezéseket kell relációjellel összekapcsolni. Erre annakidején nem hívhattuk fel a figyelmet eléggé nyomatékosan, miután addig csak a feltétlen kifejezéseket ismertük. E tilalom egyébként szintén összefügg a then utáni if tilalmával, amint azt a feltételes logikai kifejezések tárgyalása során látni fogjuk.
Eddig két kizáró tilalmat ismertünk meg a feltételes aritmetikai kifejezésekre vonatkozólag: az egyik a feltételes kifejezések then utáni írására vonatkozik, a másik a relációkra. További korlátozást a szintaxis nem is tesz, tehát e két kivételtől eltekintve, a feltételes aritmetikai kifejezések korlátlanul alkalmazhatók.
A feltételes aritmetikai kifejezésekhez teljesen hasonlóak a feltételes logikai kifejezések, melyek egyetlen logikai értéket határoznak meg; ez az érték függ a kifejezést felépítő változók aktuális értékétől. A feltételes logikai kifejezés általános alakja a következő:

if L then K1 else K2

Itt L, K1 és K2 logikai kifejezések.
A kifejezésben K2 maga is lehet feltételes kifejezés. Ennek else-je után ismét következhet feltételes kifejezés. Az ALGOL szintaxisa azonban azt is megengedi, hogy L legyen feltételes logikai kifejezés, és ezzel egy másfajta feltétellánchoz jutunk:

if if L1 then K1 else M1 then K2 else M2

A jelsorozat aktuális értékének kiszámítását az ismert szabály rekurzív alkalmazásával kell végezni. Eszerint a számítást a logikai feltétel kiértékelésével kell kezdeni. Az L logikai feltétel helyébe itt ismét egy if L then K1 else K2 típusú logikai kifejezés került. Ezt tehát megint csak az ismert algoritmus alapján kell kiszámítani. Az L1 logikai feltétel teljesülése, ill. nem teljesülése alapján választunk a K1 és M1 logikai kifejezések között. Kiértékeljük a megfelelőt, és ennek aktuális értéke lesz a jelsorozat feltételének aktuális értéke, tehát ezen érték alapján választunk a K2 és M2 kifejezések között. A kifejezés aktuális értéke végeredményben K2 és M2 közül a megfelelőnek aktuális értéke.
L1 ismét lehet feltételes kifejezés. Ilyenkor három if áll egymás után. Ilyen kifejezés kiszámításánál algoritmusunkat háromszor kell rekurzíve alkalmazni. Az ALGOL nyelv megengedi a feltételek akárhányszoros egymásba skatulyázását. Megjegyezzük, hogy egymásba skatulyázott feltételek nemcsak logikai, hanem aritmetikai kifejezésekben is előfordulhatnak.
A feltételes kifejezések szintaxisával kapcsolatos szabályt úgy foglalhatjuk össze, hogy if, valamint else után következhet újabb if, de then után nem.
A feltételes logikai kifejezések az ALGOL szokványos felhasználási területein ritkán találnak alkalmazásra. Tárgyalásukra inkább csak a teljesség kedvéért tértünk ki; alkalmazásukra igazán gyakorlati példát nehéz lenne találni.

3.5. Összetett utasítások
Az előző pontban említettük, hogy az ALGOL-ban lehetőség van az utasítások zárójelezésére, azaz egy több elemi utasításból álló utasításcsoport - külön e célra szolgáló "zárójelek" segítségével - egyetlen utasítássá fogható össze, hasonlóan az aritmetikai és logikai kifejezésekhez, amelyekben a zárójel egy hosszabb részkifejezést egyetlen egységgé fog össze. Az utasítások zárójelezésére bevezetett alapjeleket utasítás-zárójeleknek nevezzük. A kezdő utasítás-zárójel a begin (kezdet), a vég-zárójel az end (vég) alapjel. Bármely ALGOL-utasításcsoport egyetlen feltétlen utasításnak számít, ha utasítás-zárójelek közé zárjuk. A zárójelbe zárt utasítást vagy utasításcsoportot összetett utasításnak nevezzük. Az összetett utasításban szereplő egyes utasítások tetszőlegesek lehetnek; így többek között szerepelhet köztük újabb összetett utasítás. Ilyen esetben az utasítás-zárójelek egymásba skatulyázódnak, ami tetszőleges mélységig megengedhető.
Az utasítások zárójelezésére az aritmetikai kifejezések zárójelezési szabályaival teljesen analóg szabályok érvényesek. Két fontos szabályt mégis külön kiemelünk:

és

begin {utasítások}; begin {utasítások} end; {utasítások} end

Utasítás-zárójeleket alkalmazhatunk akkor is, ha egy feltételes utasításban más módon nem tudjuk eltüntetni a then utáni if-et. Az ALGOL szintaxisa megengedi egyetlen ALGOL-utasítás zárójelbe zárását is, de ennek szükségessége csak ebben az egyetlen esetben merül fel.

3.6. Indexes változók
Amikor eddigi tárgyalásainkban változókról beszéltünk, mindig index nélküli, skaláris változókra gondoltunk. Ebben a pontban az indexes változók használatára vonatkozó szabályokat taglaljuk.
A matematikában igen gyakran felmerül a szükségessége annak, hogy bizonyos számcsoportok elemeivel ne csak egyenként tudjunk műveleteket végezni, hanem magukat a csoportokat egészükben is kezelni tudjuk. Ez a helyzet például a lineáris algebra vizsgálatainál, a statisztikában és a matematika sok más ágában is. A számcsoportokon végzett műveletek általában igen nagy mennyiségű aritmetikai és logikai operációt tesznek szükségessé, és ezért elvégzésükre gyakran elektronikus számológépet kell igénybe venni. Az ilyen feladatokban általában nagy mennyiségű számadaton azonos, vagy igen hasonló műveletek elvégzése szükséges. (Gondoljunk például a mátrixalgebra műveleteire, adatok rendezésére, átlagok és egyéb statisztikai függvények képzésére stb.) Eddigi ismereteink alapján ilyen jellegű feladatokat csak igen nehézkesen tudnánk programozni. Ha például azt a feladatot kapnánk, hogy írjunk programot két tízelemű vektor skaláris szorzatának kiszámítására, ezt csak úgy tudnánk megtenni, hogy felírnánk egy hosszú értékadó utasítást, amelyik elemenkénti műveletekre lebontva jelöli ki a kívánt skaláris szorzást:

s := a1*b1 + a2*b2 + a3*b3 + a4*b4 + a5*b5 + a6*b6 + a7*b7 + a8*b8 + a9*b9 + a10*b10

Ez tízelemű vektor esetén, ha nem is kényelmes, de végszükség esetén elviselhető volna. Százelemű vektor esetén azonban már nagyon nehézkes.
Elvben könnyű látni a kiutat. Olyan programot kell szerkesztenünk, amely ciklusban szorozza össze a vektorok egyes elemeit, és minden egyes ciklusban hozzáad egy-egy szorzatot az előző szorzatok részletösszegéhez. De hogyan tudjuk ezt ALGOL-ban leírni? Ha a1, b1, a2, b2, ... egymástól függetlenül definiált skaláris változók, akkor ezeken nem tudunk végigfuttatni egy indexváltozót, mert az "általános", i-edik elemet nem jelölhetjük egyszerűen ai-vel.
A felvetett probléma az ALGOL-ban indexes változók alkalmazásával oldható meg. Az indexes változók valamilyen szempontból összetartozó változók által alkotott csoportok elemei. Az összetartozást azzal fejezzük ki, hogy a változócsoport elemeit közös azonosítóval látjuk el, és a csoport egyes elemeinek az azonosítón kívül egy vagy több hivatkozási számot is adunk. A hivatkozási számot vagy számokat nevezzük indexeknek. Egy indexes változó akkor van meghatározva, ha azonosítóján kívül valamennyi indexe adott.
Az indexes változókat a skaláris változóktól elkülönítve deklarálják. A deklarációban a változók azonosítóján kívül az egyes indexek értékhatárait is fel kell tüntetni.
Az indexes-változók teljesen úgy viselkednek, mint az index nélküli, skaláris változók. Típusuk, akárcsak a skaláris változóké, lehet egész, valós vagy szövegfüzér. Ugyanúgy használhatók kifejezésekben, értékadó utasításokban. Az egyetlen eltérés, hogy az indexes változó aktuális értékéhez való hozzáférés előtt előbb indexeinek aktuális értékeit kell meghatároznunk.
Az indexeket az ALGOL-ban szögletes zárójelbe zárva, egymástól vesszővel elválasztva soroljuk fel. Az index definiálható tetszőleges aritmetikai kifejezés segítségével. Ha az indexet nem számkonstanssal, hanem változóval vagy aritmetikai kifejezéssel adjuk meg, akkor az index számértékét (aktuális értékét) ezeknek a kifejezéseknek, illetve változóknak aktuális értéke határozza meg.
Példák indexes változókra:

p[i,k]
A[i+j,2*i]
g[5,3,j,k,n]
B[if a>b then 2 else 3]

Ezekre a változókra való hivatkozásnak nyilván csak akkor van értelme, ha az indexkifejezéseknek van aktuális értékük, és ez az érték az előre definiált értékhatárok közé esik. Magától értetődő követelmény az is, hogy az indexek száma megegyezzék a deklarációkban rögzített indexszámmal. Az indexek száma nincs felülről korlátozva; szabad akárhány indexes változót is deklarálni.
Az előzőekben már említettük az indexes változók deklarálását. Ennek részletes tárgyalására a könyv IV. fejezetében 3. pontjában kerül sor. Az indexes változók csoportjait gyűjtőnéven tömböknek nevezzük. A tömb speciális esete a vektor (egyméretű tömb, egyindexes változók csoportja), valamint a mátrix (kétméretű tömb, kétindexes változók csoportja).
Néhány további szemantikai szabály az indexes változókkal kapcsolatban:

  1. Indexként valós típusú változót vagy valós értékű aritmetikai kifejezést is alkalmazhatunk, bár az index mindig egész szám. Ilyen esetben a valós értékről az egészre az, értékadó utasításoknál tárgyalt kerekítési szabály szerint kell áttérni. Az indexet mindig úgy kell tekinteni, mintha ki nem írt egész típusú fiktív változó volna, és az indexkifejezések kiszámítása valójában értékadás erre a fiktív változóra nézve.
  2. Egy indexes változó indexkifejezésében tetszés szerinti számú újabb indexes változó szerepelhet. Ezt a szabályt rekurzíve értelmezve, kimondhatjuk, hogy az indexek tetszőleges mélységben egymásba skatulyázhatok.
  3. Külön szemantikai szabály rendelkezik az olyan értékadó utasításokról, amelyek bal oldali változója indexes változó: az ilyen utasításokat oly módon kell végrehajtani, hogy előbb meghatározzuk az összes bal oldali változó indexkifejezéseinek aktuális értékét, mégpedig - ha több indexkifejezés van - szigorúan balról jobbra tartó sorrendben, és ezután a jobb oldali kifejezés aktuális értékét. E szabály nélkül egyes értékadó utasítások értelmezése kétes volna. Például:

    A[i] := i := i+1;

Legyen i aktuális értéke 2. A kimondott szabály értelmében az i, és az A[2] változóknak 3-at ad értékül. A lényeg az, hogy itt az A[2], és nem az A[3] változót kell figyelembe venni. Az utasítás ugyanis megváltoztatja az i indexváltozó aktuális értékét is, de csak az indexkifejezés aktuális értékének meghatározása után.

Példák:
Első példaként vizsgáljuk a fejezet elején felvetett feladatot, két vektor skaláris szorzatának meghatározását. Legyen a két vektor (egyméretű tömb) azonosítója a és b, a közös rendszám n. Legyen az eredmény az S változó értéke. A program:

S:=0; i:=1;
L: if i=n+1 then go to out;
S:=S+a[i]*b[i];
i:= i+1;
go to L;
out:
{folytatás}

A jelen pont elején kitűzött feladatot sikerült megoldanunk, az indexes változók segítségével programhurkot generáltunk a skaláris szorzás feladatához. A programot bevezető S:=0 utasítás a gyűjtőrekesz törlése. Meg kell szoknunk, hogy ha egy rekeszt (változót) egy szumma részletösszegeinek tárolására használunk, és ennek a rekesznek a tartalmához valamely ciklus minden egyes menetében hozzáadunk egy újabb tagot - amint azt a programban az S:=S+a[i]*b[i] utasítás teszi -, ezt a változót a ciklus elején törölnünk kell, azaz nullát kell adnunk értékéül. Ha ez az utasítás nem állna a program elején, az S változó úgy kerülne aritmetikai kifejezésbe, hogy előzőleg nem volna definiált értéke, és ezért az egész aritmetikai kifejezés értéke határozatlan volna. Az "out" címke a program folytatását jelképezi. A program szerkezete világos; a gép minden egyes ciklusban összeszorozza a vektorok egy-egy elempárját, hozzáadja az eredményt az előző szorzatok részösszegéhez, megnöveli i értékét, és addig folytatja az eljárást, amíg i el nem érte az n+1 értéket.

Második példa: Írjunk programot egy A négyzetes mátrix és egy b vektor szorzatának meghatározására. Az eredmény legyen a c vektor. A rendszám n. A program:

   j:=1;
K: if j=n+1 then go to out;
   s:=0; i:=1
L: if i=n+1 then go to M;
   S:=S+A[j,i]*b[i]; i:=i+1;
   go to L;
M: c[j]:=S; j:=j+1;
   go to K
out:
{folytatás}

A program némi bővítéssel adódik az első példából. Itt kétszeresen egymásba skatulyázott ciklussal van dolgunk. A belső ciklus rögzített j mellett, skalárisán összeszorozza az A mátrix j-edik sorát a b vektorral. A skaláris szorzás programja teljesen megegyezik az előző programmal. E köré a program köré van építve egy külső ciklus, amely egy skaláris szorzás elvégzése után "továbbviszi" eggyel j értékét, és a megnövelt j-vel megismételteti a skaláris szorzást. Az algoritmus véget ér, ha j elérte az n+1-et, azaz már az n-edik sort is összeszorozta a gép a b vektorral.
A példával kapcsolatban még egy megjegyzést kell tennünk. A figyelmes Olvasó bizonyára észrevette, hogy az S segédváltozó látszólag felesleges, ha helyébe mindenütt c[j]-t írnánk, akkor a c[j]:=S értékadó utasítás fölöslegessé válnék, és egy látszólag rövidebb programhoz jutnánk. Ez meg is felel a valóságnak, és az így kapott program mind szintaktikusan, mind szemantikailag kifogástalan lenne. Publikációs célra készült program esetén ez a rövidítés kívánatos is, mivel fokozza a program áttekinthetőségét. Ha azonban a programot gépre szánjuk, akkor a bemutatott változat időben gazdaságosabb, mert az indexes változókhoz való fordulás mindig hosszabb időt vesz igénybe, mint n skaláris változókhoz való fordulás. Éppen ezért időtakarékosság céljából minden olyan helyen, ahol ezt a program szerkezete megengedi, az indexes változókat skalárisokkal célszerű helyettesíteni.

3.7. Ciklusutasítások
Már az eddig tárgyalt példaprogramok között is szerepelnek néhányban különféle programhurkok (ciklusok). E programokból is látható, hogy a programciklusok három lényeges alkatrészt tartalmaznak, éspedig:

  1. A ciklus előkészítése, bizonyos - a ciklusban értéküket megváltoztató - mennyiségek kezdeti értékének beállítása;
  2. A ciklusban változó mennyiségek továbbléptetése, értékük megváltoztatása;
  3. A ciklusból való kilépés fölött döntő logikai vizsgálat, vezérlésátadás vagy a program folytatására, vagy a ciklusban ismétlendő utasítások további végrehajtására.

A 2. pontba tartozó utasításokat a ciklus "magjának" nevezzük.
Ha összevetjük az előző példaprogramokat, észrevesszük, hogy azok tartalmaznak néhány igen hasonló utasítást. Szerepel bennük ugyanis egy-egy változó, amelyre vonatkozóan valamely logikai feltételnek kell teljesülnie a ciklusból való kilépéshez, és mindhárom programban egyaránt megtalálható e változók kezdőértékének a beállítása, továbbléptetése, és a reá kirótt logikai feltétel teljesülésének ellenőrzése. Ezek az utasítások tulajdonképpen nem vesznek részt az effektív számításban, csupán a program vezérléséhez szükségesek. Adminisztratív utasításoknak is szokták őket nevezni. A második program kissé bonyolultabb az elsőnél. Itt két egymásba skatulyázott ciklusunk van, és így a ciklusszervezéssel kapcsolatos adminisztráció is kétszeres.
Annak érdekében, hogy a ciklusok szervezésének adminisztrációs utasításaiba kevesebbet kelljen írni, az ALGOL-ban vannak olyan utasítások, amelyek egyesítik magukban egy kiválasztott változó kezdeti értékének beállítását, ciklusonkénti továbbléptetését, és a ciklusból való kilépéshez szükséges logikai vizsgálatot; az ilyen speciális utasításokat ciklusutasításoknak nevezzük. Ebben a pontban a ciklusutasítások különféle típusaival foglalkozunk.
Az ALGOL ciklusutasításainak két alaptípusa van, ezekkel azonban igen sok változat képezhető. Először az alaptípusokat ismertetjük, majd áttérünk a kombinált típusok tárgyalására.
A ciklusutasítások tárgyalását lét újabb alapjel bevezetésével kezdjük: ez a for és a while. Minden ciklusutasítás ezek valamelyikével kezdődik.

a) A ciklusutasítás első alaptípusa
A ciklusutasítás első alaptípusában a cikluskezdetet a következő konstrukció követi:

for V: = A1 step A2 until A3 do U;

ahol A1, A2 és A3 tetszőleges aritmetikai kifejezések, a step,az until és a do pedig újabb ALGOL-alapjelek. A do elhatároló jelet valamilyen U utasítás követi. U általában összetett utasítás, és a ciklus magját képviseli.
Az utasítás végrehajtása azzal kezdődik, hogy a V változó, amelyet a továbbiakban ciklusváltozónak fogunk nevezni, felveszi az A1 aritmetikai kifejezés aktuális értékét. Ezt követőleg a gép megvizsgálja, hogy V értéke elérte-e már A3 értékét. (Később pontosan definiálni fogjuk, hogy mit értünk ezen.) Ha V még nem érte el A3 értékét, akkor végrehajtódik az U utasítás. U végrehajtása után V értéke megnövelődik A2 aktuális értékével, és a gép ismét megvizsgálja, hogy elérte-e már A3-at. Ha nem, akkor ismét végrehajtódik U, ismét megnövelődik V értéke, és ismét vizsgálat következik, hogy elérte-e már V az A3-at. A ciklus addig ismétlődik, amíg csak V el nem éri A3-at; ezután a gép áttér a ciklusutasítás utáni utasítás végrehajtására.
Az U utasítás általában (de nem feltétlenül) valamilyen formában függ a V ciklusváltozótól.

Példaként tekintsük ismét a skaláris szorzás programját. Tanulságos összehasonlítani ezt a program-változatot az előző pontban bemutatott példával, hogy lássuk, mennyiben egyszerűsíti le a programot a ciklusutasítások bevezetése.
A program:

s:=0;
for i:=1 step 1 until n do
  S:=S+a[i] *b[i] ;

A program szerkezete ugyanaz, azonban az i változó módosításáról, kezdőértékének beállításáról és a kilépési vizsgálatról "egy személyben" a for utasítás gondoskodik.
Megjegyezzük, hogy a step ... until típusú ciklusban az U utasítás még akkor is végrehajtódik, amikor a ciklusváltozó értéke éppen egyenlő az A3 kifejezés aktuális értékével (példánkban i=n-nel). A ciklusutasítás második alaptípusa (ld. b) alpont) tárgyalása előtt megelőlegezhetjük, hogy az ALGOL-M-ben nincs hagyományos értelemben vett hátultesztelős ciklus (amikor a ciklus magja egyszer mindenképpen lefut, és a ciklusmagban bekövetkező események hatására dől el, hogy befejeződik-e a ciklus végrehajtása). Ez a szerkezet a for ciklussal helyettesíthető: ha egy esemény vizsgálatának hatására a ciklusváltozó értékét értékadó utasítással A3-ra (a ciklusváltozó végértékére) állítjuk, a for utasítás következő vizsgálatakor a ciklusváltozó értéke A3+1-re növekszik és a ciklus végrehajtása befejeződik.
Egymásba skatulyázott ciklusok oly módon képezhetők, hogy az U utasítás valamelyik utasítása helyébe újabb for utasítást írunk, írjuk át például for utasítás segítségével a négyzetes mátrix és vektor szorzatának számító példaprogramot ciklusutasítások segítségével:

for j:=1 step 1 until n do begin
  S:=0;
  for i:=1 step 1 until n do
    S:=S+A[j,i]*b[i];
  c[j]:=S;
end;

A példaprogram két egymásba skatulyázott ciklusból áll. A külső ciklus a j sorindex szerint halad, és magja egy összetett utasítás. A ciklus magján belül egy újabb, i szerinti ciklusutasítást találunk. Ez utóbbinak magja egyetlen értékadó utasításból áll, ezért a második do után nem következik begin. Jól jegyezzük meg: a ciklusutasítás magja lehet elemi vagy összetett utasítás. Ha a ciklusmag egyetlen elemi utasításból áll, akkor a do után nem áll begin. Ez a helyzet az i szerinti ciklusánál. Ezzel szemben, ha a ciklus magja összetett utasítás, akkor a do után begin következik. (Ha speciálisan a ciklusutasítás magja egyetlen újabb ciklusutasítás, akkor nem kell a do után begin, mert a ciklusutasítás, magjával együtt, elemi utasítás, még akkor is, ha a ciklusmag összetett utasítás.)

Az általunk felhozott példák eléggé speciálisak abból n szempontból, hogy azokban az A1, A2, A3 aritmetikai kifejezések mind számkonstansok vagy változók. Általános esetben ezek tetszőleges aritmetikai kifejezések lehetnek, amelyek értéküket változtathatják a ciklus minden egyes lefutásakor, hiszen az U utasítás értéket adhat bármelyik A1-et, A2-t vagy A3-at felépítő változónak.

b) A ciklusutasítás második alaptípusa
A ciklusutasítás második alaptípusában a cikluskezdet alakja:

while L do U

ahol L logikai kifejezés, U tetszőleges utasítás.
Szemantikai szempontból az utasítás jelentése a következő:

  1. Megvizsgálandó az L logikai kifejezés aktuális értéke.
  2. Ha L aktuális értéke true, akkor végrehajtandó az U utasítás, és ezután vissza kell térni a while utasításra, megismétlendő a logikai vizsgálat.
  3. Ha L aktuális értéke false, akkor át kell térni a soron következő utasítás végrehajtására.

Végeredményében ez a ciklusutasítás azt jelenti, hogy mindaddig ismételni kell az U utasítás végrehajtását, amíg csak az L kifejezés true értékű marad, és amint ez az érték false-ra változik, át kell térni a következő utasításra.
A while típusú ciklusutasítás jól használható abban az esetben, ha nem tudjuk előre, hányszor kell a ciklust lefuttatni. Ez a helyzet például iterációs eljárások programozása esetén, amikor a ciklusok száma az iteráció konvergenciájának gyorsaságától függ.
Példa két szám legnagyobb közös osztójának kiszámítására (a mod függvényt későb fogjuk elkészíteni):

INTEGER FUNCTION GCD(X,Y);
INTEGER X,Y,T;
BEGIN
  WHILE Y>0 DO BEGIN
    T:=Y; Y:=MOD(X,Y); X:=T;
  END;
  GCD:=X;
END;

3.8. Kiválasztó utasítás
A kiválasztó utasítás segítségével könnyen megoldhatjuk a programunk egy értéktől függő többirányú elágaztatását. Az ALGOL-ban nem szabványosnak számító CASE szerkezet alakja:

CASE kifejezés OF
BEGIN
   utasítás1;
   utasítás2;
   utaítás...;
END;

A kifejezés (leggyakrabban egyetlen változó) egész típusú. A választott utasítás az egész kifejezés értékétől függ: ha értéke 0, az BEGIN után álló első utasítás kerül végrehajtásra, ha az értéke 1 a második utasítás, stb. A megadott utasítás - ami lehet összetett utasítás is - végrehajtása után a program futása a CASE szerkezetet lezáró END utáni utasításra kerül (tehát a CASE-szerkezetből csak egy utasítás kerül végrehajtásra). Ha nincs a kifejezés értékének megfelelő utasítás, akkor egy üres utasítás hajtódik végre.). ELSE-ág megadására nincs lehetőség.
Példa:

WRITEON ("Select function: "); READ(A);
CASE A OF
BEGIN
  WRITE("Case 0");
  WRITE("Case 1");
  WRITE("Case 2");
  WRITE("Case 3");
END;

A CASE-szerkezet utasításai címkét is viselhetnek, amit javasolt is alkalmazni, főleg, ha összetett utasításokat tartalmaznak a CASE ágai:

CASE A OF
BEGIN
  0: WRITE("Case 0");
  1: WRITE("Case 1");
  2: WRITE("Case 2");
  3: WRITE("Case 3");
END;

4. A program kísérő információi

4.1. Bevezetés
Eddigi ismereteink alapján lényegében bármely algoritmust, amely egyáltalán leírható ALGOL-ban, be tudunk programozni. Tudjuk azonban, hogy azok az példaprogramok, amelyekkel a 3. fejezetben foglalkoztunk, nem alkotnak zárt egészet, hanem csupán nagyobb programok kiragadott részeinek tekinthetők. Teljességükhöz mindenekelőtt a használt azonosítókról szóló felvilágosítások, az ún. deklarációk hiányoznak. A deklaráció fogalmával már az 1. fejezetben megismerkedtünk. Ebben a fejezetben főként az ALGOL nyelvnek a deklarációk megadásira, és azok érvényességére vonatkozó szabályait tárgyaljuk, azonban kitérünk a nem deklaráció jellegű kísérő Információknak, a magyarázó megjegyzéseknek (kommentároknak) használatára és funkciójára is (4.6. pont).
Amint azt az 1. fejezetben említettük, a deklarációk a fordítóprogram számára tartalmaznak információt a programban felhasznált betűjelölésekről, az azonosítókról. A skaláris változók részére a fordítóprogram egy-egy memóriarekeszt tart fenn, ezért azokat egyszerűen felsoroljuk egy megfelelően megadott listán. Az indexes változók esetében azonban nem ilyen egyszerű a helyzet, ugyanis a fordítóprogramnak azt is tudnia kell, hány azonos nevű változó tartozik egy-egy tömbhöz. Egy 12 x 17 típusú mátrix tárolására például 12 x 17 = 204 rekesz kell. A tömbök elemszáma az indexek számától és értékhatáraitól függ, ezért a deklarációnak ezeket is tartalmaznia kell.
Az ALGOL-szerzők a nyelvet úgy igyekeztek definiálni, hogy a lehető legkönnyebb legyen a programozó matematikusok együttműködése, hiszen ez az ALGOL-koncepció egyik alapvető célkitűzése. Ez a körülmény eleve maga után vonja azt a feltételezést, hogy egy ALGOL-programot igen sok esetben nem egyetlen programozó készít el, hanem matematikusok, programozók egy csoportja. A programozók együttműködése vagy úgy történik, hogy egy nagy terjedelmű feladat különböző részeit más és más személy írja meg, vagy pedig úgy, hogy egyes programrészeket változtatás nélkül átvesznek más programokból, programokat publikáló folyóiratokból, ill. programgyűjteményekből.
Magától értetődik, hogy minden önmagában teljes programnak vagy programrésznek saját jelölésrendszere, saját azonosítói vannak. Ha egy programot bele akarunk építeni egy másik programba, csaknem biztosak lehetünk abban, hogy bizonyos gyakori azonosítók mindkét programban szerepelni fognak és mást jelölnek, hacsak előzőleg nem gondoskodunk valamelyik program szisztematikus átjelöléséről. (Például mindkét program használja az x, y, a, b stb. betűket.) Ezzel a betűjelöléseknek nemkívánatos konfúziója jön létre.
Elvi akadályba ugyan nem ütközik, de gyakorlatilag igen kellemetlen feladat a programok átjelölés céljából való felülvizsgálata. Gondoljunk arra, hogy ha egy programot pl. öt különböző helyről "ollóznak" össze, mennyire figyelmesen kell azt átvizsgálnia a "főszerkesztőnek", hogy ne maradjon egyetlen ütközés sem a különböző azonosítók között.
Az ALGOL nyelv ezt a főszerkesztői feladatot a fordítóprogramra hárítja: az ALGOL fordítóprogram maga gondoskodik a különböző jelölésrendszerek összehangolásáról. Az alapgondolat az, hogy az ALGOL-ban a deklarációit érvénye nem az egész programra, hanem annak csak meghatározott részére terjed ki, és ezen a programrészen kívül ugyanaz az azonosító felhasználható más célra is. Ennek további kifejtése céljából először is be kell vezetnünk a blokk fogalmát. Az ALGOL nyelvben bármely összetett utasítás begin-je után deklarációkat helyezhetünk el. Az olyan összetett utasítást, amelynek begin-je után legalább egy deklaráció következik, blokknak nevezzük. A deklaráció érvénye - a megfelelő azonosító ún. hatásköre - csak arra a blokkra terjed ki, amelynek kezdetén deklarálták.
Az ALGOL nyelv blokkstruktúrájának lényege abban áll, hogy a különböző blokkokban deklarált azonosítók teljesen függetleníthetők egymástól, vagyis ha ugyanaz az azonosító két különböző blokkban van deklarálva, akkor ez, már biztosítja azt, hogy ne keveredhessenek össze. Ha tehát a közös azonosítókat tartalmazó programrészeket külön blokkokba helyezzük, ezáltal biztosíthatjuk azok megkülönböztethetőségét. Ez a módszer igen nagymértékben megkönnyíti a különböző személyek által írt programok összeépítését. A következőkben látni fogjuk, hogy a blokkstruktúra egy sereg szemantikai problémát vet fel, Különösen egymásba skatulyázott blokkok esetén.

4.2. Típusdeklarációk
A skaláris változók deklarációja lényegében az azonosítók listaszerű felsorolásából áll. Külön-külön listán soroljuk fel az egész, a valós és a szövegfüzér típusú változókat. Az egyes változóazonosítókat vesszővel választjuk el egymástól, és minden egyes változólista után pontosvessző áll. A változók típusának megjelölésére három új alapjelet vezetünk be, ezek az integer (egész), decimal (valós) és string (szövegfüzér) alapjelek.
Ha például egy blokkban hét változót kívánunk szerepeltetni, mégpedig az x, y és z valós típusú változókat, i, j, k egész típusúakat, és wrd szüvegfüzér típusút, akkor ennek a blokknak a kezdetén (a blokkot megnyitó begin után) a deklarációsorozatot a következőképpen helyezhetjük el:

begin
integer i,j,k;
decimal x,y,z;
string wrd;

A valós típusú változok deklarálásánál a tárolni kívánt számjegyeket is megadhatjuk, ha el akarunk térni az alapértelmezés szerinti 10 számjegytől. Ugyanígy a tárolni kívánt szövegfüzérek hosszát is megadhatjuk, ha el akarunk térni az alapértelmezett 10 karakter hosszúságtól:

decimal(18) x,y,z;
string(255) wrd;

Sem a listákon belüli elemeknek, sem pedig maguknak a listáknak nincs kötött sorrendje. A példában is írhattuk volna elsőnek a szövegfüzér típusú változók listáját, másodiknak az egész típusút, stb. Az sincs kikötve, hogy mindegyik fajta listából csak egyetlen egy lehet egy blokkban: megadható például két valós (decimal alapjellel kezdődő) változólista is. Két dologra azonban ügyelni kell a változók deklarálásával kapcsolatban. Egyrészt, ugyanazt az azonosítót nem szabad kétszer deklarálni, másrészt a blokkban a deklarációs résznek véget vet az első, nem deklaráció jellegű jelsorozat (utasítás), és ezután ugyanazon blokkban újabb deklarációkat már nem szabad írni.
Az ALGOL nyelvben a blokkot megnyitó utasítás zárójelet és az utána következő deklarációkat együttesen blokkfejnek nevezzük. A blokkfejnek ott van vége, ahol a blokk első ALGOL-utasítása kezdődik.

Az ALGOL-ban az utasítászárójelek - így a blokkok is - tetszőleges mélységben egymásba skatulyázhatók. A következőkben azokat a szemantikai problémákat tárgyaljuk, amelyek az egymásba skatulyázott blokkokkal kapcsolatban merülnek fel.
Legyen például valamely A blokkba beleskatulyázva egy B blokk. Legyen az A blokk fejében két változó deklarálva, x és y, a B blokk fejében pedig két másik változó, u és v. Valamennyi változó legyen valós típusú. A program szerkezetét az alábbi séma mutatja:

A: begin decimal x,y;
   {utasítások};
B: begin decimal u,v;
   {utasítások};
   end;
   {utasítások};
   end

Mindenek előtt két fogalmat, a lokális és a nem lokális (globális) változó fogalmát vezetjük be.
Mint látjuk, a sémában az A blokk teljes egészében tartalmazza a B blokkot, B része A-nak. Az x és y változók az A blokk fejében vannak deklarálva, tehát érvényességi körük az A blokkot bezáró end-ig terjed. (Ez a példában a második, "külső" end.) Miután az A blokk tartalmazza B-t, B is beletartozik az x és y változók hatáskörébe. Következésképpen a B blokk belsejében szabad olyan utasítást írni, amely x-re vagy y-ra hivatkozik (például értéket ad x-nek vagy y-nak), annak ellenére, hogy nem a B blokkban vannak deklarálva. Az ilyen változókat globális változónak nevezzük a B blokkra nézne. Ennek ellentéte a lokális változó, amelynek, deklarációja ugyanazon blokkban van elhelyezve. Ilyen változók a B blokkban u és v, az A blokkban x és y. Arról, hogy egy változó lokális vagy globális-e, nyilván mindig csak egy meghatározott blokk viszonylatában van értelme beszélni; például x és y lokális A-ra nézve, de globális B-re. Miután egy azonosítóra való hivatkozásnak csak hatáskörén belül van értelme, az u és v változókra hivatkozó utasításokat csakis B belsejében használhatunk, A-nak B-től idegen részében nem.
Miután egy teljes programban csupa deklarált azonosítónak kell szerepelnie, nyilvánvaló, hogy teljes programban nem szerepelhet globális változó. Gyakorlatilag azt mondhatjuk, hogy minden teljes ALGOL-program blokk, amelyben természetesen lehetnek alacsonyabb rendű alblokkok. (Az ALGOL szintaxisa ugyan megengedi, hogy egy ALGOL-program ne blokk, hanem összetett utasítás legyen, de ez csak úgy fordulhat elő, hogy egy vagy több blokkot beskatulyáznak egy utasítás-zárójelpárba. Ilyen konstrukciót azonban a gyakorlati programozásban nem használnak.)
A blokkból való kilépés után a blokk valamennyi lokális változója elveszti értékét. Előfordulhat, hogy a vezérlés kilép egy blokkból egy magasabb rendű blokkba, majd ismét visszakerül ugyanabba az alacsonyabb rendűbe. Minden egyes ilyen ismételt belépéskor az alacsonyabb rendű blokk valamennyi lokális változója "tiszta lappal" indul, tehát mindaddig nincs értéke, amíg egy értékadó utasítás nem ad neki értéket. Másként fogalmazva, a kilépés után nem őrződik meg a lokális változók utolsó értéke. Az alacsonyabb rendű blokkból magasabb rendűbe való átlépés történhet oly módon, hogy a gép végrehajt egy go to utasítást, amelynek rendeltetési címkéje egy magasabb rendű blokkban van, vagy történhet a kilépés a blokkot bezáró end-en keresztül is. Mindkét esetben elvész a lokális változók értéke.
Blokkba belépni mindig csak a blokkot megnyitó begin-en keresztül szabad, tehát nem lehet go to utasítással blokk belsejébe beugrani.
Az ALGOL szintaxisa megengedi, hogy ugyanazt az azonosítót két - vagy több - hierarchiailag egymás fölé rendelt blokkban is deklaráljunk. Erre példa a következő:

begin decimal x;
   x:=2.5;
   {utasítások};
   begin integer x;
      x:= 3;
      {utasítások};
   end;
   {utasítások};
end

Az A külső blokkban x valós típusú változóként van deklarálva, és ránézve mindjárt értékadás is történik, amelynek következtében felveszi a 2.5 értéket. Ezután a B új blokk kezdődik, amelynek fejében x újra deklarálva van, de most már mint egész típusú változó. Ebben a blokkban is történik értékadás x-re nézve. Kérdés, mi a program szemantikája, mi történik az x változó értékével?
Az ALGOL szabályai úgy rendelkeznek, hogy a külső blokkban a külső érték, a belsőben a belső érték az érvényes. Tehát a B blokknak x-re hivatkozó utasításaiban x mint egész típusú változó szerepel, melynek aktuális értéke 3 (feltesszük, hogy B-ben nincs másik utasítás, amelyik értéket adna x-nek). Ugyanakkor az A blokknak B-től idegen részeiben x valós típusú változó, 2.5 aktuális értékkel. Az újradeklarálással tehát x régi értéke és régi típusa nem vész el véglegesen, hanem csak "látens állapotba" kerül arra az időre, amíg x-nek a B blokkbeli lokális deklarációja van érvényben. A B blokkból való kilépés után az A blokkbeli látens érték ismét aktívvá, és az x = 2.5 érték ismét hozzáférhetővé válik. Ilyen esetben az x azonosító mind az A, mind a B blokkra nézve lokális. Az ehhez hasonló szituációban sem a belső blokkon kívüli változóhoz nem lehet a belső blokk belsejéből hozzáférni, sem pedig a belső blokkon belüli változóhoz a külső blokkból.

Ebben a fejezetben tárgyaltunk egy sereg szemantikai szabályt az egymásba skatulyázott blokkok értelmezésével kapcsolatban. Szükségesnek tartjuk ismételten hangsúlyozni, hogy a blokkstruktúra főként nagy volumenű feladatok programjaiban előnyös. Olyan feladatok esetén, amelyekre pl. egy matematikus - más programokból átvett részek felhasználása nélkül - elfogadható időn belül fel Ind programot írni, általában nincs értelme több hierarchikusan egymás fölé rendelt blokknak. Éppen ezért a gyakorlati ALGOL-programok jelentős részében a jelen pontban elmondott szemantikai szabályok nagy részét nem alkalmazzák. Egyszerű esetben az összes változót a program elején deklaráljuk. Ilyenkor az egész program egyetlen blokkból áll. Komplex feladatok programjainak megírásakor azonban az e fejezetben foglaltak hatékonyan alkalmazhatók.

4.3. Tömbdeklarációk
A tömbdeklarációk információkat tartalmaznak a fordítóprogram számára a tömb méretszámáról (dimenzió-számáról) és az egyes indexek értékhatárairól. Az indexek számának és értékhatárainak ismeretében a tömb elemeinek száma kiszámítható. A fordítóprogram a tömbdeklarációkból tudja meg, mekkora memóriateret kell fenntartania a célprogram indexes változói részére.
A tömbdeklarációk céljára bevezetünk egy újabb ALGOL-alapjelet: array. A tömbdeklaráció egy típusdeklaráló alapjellel (decimal, integer vagy string) kezdődik, majd következhet string és decimal típus esetében kerek zárójelben a mezőhosszúság (string-nél a karakterek -, decimal-nál a számjegyek száma). Ezt követi a most bevezetett array alapjel, majd a tömb azonosítója. Végül szögletes zárójelben az egyes indexekre vonatkozó értékhatárok következnek, listaszerű felsorolásban. A tömbdeklarációk megadási módját az alábbi sémával szemléltethetjük:

típus array M[A1:B1;A2:B2;...;An:Bn]

vagy

típus(N) array M[A1:B1;A2:B2;...;An:Bn]

Itt a tömb azonosítója M. N string típus esetén a tömbelemekben tárolható karakterek száma, decimal esetében a számjegyek száma. Ha N elmarad, alapértelmezés szerint a karakterfüzérek 10 karakter hosszúak lehetnek, a decimal típus 10 számhegyet tárolhat.
A1, B1, A2, B2, ..., An, Bn a legegyszerűbb esetben egész számok, általában azonban tetszőleges aritmetikai kifejezések.
A szögletes zárójelben álló listát korlátpár-listának nevezzük. Ez annyi elemet tartalmaz, ahány indexe az M tömbhöz tartozó indexes változóknak van. A korlátpár-lista elemei két-két aritmetikai kifejezésből állnak, melyek egymástól kettősponttal vannak elválasztva. A kettőspontoktól balra álló (A1, A2, ..., An) aritmetikai kifejezések a megfelelő index értékének alsó határát, a kettőspontoktól jobbra álló (B1, B2, ..., Bn) aritmetikai kifejezések pedig felső határát definiálják. Az indexek határainak számszerű értékét a korlát-pár listában szereplő aritmetikai kifejezések aktuális értéke határozza meg, ezért az indexhatárok számszerű értéke a program futása közben változhat. Ebben az értelemben az ALGOL-ban "dinamikus indexhatárokról" beszélünk. A tömbdeklarációt bevezető típusdeklaráló alapjel a tömb típusát definiálja (a tömbhöz tartozó valamennyi indexes változó azonos típusú).
Példák tömbdeklarációkra:

INTEGER ARRAY X[0:5,0:5]
DECIMAL(12) ARRAY X,Y[3:6,5:10]
STRING(127) ARRAY WORDS[Y+3:12]

Az indexhatárokat meghatározó aritmetikai kifejezésekről három szemantikai szabály rendelkezik:

  1. Ha egy indexhatárt definiáló aritmetikai kifejezés valós típusú eredményt állít elő, erről egész típusú eredményre ugyanúgy térünk át, mint az indexes változók indexének kiszámítása során, tehát az értékadó utasításoknál tárgyalt szabály szerint.
  2. A korlátpár-listában szereplő aritmetikai kifejezések mindegyikének értékkel kell bírnia, amikor a vezérlés a tömbdeklarációt tartalmazó blokk begin-jéhez érkezik. Ebből adódik a fontos szabály, hogy azokat a változókat, amelyek egy tömbdeklaráció aritmetikai kifejezéseiben szerepelnek, nem szabad ugyanebben a blokkban deklarálni, hanem okvetlenül magasabb rendű blokkban. Speciálisan egy teljes ALGOL-program legkülső blokkjában csakis olyan tömbdeklaráció szerepelhet, amelynek valamennyi indexhatára számkonstanssal van megadva. Teljes ALGOL-programnak ugyanis nem lehetnek globális változói.
  3. Az alsó indexhatárokat meghatározó aritmetikai kifejezéseknek nem szabad nagyobb aktuális értéket előállítaniuk, mint a felső határokat meghatározó kifejezéseknek, ellenkező esetben a tömbdeklaráció értelmetlen.

A tömbdeklarációkat, akárcsak a skaláris változók deklarációit és minden egyéb deklarációt, mindig valamely blokk fejében adjuk meg. Ha ugyanazon blokkfejben több azonos méretű és azonos indexkorlátokkal bíró tömböt kívánunk deklarálni, rövidített írásmóddal élhetünk: elegendő az indexkorlátokat csupán egyszer megadnunk, és ezt megelőzőén listaszerűen, egymástól vesszővel elválasztva, felsorolnunk azokat a tömbazonosítókat, amelyekre a közös indexhatárok vonatkoznak.
Tegyük fel például, hogy deklarálni kívánunk két n elemű vektort, és három n x m típusú mátrixot. A vektorok azonosítói legyenek u és v, a mátrixoké P, Q és R. Ekkor felírhatjuk a következő tömbdeklarációkat:

BEGIN
DECIMAL ARRAY U,V[1:n],P,Q,R[1:n,1:m];

Több tömb egyidejű deklarációja esetén elegendő az array alapjelet is csupán egyszer alkalmaznunk az egy csoportban megadott tömbdeklarációk előtt. Különböző típusú tömbök külön csoportban deklarálandók. Tegyük fel például, hogy valamely blokk fejében egy egész típusú vektort (I) és két valós típusú mátrixot kívánunk deklarálni. A megfelelő blokkfej a következőképpen írható fel:

BEGIN
INTEGER ARRAY I[1:n];
DECIMAL ARRAY A,B[i:k,i-1:k+1];

Az egy csoportban megadott tömbdeklarációk után pontosvessző következik, amely a csoport végét jelzi. Az azonos típusú tömböknek egy csoportban való deklarálása csak lehetőség, amelynek segítségével rövidíthetjük az ALGOL-programot, de alkalmazása nem kötelező; deklarálhatunk akár minden tömböt külön is.

4.4. A címkék hatásköre
A deklarált azonosítók hatáskörére vonatkozó szemantikai szabályokat az előzőekben - főként az 1. és 2-ban - már megismertük. A címkék szintén lehetnek azonosítók, sőt leggyakrabban azok (lásd 3. fejezet 3. pont), hatáskörükről mégis külön szemantikai szabályok rendelkeznek, minthogy nincs
Az alapvető szemantikai szabály a következő: minden címke lokális arra a legkisebb blokkra nézve, amelyik őt hatalmazza. Tekintsük például a következő programsémát:

begin
   {deklarációk};
   {utasítások};
B: begin
   {deklarációk;
   {utasítások};
P: {utasítás}; {utasítások} end;
   {utasítások}
end

A programséma két egymásba skatulyázott blokkból áll. A belső blokk, B, tartalmaz egy P címkével ellátott utasítást, tehát a P azonosító a B blokknak lokális azonosítója.
Ennek a szemantikai szabálynak néhány fontosabb következménye van. Először is, ha egy azonosítót, amely egy magasabb rendű blokkban deklarálva van (például egy skaláris változó azonosítója), címkeként használunk egy alacsonyabb rendű blokkban, ezzel de facto újradeklaráljuk, tehát a reá való hivatkozás esetén érvénybe lépnek az újradeklarálásra vonatkozó szemantikai szabályok. Ha például a címkeként használt azonosító egy magasabb rendű blokkban skaláris változó azonosítója volt, akkor ennek a változónak az aktuális értéke (ha volt neki) azalatt, míg a gép a címkét tartalmazó legkisebb blokkot hajtja végre, látens állapotba kerül, és csak akkor válik ismét hozzáférhetővé, ha ebből a blokkból már kikerült a vezérlés.
A címkék lokalitási szabályának másik folyománya az a már ismert szemantikai szabály, amely megtiltja kívülről a blokk belsejébe való vezérlésátadást. Egy ilyen vezérlésátadás ui. nem lenne egyéb, mint egy blokk lokális azonosítójára való hivatkozás a blokkon kívülről. Tudjuk, hogy ez bármiféle lokális azonosító esetén a nyelv szemantikai szabályaiba ütközik. Összetett utasítás belsejébe szabad go to utasítással beugrani.
Megtörténhet, hogy több hierarchiailag egymás fölé rendelt blokkban előfordul ugyanaz a címke. Ha egy go to utasítás erre a címkére hivatkozik, akkor a gép először megvizsgálja, hogy ugyanabban a blokkban előfordul-e ez a címke. Ha igen, a vezérlés erre a címkére adódik át. Ha a gép az azonos blokkban nem találja meg a rendeltetési címkét, megvizsgálja a következő legalacsonyabb hierarchiájú blokkot. Ha ebben megtalálja a keresett címkét, átadja rá a vezérlést, ha nem, ismét megvizsgálja a soron következő legalacsonyabb blokkot, stb. A go to utasítás végrehajtása közben a vezérlés nem kerülhet alacsonyabb hierarchiájú blokkba, mint amilyenben a go to utasítás van.
Példaképpen tekintsük a következő programsémát:

A: begin
   {deklarációk};
   {utasítások};
   P: {utasítás};
   B: begin
      {deklarációk};
      {utasítások};
      P: {utasítás};
      C: begin
         {deklarációk};
         go to P;
         {utasítások};
      end
   end
end

A program három egymás fölé rendelt blokkból áll. A legalacsonyabb hierarchiájú C blokkban van egy vezérlésátadó go to utasítás, melynek rendeltetési címkéje P. Ebben a blokkban nem található meg a rendeltetési címke. A gép tehát keresni kezdi az eggyel magasabb hierarchiájú B blokkban, és meg is találja. A vezérlés erre a B-beli P címkére adódik át, bár az A blokkban is van egy P címke.

4.5. Magyarázó megjegyzések a programban
A deklarációk, mint az előző fejezetekben láttuk, lényegében a programra vonatkozó felvilágosítások, melyek elsősorban nem a programot felhasználó szakembernek, hanem a fordítóprogramnak szólnak, és lehetővé teszik, hogy a fordítóprogram előállítsa a célprogramot. A programban való eligazodás érdekében azonban nagyon hasznos, ha tartalmaz olyan felvilágosításokat is, amelyek a fordítóprogram számára ugyan értéktelenek, viszont tájékoztatják a felhasználót a program működéséről, alkalmazásának módjáról, a felhasználás esetleges korlátairól és a programmal kapcsolatos egyéb tudnivalókról. Az ALGOL nyelv lehetőséget ad arra, hogy a programozó ezeket a felvilágosításokat szintaktikusan korrekt módon beépítse a programba, mégpedig oly módon, hogy a fordítóprogram figyelmen kívül hagyja ezeket.
A magyarázó szövegek kezdetének jelzésére külön alapjel van bevezetve, a comment amely begin és pontosvessző után alkalmazható. A magyarázatoknak a fordítóprogram által történő figyelmen kívül hagyását az a szemantikai szabály biztosítja, hogy a comment alapjeltől a legközelebbi pontosvesszőig minden megjegyzésnek számít. A comment alapjellel bevezetett kommentár nem tartalmazhatja a pontosvessző alapjelet.
Az Algol-M-ben nem szabványos módon is írhatunk megjegyzéseket: a százalékjelek (%) által határolt szöveget, a program bármely pontján megjegyzésnek tekinti a fordító.

5. Eljárások

5.1. Bevezetés
A számológép-programozás gyakorlatában sokszor igen hasznos, ha egyes programokat olyan módon írnak meg, hogy azok bizonyos értelemben zárt egészet alkossanak, Egy ilyen program ui. építőkocka-elemként beleépíthető egy nagyobb programba - esetleg több helyen is -, ha szükséges. Különösen két esetben célszerű a programok egyes részleteit "előregyártott elem" formájában kidolgozni:

  1. ha egy nagyobb programban ugyanaz az utasításcsoport több különböző helyen jelenne meg;
  2. ha a program valamely része bizonyos szempontból "közérdekű", azaz előreláthatólag ugyanezt a programrészt a későbbiekben más programok is fel tudják majd használni.

Az első esetben azért célszerű a kérdéses részprogram építőkockaszerű kidolgozása, mert ezáltal elkerülhető azonos utasításcsoportok ismételt leírása, és ezzel a program terjedelme csökken. Az ilyen építőkockát, amelyet a továbbiakban eljárásnak fogunk nevezni, az ALGOL-ban mindig egy blokk fejében definiálják (deklarálják), és a blokk belsejében csak hivatkoznak erre a definícióra. A programozási folyóiratok a számítási eljárásokat (algoritmusokat) mindig ilyen eljárás formában közölték, és ezeket csak bele kell másolni a megfelelő blokkba, ahol majd felhasználásra kerülnek.

Mi jellemző egy ilyen ALGOL-eljárásra?
Az ALGOL-eljárás nem egyéb, mint egy - megfelelő kísérő információval ellátott - program, amely meghatározott kiinduló információból meghatározott kimenő információt állít elő, mégpedig olyan módon, hogy a kiinduló információt mindig egy ALGOL-program adja meg az eljárás részére, és az eredmény további felhasználás céljából a gép rendelkezésére áll. Az eljárás sohasem teljes program, működtetéséhez mindig szükség van egy vezérlőprogramra, amely aktivizálja, azaz megadja részére a kiinduló információt, utasítást ad a végrehajtásra, és a végrehajtás után valamilyen módon felhasználja az eredményt. Az eljárás aktivizálását másképpen az eljárás behívásának nevezzük.
Eljárás lehet például egy olyan program, amely lineáris algebrai egyenletrendszereket old meg; kiinduló információ pedig az egyenletrendszer rendszáma, az együtthatómátrix és a jobb oldal; az eredmény a rendszer megoldása. Az előzőkben elmondottak szerint az együtthatómátrixot, a rendszámot és a jobb oldalt a vezérprogramnak kell "szállítania" az eljárás részére, az eljárás viszont "szállítja" a vezérprogram részére a megoldásokat, és ugyancsak a vezérprogramnak kell gondoskodnia ezek felhasználásáról. Ha a feladat olyan, hogy a számítás során többször kell lineáris egyenletrendszereket megoldani, akkor a vezérprogram többször is behívhatja ugyanazt az egyenletrendszer-megoldó eljárást.
Az eljárások alkalmazásának előnye az említett első esetben csupán a helytakarékosság, ami a célprogramban memóriatakarékossággal egyenértelmű. A második esetben azonban sokkal komolyabb jelentősége van: a programozónak nem kell tudnia, hogy az eljárás hogyan működik, elég, ha azt tudja, hogyan kell megadni a bemenő adatokat, és hogyan kapja meg az eredményt. (Természetesen ez csak akkor elegendő, ha a programozó kipróbált, hibátlan eljárást épít bele a programjába.) Előbbi példánknál maradva, egy lineáris egyenletrendszer-megoldó eljárás felhasználásához a programozónak nem kell tudnia, hogyan történik a Jordan-elimináció.
Az eljárások bevezetése rendkívüli módon megkönnyíti az irodalmilag publikált programok gyakorlati felhasználását, mert beépítésükhöz úgyszólván semmi előzetes átalakítást, átdolgozást, szerkesztési munkát stb. nem kell végezni, ha a felhasználó gépnek megszorításoktól eléggé mentes ALGOL-fordítója van.
E helyen szeretnénk az Olvasó figyelmét felhívni azokra a folyóiratokra, amelyek rendszeresen publikáltak ALGOL-eljárásokat. Ilyenek a Communications of the ACM (Association for Computing Machinery), a BIT (Nordisk Tidskrift for Informations Behandling), a Numerische Mathematik, a Journal of the ACM, stb. Az elmúlt évek alatt ezek a folyóiratok több száz algoritmust közöltek a legkülönbözőbb numerikus matematikai feladatokra, és a gyakrabban előforduló feladattípusokra csaknem mindig található ezek között megfelelő. Ennek folytán sok esetben egy feladat programozási munkája a megfelelő eljárás kiválasztására, a programba való bemásolására és alkalmas vezérprogram írására redukálódik.
Ebben a fejezetben az eljárásokkal kapcsolatos szintaktikus és szemantikai szabályokat tárgyaljuk, továbbá példákkal illusztráljuk az ALGOL-eljárások megadási módját és gyakorlati alkalmazásukat.

5.2. Eljárás deklaráció és eljárás utasítás
Említettük az első fejezetben, hogy az ALGOL-eljárásokat mindig egy blokk fejében definiálják, és az aktivizálás a blokk belsejében, az eljárásra való hivatkozással történik.
Minden eljárásnak azonosítója van, és a blokkfejben lényegében az azonosítót deklarálják. Az eljárás deklaráció egy különleges ALGOL-program, amely az eljárás azonosítójához rendelt algoritmus leírását tartalmazza.
Tudjuk az előzőkből, hogy az eljárás részére (csaknem) mindig meg kell adnunk valamilyen kiinduló információt, és az eljárás ennek felhasználásával előállít valamilyen kimenő információt. Az eljárás az őt aktivizáló programmal bizonyos azonosítókon keresztül tartja a kapcsolatot: a bemenő információ megadása lehet pl. értékadás bizonyos meghatározott változókra nézve, a kimenő információt pedig ugyancsak bizonyos meghatározott változóknak adja az eljárás. Azokat az azonosítókat, amelyeket arra a célra jelölünk ki, hogy rajtuk keresztül az eljárás kapcsolatot tartson az őt. behívó programmal, az eljárás paramétereinek nevezzük.
Az eljárás deklaráció a procedure alapjellel kezdődik (Kivétel a függvényt definiáló speciális eljárás, ld. 5.3. pont), ezt az eljárás azonosítója követi. Az eljárásazonosító után, kerek zárójelbe zárva, az eljárás formális paramétereinek listája áll, melyet egymástól vesszővel elválasztott azonosítók sorozata alkot. Mindezt egy pontosvessző követi. Alakja:

PROCEDURE eljárásnév(paraméter1, paraméter2, ..., paramétern);

Példa eljárásdeklaráció kezdetére:

procedure Gamma(x,y,z);

Itt Gamma az eljárás azonosítója, x, y, z pedig formális paraméterek. Megemlítjük, hogy a formális paraméterek listája bizonyos körülmények között hiányozhat, amire később példát is mutatunk majd.
Ezután az eljárásdeklaráció egy kísérő informatív résszel folytatódik, amely a fordítóprogram számára szükséges felvilágosításokat tartalmazza az eljárás formális paramétereire vonatkozólag. Bizonyos körülmények között ez a programrész is hiányozhat. Az eljárásdeklaráció e részét specifikációs résznek nevezzük.
A specifikációs részt követi az az ALGOL-program, amely leírja magát az algoritmust, amelyet az eljárás azonosítójához rendelünk. Ezt az ALGOL-programot az eljárás törzsének nevezzük. A procedure típusú bevezető jelsorozat és a specifikációs rész együttesen alkotja az eljárásfejet. Az eljárásdeklaráció tehát eljárásfejből és eljárástörzsből áll. Ez a felépítés némileg hasonló a blokkok szerkezetéhez. Egy eljárás törzse mindig egyetlen utasítás. Ha több utasításból áll, akkor ezeket utasítás-zárójelekkel egyetlen utasítássá kell összefogni. A gyakorlatban az eljárástörzs általában blokk; az ALGOL szintaktikus szabályai megengedik az eljárástörzset megnyitó begin után lokális azonosítók deklarálását.
Az eljárások az ún. eljárásutasítások segítségével aktivizálhatók. Az eljárásutasítás az aktivizálandó eljárás azonosítójából, és a bemenő információt közvetítő aktuális paraméterek listájából áll. A paraméterek érték szerint kerülnek átadásra, ezek értéke az eljárás végrehajtása közben nem változnak meg. Ez azt jelenti, hogy az eljárások nem adnak vissza értéket a hívási ponthoz, ezt csak globális változókon keresztül lehet elérni. A paraméterek számok, kifejezések, szövegfüzérek, vagy skaláris változók lehetnek, tömböket nem lehetett paraméterként átadni.
Példa:

PROCEDURE COMPARE(X,Y);
INTEGER X,Y;
BEGIN
  WRITE("The largest integer is ");
  IF X>Y THEN WRITE(X);
     ELSE WRITE(Y);
END;

Egy eljárásutasítás funkciója a következő:

  1. Közvetíti az eljárás részére a kiinduló információt;
  2. végrehajtatja az eljárástörzset;
  3. az eljárástörzs végrehajtása után vezérlésátadási hajtat végre az eljárást behívó program folytatására; ilyenkor általában - de nem okvetlenül - az eljárásutasítást a felírás sorrendjében követő utasítás kerül végrehajtásra.

5.3. Függvényeljárások
A 2. fejezet 5. pontjában említettük a standard függvények fogalmát. Ezek a matematikai analízis, valamint az elemi számelmélet leggyakrabban előforduló függvénykapcsolatai, melyek az ALGOL hivatkozási nyelv feltételezése szerint minden elektronikus számológép memóriájában - előre kidolgozott program formájában - tárolva vannak, és szükség esetén bármikor aktivizálhatók, tehát a fordítóprogram elő tudja hívni őket, ha standard azonosítójukkal találkozik a lefordítandó programban. Ez úgy értendő, hogy a fordítóprogram olyan utasításokat helyez el a célprogramban, amelyekre a gép memóriájának abból a részéből, amelyben a standard függvények előállítási programjai tárolnak, a megnevezett program átkerül azokba a memóriarekeszekbe, ahol a célprogram tárol, és (amennyiben szükséges) végrehajtódnak rajta azok az átalakítások, amelyek működtetéséhez szükségesek.
A standard függvények köre azonban igen szűk, ráadásul az ALGOL-M-ben nincsenek implementálva, így a gyakorlati programozásban gyakran felmerül a szükségessége függvények definiálására. Ezért nagyon kívánatos, hogy ALGOL-program segítségével definiálhatók legyenek nem standard függvények. Erre már csak azért is szükség van, mert az ALGOL-M-ben eljárásoknak csak érték szerint adhatunk át paramétereket, így a függvények nem adnak kimenő értéket. A matematikai képletíráshoz való közelítés szempontjából pedig kívánatos, hogy a speciális függvények, ha már egyszer definiálva vannak, ugyanúgy legyenek aktivizálhatók, mint a standard függvények.
A fenti követelmények kielégítésére vezették be az ALGOL-ban az ún. függvényeljárások fogalmát. A függvény-eljárások igen hasonlók a már megismert közönséges eljárásokhoz, a deklarálás alapjele a function. A függvény-eljárások alakja:

típus FUNCTION függvénynév{(paraméter1, paraméter2, ..., paramétern)};
típusdeklaráció;
utasítás;

Az eljárásoktól eltérően, a függvényeljárás azonosítójához minden egyes aktivizálás hozzárendel egy értéket, amelyet függvényértéknek nevezünk. A függvényeljárások deklarációjának legelső alapjele mindig egy típusdeklaráló alapjel (decimal, integer vagy string), amely meghatározza az eljárás aktivizálásakor keletkező érték típusát. Az utasítás összetett utasítás is lehet. Ahhoz, hogy az eljárás által definiált függvényérték meg legyen határozva, kell az függvénydeklarációban legalább egy (több is lehet) olyan értékadó utasítás, amelynek bal oldalán az eljárás saját azonosítója áll, és amely az eljárás aktivizálása során végre is hajtódik. Az az érték lesz a függvényérték, amelyet a legutoljára végrehajtott ilyen értékadó utasítás ad az eljárás azonosítójának. Ha egy függvénydeklaráció eleget tesz a fenti feltételeknek, akkor az eljárás aktivizálása teljesen a standard függvények analógiájára történhet, tehát az eljárás azonosítója után kerek zárójelben - egymástól vesszővel elválasztva - felsoroljuk az aktuális argumentumokat, és ezt az egész konstrukciót használhatjuk aritmetikai (logikai) kifejezések "alkatrészeként". A függvény-paraméterek - ha vannak - érték szerint kerülnek átadásra, lehetnek egész, valós vagy karakterlánc típusúak.
Példa a gyakran használt modulo, x és y osztásának egész maradékát adó függvényre:

INTEGER FUNCTION MOD(P,Q); INTEGER P,Q;
  MOD:=P-Q*(P/Q);

A függvénydeklaráció első alapjele az integer, amely meghatározza a függvényérték típusát. A függvénynek két paramétere van: P és Q). Az egyetlen értékadó utasításból álló eljárástörzs bal oldalán mod azonosítója áll, mégpedig az aktuális argumentumok nélkül. Jól jegyezzük meg: amikor az eljárás aktuális értékét meghatározó értékadó utasításokat írjuk, a megfelelő értékadó utasítás bal oldalán az eljárás azonosítója aktuális argumentumok nélkül áll. Ha a programban valahol definiáltuk a mod(x,y) függvényt, ezután már használhatjuk a mod azonosítót aritmetikai kifejezésekben.
A függvényeljárás azonosítója az aktuális argumentumok listájával együtt - ezt az együttest az ALGOL-ban függvénykifejezésnek nevezzük - korrekt aritmetikai kifejezés, és mint ilyen, megadható aktuális paraméterként olyan helyeken, ahol az ALGOL egyéb szabályai kifejezés-paramétereket megengednek.
Négyzetgyök vonásra az egyik legegyszerűbb és legelterjedtebb módszer a Newton-Raphson módszer. Ehhez rögtön az abszolút érték függvényt is elkészítjük:

DECIMAL FUNCTION ABS(X); DECIMAL X;
  ABS:=IF X<0 THEN -X ELSE X;

DECIMAL FUNCTION SQRT(X); DECIMAL X;
DECIMAL SQ,PSQ;
BEGIN
  SQ:=X/2.0; PSQ:=0.0;
  WHILE ABS(SQ-PSQ)>0.08 DO BEGIN
    PSQ:=SQ;
    SQ:=0.5*(SQ+X/SQ);
  END;
  SQRT:=SQ;
END;

Meg kell említenünk a függvények egy sajátságos tulajdonságát. Az úgynevezett mellékhatások lehetőségére fogunk rámutatni. Egy függvényeljárásról akkor mondjuk, hogy mellékhatása van, ha aktivizálása közben megváltoztatja olyan változók értékeit, amelyek abban a blokkban, amelyben a függvényeljárás deklarálva van, érvényes deklarációval rendelkeznek (ahogy ezt az eljárások is megtehetik). A mellékhatás oly módon jön létre, hogy az eljárástörzsben értékadás történik egy vagy több, az eljárástörzsre globális azonosítóra nézve.
A mellékhatások lehetőségével minden ALGOL fordítóprogram szerkesztésekor számolni kell. Éppen emiatt van egy sereg szintaktikus és szemantikai szabály, amelynek első pillanatban nem látszik az értelme. Ezek közé tartozik, - hogy csak a legfontosabbakat említsük - a szigorú balról jobbra szabály, amelyet az esetleg kényelmesebb vagy gazdaságosabb kódolás érdekében sem szabad megszegni; az értékadó utasítások szemantikájának az a szabálya, hogy a bal oldali változók indexkifejezései előbb számítandók ki, mint a jobb oldali kifejezés aktuális értéke, és magukra az indexkifejezések kiértékelésére is a balról jobbra szabály érvényes (mind az indexkifejezéseknek, mind a jobb oldali kifejezéseknek a kiértékelése produkálhat mellékhatást); a logikai kifejezések tárgyalása során kimondott azon szabály, mely szerint a kifejezés kiszámításában akkor sem szabad megállni, ha valamely részeredmény már eleve megszabja a végeredményt (pl. logikai szorzat első tényezője false stb.).
Sajnos, a mellékhatások lehetősége rendkívül megnehezíti az ALGOL fordítóprogramok által produkált célprogramok optimalizálását. A FORTRAN nyelv szerzői nem vállalják a felelősséget esetleges mellékhatások fellépéséért, és figyelmeztetik a programozót, hogy a fordítóprogram fenntartja magának a jogot az elemi algebra azonosságainak alkalmazására fordítás közben (kommutatív, asszociatív, disztributív törvény). Tehát a FORTRAN-programokban a programozónak kell ügyelnie arra, hogy ne írjon olyan programot, amelynek végrehajtásában nemkívánatos hatások lépnek fel. Ez a megkötés lehetővé teszi viszont a célprogramok optimalizálását, ismétlődő részkifejezések fel ismerését, és az ismételt számolás elkerülését, indexkifejezéseknek cikluson kívüli számolását stb. Mindez az ALGOL-ban (egyébként nem kizárólag a mellékhatások lehetősége miatt) nagyon nehézkes, ami kétségkívül egyik oka annak, hogy egyesek idegenkednek az ALGOL gyakorlati alkalmazásától.

5.4. Rekurzív eljárások és rekurzív függvénybehívások
Láttuk az előző fejezetekben, hogy az eljárások és függvények egymást is aktivizálhatják, mégpedig akár a függvény végrehajtása közben, akár az eljárás aktuális paramétereinek kiértékelése közben. Az is megengedett, hogy egy függvény törzse az függvénytörzsre nézve globális függvényeket aktivizáljon. Mindenesetre látszik, hogy egy függvény működése közben igen sokféle módon kerülhetnek aktivizálásra más eljárások, sok esetben aktivizálások egész láncolata jön létre.
Az ALGOL szintaktikus és szemantikai szabályai azt is megengedik, hogy egy függvény önmagát hívja be. Ilyen esetben azt mondjuk, hogy az eljárás rekurzíve aktivizálódott. A. rekurzív aktivizálásnak két alapesetét különböztetjük meg, mindkettőn belül további 2-2 aleset lehetséges. A két alapeset a következő:

  1. Valamely eljárás utasításban az aktuális paraméterek listáján az aktivizálandó eljárás azonosítója szerepel;
  2. valamely eljárás az eljárástörzs végrehajtása közben - közvetlenül vagy közvetve - önmagát hívja be.

Az első esetben rekurzív eljárásbehívásról, a másodikban vagy rekurzív eljárásról, vagy szimultán rekurzív eljárásrendszerről beszélünk, aszerint, hogy az eljárás közvetlenül vagy közvetve hívja-e be önmagát. A rekurzív behívás első és egyszerűbb alapesetével akkor állunk szemben, ha az eljárás valamelyik érték szerint behívott formális paraméterére olyan aktuális paraméterkifejezés, amelynek kiszámításához magának a függvényeljárásnak az aktivizálása szükséges.
A rekurzív eljárásbehívás második alapesete áll fenn, ha egy eljárás név szerint behívott formális paraméterének helyén aktuális paraméterként saját magát az eljárási adjuk meg. A rekurzív függvények fogalmát az irodalomban - szinte hagyományosan - a faktoriális függvény kiszámításának programján szokták megmagyarázni.
A faktoriális függvényre a következő rekurzív definíció adható meg:

n! = 1, ha n=0
n*(n-1)!, ha n>0

(n pozitív egész szám). Ez szinte változtatás nélkül átírható ALGOL-programmá:

DECIMAL FUNCTION FAC(N); INTEGER N;
  FAC:=IF N=0 THEN 1. ELSE FAC(N-1)*N;

Formálisan könnyű látni, hogy a függvénydeklaráció valóban a matematikai definíció ALGOL átírása, azonban fel szokott merülni a kérdés, hogy valójában mi történik a gépben egy ilyen eljárás aktivizálása során, hogyan "dolgozik" egy rekurzív eljárás?
A kérdésre megpróbálunk egy olyan példa alapján választ adni, amely nem az ALGOL-terminológián alapul, hanem teljesen hétköznapi fogalmakkal dolgozik. Képzeljünk el egy sokemeletes iroda-toronyházat, melynek minden emelete azonos beosztású, minden emeleten van egy sereg (só)hivatalszoba, és minden szobában ül egy hivatalnok, aki utasításokat ad a hozzá forduló ügyfeleknek. Az utasítások a következők lehetnek:

  1. "Menjen ugyanezen az emeleten a ... számú szobába!"
  2. "Menjen az emelet kijáratához!"
  3. "Menjen a fölöttünk levő emelet első szobájába, és ha a fölöttünk levő emeleten végzett, jöjjön ide vissza!"
  4. Ezenkívül a hivatalnok intézhet valamit az ügyfél iratain, és utasítás nélkül továbbengedheti, amely esetben az automatikusan a következő szobában ülő hivatalnokhoz megy.

A hivatalnokoknak nincs joguk az ügyfelet sem alacsonyabb emeleten fekvő szobába küldeni, sem pedig olyanba, amelyik két vagy annál több emelettel van magasabban: sőt az eggyel magasabb emeleten fekvő szobák közül is mindig csak az elsőbe küldhetik, és az onnan megy majd esetleg az emelet további szobáiba. A 2. számú utasítás hatására, ha egy földszinten ülő hivatalnok adta, az ügyfél befejezte látogatását a hivatalban és távozik; ügye elintézettnek tekintendő. Ha ezzel szemben ugyanezt az utasítást egy emeleti hivatalszobában kapja, akkor ez azt jelenti, hogy visszatér az eggyel alacsonyabb számú emeletre ahhoz a hivatalnokhoz, aki legutoljára küldte egy emelettel feljebb, és ott újabb utasítást kap.
Az ügyfél célja, hogy véges idő alatt elintézze ügyét a hivatalban. Ha ügye olyan, hogy az a hivatal fenti rend tartása mellett elintézhető, akkor véges sok szoba felkeresése után eljut egy olyan földszinti szobához, amelyben elhangzik a "Menjen az emelet kijáratához" utasítás, véget vet a szobák közti bolyongásnak. Ha ellenben az ügy nem intézhető el az adott rendtartás mellett, akkor az ügyfél a végtelenségig bolyong a szobák között, és soha többé nem jön ki a hivatal kapuján. A legegyszerűbb ügyek a földszinten intéződnek, és ilyenkor az ügyfélnek nem kell lépcsőt járnia. Bonyolult ügyek esetén az ügyfelet magad emeletekre is felküldik az ügyintézés során.
A közönséges, nem rekurzív eljárás olyan "hivatal" ahol mindent elintéznek a földszinten. Rekurzív eljárás esetén lehetőség van a vezérlést arra utasítani, hogy eggyel magasabb szinten járja végig még egyszer a program törzsét; itt esetleg ismét még eggyel magasabb szintre kerül a vezérlés, és így tovább. Rekurzív eljárás végrehajtása közben a gép nyilvántartja, hogy éppen hányadik szinten tartózkodik, és az eljárástörzset bezáró end elérése csak akkor jelenti a számára a főprogramra való visszatérést, ha egyidejűleg a szintszámláló nullán áll. Ellenkező esetben az end elérése után a gép tudja, hogy nem az egész eljárással végzett, hanem annak csupán egy szintjével, megfelelően az előző példánkban annak az esetnek, amikor az ügyfél nem a földszinten kap "Menjen a kijárathoz" utasítást. Az ALGOL megengedi az eljárásoknak tetszőleges magas szinten való aktivizálását, de a rekurzív hívásnak értelmesnek kell lennie, azaz lehetővé kell tennie a gép számára, hogy véges sok lépésben kijusson az eljárásból, ellenkező esetben kijárat nélküli, végtelen rekurzió lép fel. Ez történik pl. abban az esetben, ha az előbb bemutatott FAC algoritmust negatív argumentummal hívják be. Ezen a problémán itt segít, ha a függvény befejezésének feltételét módosítjuk: IF N<2.

A numerikus analízis legtöbb számítási algoritmusa ugyan rekurzív módon van adva, a gyakorlatban azonban a rekurzív algoritmust ciklikus programmá írjuk át. Messze vezetne annak taglalása, hogy ez mikor lehetséges, de a numerikus analízis és az ALGOL egyéb tipikus felhasználási területein általában sikerül, és ilyenkor a kényelmesebb programozás és a gyorsabb számolási idő érdekében ciklusos programmal és nem rekurzív eljárással számolunk. Például a faktoriális függvényt is célszerűbb egy közönséges for ciklus segítségével előállítani:

DECIMAL FUNCTION FAC(N); INTEGER N;
INTEGER I;
DECIMAL F;
BEGIN
  F:=1.;
  FOR I:=2 STEP 1 UNTIL N DO
    F:=F*I;
  FAC:=F;
END;

Ez a második eljárás a számítógép-programozás gondolatköréhez szokott szakember számára sokkal természetesebb, mint a rekurzív felfogás, és nyilván a faktoriális kiszámítását, mindenki így, és nem rekurzív eljárással programozná. A programozó a rekurzív formulát - ha tudja - mindjárt fejben átfogalmazza ciklikus algoritmussá. Azonban van olyan eset, amikor az egyedüli lehetőség rekurzív algoritmusok alkalmazása. Ilyen például a különböző fordító-programok megírása, amelyben kiterjedten alkalmaznak rekurzív programokat. Csakhogy ezek általában éppen nem ALGOL-ban íródnak, ezért az ALGOL-on belül ritkán merül fel rekurzív eljárások alkalmazásának szükségessége.
Hasonlóan ritkán, vagy még ritkábban merül fel a re kurzív aktivizálás negyedik alapesetének, az ún. szimultán rekurzív eljárásrendszerek alkalmazásának szükségessége, Szimultán rekurzív eljárásrendszerről akkor beszélünk, ha két eljárás - mondjuk A és B - kölcsönösen behívják egymást; pl. A aktivizálása esetén behívja B-t, majd B "visszahívja" A-t, és ez ismét B-t, s így tovább. Előbbi példánkat könnyű átfogalmazni erre az esetre - vagy akár N számú eljárásból álló szimultán rekurzív eljárásrendszer esetére - is.

Annak érdekében, hogy a különböző azonosító típusok között valamelyes rendet teremtsünk, összefoglaljuk, hogy milyenfajta azonosítók fordulhatnak elő az eljárások törzsében.

  1. Lokális azonosítók: semmiféle kapcsolatuk nincs az eljárást aktivizáló programmal, érvényük, hatáskörük csak az eljárástörzsre terjed ki, az eljáráson kívülről semmilyen módon nem hozzáférhetők.
  2. Érték szerint hívott formális paraméterek. Sok tekintetben hasonlóan viselkednek az eljárástörzs lokális azonosítóihoz, de definíciószerűen az eljárástörzset körülvevő azon fiktív blokkban tekintendők lokálisnak, amely magában foglalja a reájuk vonatkozó ugyancsak fiktív értékadó utasításokat is. Következésképpen egyirányú kapcsolatban állnak az eljárást aktivizáló programmal; ez megadja kezdeti értéküket, de ezután függetlenné válnak a behívó programtól, és teljesen úgy viselkednek, mint a lokális változók. Az eljárástörzs végrehajtása után végértékük hozzáférhetetlen a behívó program számára.
  3. Globális azonosítók. A behívó programmal való kétoldalú kapcsolat fenntartása céljából alkalmazhatunk az eljárástörzsre nézve globális változókat is, amelyek lehetnek akár globálisak, akár lokálisak arra a blokkra nézve, amelyben az eljárás maga deklarálva van. Függvényeljárások esetében azonban globális változókra való értékadás az eljárástörzs végrehajtása közben nehezen áttekinthető mellékhatásokra vezethet, és "közérdekű" eljárásokban globális azonosítók alkalmazása nem célszerű.
  4. Az eljárás saját azonosítója:
    a) Függvényeljárás esetében az eljárás saját azonosítójának legalább egyszer kötelezően elő kell fordulnia egy értékadó utasítás bal oldalán aktuális paraméterlista nélkül. Az ilyen értékadó utasítás a függvényeljárás segítségével meghatározandó függvényérték definiálására szolgál; a keletkező függvényérték típusát az eljárásdeklarációt bevezető típusdeklaráló alapjel (decimal, integer, string) határozza meg.
    b) Az a) alatti esetet kivéve, minden olyan helyen, ahol az eljárástörzsben előfordul az eljárás azonosítója, az eljárás rekurzíve aktivizálódik. Magától értetődik, hogy rekurzív aktivizálás esetén az eljárás azonosítójának aktuális paraméterlistával együtt kell állnia, és az aktuális paraméterlistának ki kell elégítenie az eljárások behívásával kapcsolatos ismert szabályokat.

6. A perifériális egységekre hivatkozó I/O utasítások

6.1.Bevezetés
Az előző fejezetekben többször hangsúlyoztuk, hogy a gyakorlatban egy teljes ALGOL-program tartalmaz olyan utasításokat, amelyek végrehajtása közben a gép kiinduló információkat vesz fel a bemeneti egységen keresztül, és olyanokat, amelyek hatására közli a programozóval a számítás eredményeit. A gép a külvilággal a be- és kimeneti (I/O) egységeken keresztül tartja a kapcsolatot; ezeket közös néven perifériális egységeknek nevezzük. A perifériális egység fogalomkörbe azonban nemcsak a billentyűzet és monitor / sornyomtató egységek tartoznak, hanem az összes olyan egység is, amely közvetlenül nem vesz részt a számításban, hanem csak adatokat tárol, vesz fel, vagy közöl. Nem tartozik a perifériális egységek közé a központi memória, mert a gép működése közben közvetlenül részt vesz a számításban, ezzel szemben a különböző háttértárakat (esetünkben mágneslemez) már ide számítjuk.
A perifériális egységek terén mutatkozó nagy eltérések miatt az ALGOL 60 szerzői úgy döntöttek, hogy nem definiálnak szabványos utasításokat a ki- és bevitel, valamint az egyéb perifériákra való hivatkozás céljaira. Az ALGOL nyelv hivatalos definiálása óta eltelt időben igen nagy számú - többé-kevésbé teljes, részben korlátozott - ALGOL gépi reprezentáns keletkezett, ami azzal járt, hogy nagymértékben megszaporodott a merőben különböző ki- és beviteli rendszerek száma. Ez erősen akadályozza az ALGOL általános felhasználását, mely ebben a tekintetben hátrányban van pl. a FORTRAN-nal szemben, amelynek lényegében egységes ki- és beviteli rendszere van.
Az elektronikus számítógépek programozási rendszereiben a perifériákkal kapcsolatos operációkat két nagy csoportba sorolhatjuk. Az elsőbe tartoznak azok az utasítások, amelyek az effektív adatcserét végeztetik a géppel (kiírás, beolvasás, mágneslemezes műveletek), míg a második csoport utasításai nem hajtanak végre semmit, csupán az adatcserében részt vevő egységeket jelölik ki, jelsorozatok (nem okvetlenül számok!) formájának, hosszának, jellegének meghatározására, definiálására szolgálnak.

6.2. A READ és WRITE utasítások
Az ALGOL-M-ben az effektív adatcserét végző utasítások a WRITE (kiírás) és READ (olvasás).
Ahhoz, hogy egy számítás eredményét jól áttekinthető formában kapjuk, és hogy a kezelő a számítás pillanatnyi helyzetét figyelemmel kísérhesse, szükséges, hogy a gép képes legyen a számítás eredményei mellett szövegeket is kinyomtatni; ezek szolgálhatnak például egy számtáblázat fejléceként, vagy riasztó jelzést adhatnak valamely előre nem látott helyzetről. A WRITE eljárás képernyőre, vagy file-ba ír, a megadott paraméterek függvényében. Az eljárás legegyszerűbb esetben zárójelben felsorolt paramétereket egymás után, sorfolytonosan megjeleníti a képernyőn az aktuális kurzorpozíciótól kezdve. A paramétereket zárojelben, vesszővel elválasztva kell felsorolni, amik lehetnek: kifejezések, változók, karakterfüzérek, vagy TAB függvény. A WRITE eljárás a kiírást új sorban kezdi, míg a WRITEON a kurzor aktuális pozíciójától folytatja a kiírást.
Az ALGOL-ból ismert PIC vagy FORMAT utasítás nincs implementálva - nagyobb mennyiségű numerikus adat táblázatos megjelenítése közel lehetetlen -, a kiírás formázására az egyetlen lehetőség a TAB függvény, ami a kurzor aktuálkis pozíciójától a megadott kifejezésnek megfelelő számú szóköz karakterrel viszi jobbra a kurzort. A TAB paraméterét nem kell zárójelbe tenni. Az INTEGER típusú értékek kiírása mindig 6 karakteren történik: egy karakter előjel (pozitív előjel helyett szóközt ír) és öt számjegy (vezető nullák helyett szintén szóközt ír). A DECIMAL és STRING típusú értékek kiírásához csak az érték megjelenítéséhez szükséges karakterpozíciók kerülnek felhasználásra.

Példák:

WRITE(TAB 5,"Row",TAB 11,"Column",TAB 10,"Page");

WRITE(I,TAB 8,J,TAB 8,K,TAB 5,THREE[I,J,K]);

A WRITE eljárás paraméter nélkül nem használható ha csak új sort akarunk kezdeni, akkor is legalább egy üres string-et meg kell adni: WRITE("")
A READ utasítás egyszerre egy vagy több változót olvas be, alapeset szerint a billentyűzetről:

WRITE("Input test value: "); READ(INPUT);

Az utasítás a következő sor elején egy "->" jelet ír ki, és várja az adatok megadását. A beírt adatot csak akkor fogadja el, ha a READ utasításban megadott változó(k) típusának megfelelő. Ha nem, figyelmeztető üzenet kijezése után újra kéri az adatok beadását. DECIMAL típusú értékek bevitelekor a tizedespontot is meg kell adni, egész számok esetében is (lásd 2.2 pont)!

6.3. File-műveletek
Az ALGOL-M programok adatokat olvashatnak vagy írhatnak - szekvenciálisan - egy vagy több megnyitott file-ból, amelyek tetszőleges meghajtóban lehetnek. Ebben az estben a READ vagy WRITE utasítás után egy file-név azonosítót kell paraméterként megadni, ami jelzi, hogy a kiírás nem képernyőre, a beolvasás nem terminálról (billentyűzetről) következik. Az irás- olvasás műveleteket meg kell előznie a FILE deklarációnak (a deklarációs részben). Példa a file-ba írás menetére:

1. File azonosító létrehozása. (A példában a file-azonosító neve FNAME.)

FILE FNAME;

2. A megadott file-azonosítóhoz hozzá kell rendelni egy fizikai állományt (a file megnyitása). A file-névben a lemezmeghajtó betűjele is megadható.

FNAME:="list.txt";

3. Egy rekord kiírása a megnyitott file-ba:

WRITE FNAME (NAME[I],YEAR[I]);

A file akkor kerül lezárásra, ha véget ér a blokk futása, amiben a file-azonosítót létrehoztuk. Valamennyi file bezáródik a program futásának befejezésekor is.
Egy rekord beolvasása az 1-2 pontban bemutatott előkészületek után a READ utasítással lehetséges. Pl.:

READ FNAME (NAME[(I)],YEAR[I]);

Ha olvasáskor elértük a file végét, egy újabb olvasási kísérlet EOF figyelmeztetést küld, de a programfutás nem áll le. Felmerül a kérdés, honnan tudjuk, mikor érünk a file-végére, azaz meddig lehet olvasni egy file-ból? Elvileg READ-nál megadható az ONENDFILE foglalt szó, ami azt mondaná meg, file-vége jelnél melyik eljárást kell meghívni, ami lekezelhetné a EOF-t. Gyakorlatilag ez sajnos nem működik, így marad az a megoldás, ha kiírásnál file-ba előre beírjuk a kiírandó rekordok számát. Pl.:

PROCEDURE SAVEDATA(X); INTEGER X;
BEGIN
FILE FNAME;
INTEGER I;
  FNAME:="LIST.TXT";
  WRITE FNAME (X);
  FOR I:=1 STEP 1 UNTIL X DO
    WRITE FNAME (NAME[I],YEAR[I]);
END;

A betöltést célszerű függvényként megvalósítani, hogy azonnal visszaadja a betöltött rekordok darabszámát:

INTEGER FUNCTION LOAD;
BEGIN
FILE FNAME;
INTEGER I,X;
  FNAME:="LIST.TXT";
  READ FNAME(X);
  FOR I:=1 STEP 1 UNTIL X DO
    READ FNAME (NEV[(I)],EV[I]);
  LOAD:=X;
END;

File azonosító létrehozásakor megadhatunk fix rekordhosszúságot is (ez szöveges adatok tárolásakor lehet hasznos), ha zárójelben megadjuk a rekord hosszát:

FILE(rekordhossz) azonosító

7. A program fordítása, futtatása
A programcsomag szövegszerkesztőt nem tartalmaz, a forrásnyelvi program megszerkesztésére tetszőleges szövegszerkesztő használható. A program futtatásának előkészületeként le kell azt fordítani a

ALGOLM filenév

A forrásnyelvi programok alapértelmezett .ALG kiterjesztését nem kell megadni. A sikeres fordítás eredményeként .AIN kiterjesztésű file jön létre. Ez önmagában nem futtatható, csak a könyvtári rutinokat tartalmazó interpreterrel:

RUNALG filenév

Az alapértelmezett .AIN kiterjesztés itt is lehagyható. A program futtatása a STOP billentyűvel megszakítható.
A lefordított program háromszor-ötször gyorsabban fut a Standard BASIC-nél.
Hiba észlelésekor a fordító kiírja a hiba előfordulásának a helyét (a sor számának megadásával) valamint egy kétkarakteres hibakódot). A fordítási kísérlet azonban nem áll le az első hiba észlelésekor, így egy hiba több hibakódot is generálhat (a sor sorszáma ilyenkor már hibás), sőt előfordulhat, hogy a fordítási kísérlet végtelen ciklusba kerül és csak a STOP billentyűvel szakítható meg.

7.1 Hibakódok
Alább a dokumentáció szerinti hibakódok szerepelnek. Ettől eltérő hibakódokat is ki leht csiholni a gépből...

Fordítás közben előforduló hibák:

AS Function/Procedure on left hand side of assignment statement.
BP Incorrect bound pair subtype (must be integer).
DE Disk error; no corrective action can be taken in the program.
DD Doubly declared identifier/ label/ variable etc.
IC Invalid special character.
ID Subtypes incompatible (decimal values can not be assigned to integer variables).
IO Integer overflow.
IT Identifier is not declared as a simple variable or function.
NG No ALG file found.
NI Subtype is not integer.
NP No applicable production exists.
NS Subtype is not string.
PC Undeclared parameter.
SO Stack overflow.
SI Array subscrict is not of subtype integer.
TD Subtype has to be integer or decimal.
TM Subtypes do not match or are incompatible.
TO Symbol table overflow.
TS Undeclared subscripted variable.
UD Undeclared identifier.
UF Undeclared file/function.
UP Undeclared procedure.
VO Varc table overflow. Possibly caused by too many long identifiers.

Programfutás közben előforduló hibák:

AB Array subscrict out of bounds.
AZ Attempt to allocate null decimal or string default to 10 digits/characters.
CE Disk file close error.
DC Disk file create error.
DW Disk file write error.
DZ Division by zero, result set to 1.0.
EF Disk end of file, no action specified.
IO Integer overflow.
NI No INT file found on directory.
OV Overflow during decimal multiply.
RE Attemot to read past end of record on blocked file.
RU Attempt to random access a non-blocked file.
SL Significant digits lost during decimal store, value set to 1.0.

Programfutás közben előforduló figyelmeztetések:

II Invalid Console Input
IL Non-significant digit lost during decimal store.
SO Characters lost during string store.

Vissza