Az RPG programozási nyelv

Nyelvi elemek

Amint azt a bevezetőben említettük, a nyelv a ezen a téren is szokatlan tulajdonságokkal rendelkezik. A lyukkártyák hagyományát az RPG szintaktikája a mai napig őrzi, amennyiben szigorúan meg van határozva, hogy mit pontosan hova (sortípus, oszlop) írhatunk. (A programozó munkáját a SEU editor sorvezetők megjelenítésével ill. szintaktikai ellenőrzéssel könnyíti.) Minden sor elején meghatározzuk, hogy az aktuális sor milyen kártyának felel meg, majd az aktuális kártya pozícióbeosztásának megfelelően töltjük ki a sor további részét. A konkrét pozíciók a nyelv fejlődésével sokat változtak mindegyik kártyatípusnál. Megjegyezzük, hogy a nyelv legújabb változatában a C kártyák esetén lehetőség van bizonyos megszorításokkal a szabadon indentálhatóságra, más kérdés, hogy a tipikus RPG-programozó fog-e élni ezzel a lehetőséggel...

Jelkészlet

Azonosítók

Az azonosítónevekre a szokásos szabályok vonatkoznak (alfabetikus karakterrel (+ $ # @) kezdődhetnek, alfanumerikussal folytatódhatnak (+ _), nem lehetnek foglalt szavak, és max 4096 karakter hosszúak lehetnek. (A 15 karakternél hosszabb azonosítók csak folytatósorokba férnek bele.) Érdekesség, hogy tömbnevek nem kezdődhetnek a TAB karaktersorozattal.

Literálok

A nyelv sajátosságai

File-ok

Ahhoz, hogy megértsük az RPG nyelvi elemeit, először meg kell ismerkednünk a nyelvben (ill. az OS/400-ban) a file-okkal kapcsolatos alapfogalmakkal. Mindenekelőtt tudni kell, hogy az OS/400 rekordszinten végez minden I/O műveletet, ill. azt, hogy a DB/2 adatbáziskezelőrendszer olyan mélyen van integrálva a rendszerbe, hogy az OS/400 ún. adatbásisfájljai egyben adatbázistáblák is (ennek megfelelően akár SQL-en keresztül is feldolgozhatók, létrehozhatók, stb.). Továbbá file-ok létrehozásakor meg kell adnunk a file rekordszerkezetét (vagy az SQL create table paramétereiként, vagy a hagyományos interface-en keresztül az erre kitalált DDS rekordszerkezetleíró nyelv segítségével), és -- mivel az OS/400 nagymértékben objektumközpontú rendszer -- a file-ok mint *FILE típusú objektumok később is tudják a saját szerkezetüket, és ez le is kérdezhető. Végül fontos megemlíteni azt is, hogy az AS/400-ak hagyományos termináljaival (az ún. 5250-es terminálokkal) a rendszer teljes képernyős interface-eken keresztül kommunikál, ami által egy képernyő szintén tekinthető egy -- input és output mezőkből álló -- rekordszerkezetnek (sőt a képernyők megtervezésére ugyanazt a DDS-t használhatjuk, amit az adatbázistáblák rekordszerkezetének meghatározására). Ennek megfelelően az OS/400 alatt futó programok a képernyőket ugyanolyan FILE-ként kezelik, mint a fizikai fájlokat: amit a user beír, azt input mezőként látjuk abban a rekordban, amit akkor kapunk meg, ha a felhasználó leütötte az Entert (vagy valamilyen funkcióbillentyűt), amit pedig kiírunk (vagy nyomtató esetében kinyomtatunk), azt pedig output mezőként küldjük ki a képernyőre (nyomtatóra).

A fentieknek megfelelően az RPG megkülönböztet program-described ill. externally-described file-okat. Előbbieknél, mikor egy file-t bemutatunk az RPG-nek, akkor a nyelv adatdefiníciós eszközeivel le kell írnunk az adatszerkezetét. Viszont -- mivel az OS/400 file-jai pontosan tudják saját rekordszerkezetüket -- ezt a leírást megspórolhatjuk (sőt a redundancia megszüntetésével elkerülhetjük a figyelmetlen változtatásokkal könnyen előidézhető konzisztencia borulását, és az ebből származó hibalehetőségeket). Elég egyszerűen azt mondani az RPG-nek, hogy a file externally-described, és akkor a fordító a file rekordszerkezete alapján automatikusan legenerálja helyettünk a vonatkozó definíciókat. (Emiatt a file-nak nyilván már fordítási időben léteznie kell, ha externally-describednak adjuk meg.

Az adatáramlás iránya szempontjából egy file lehet:

Alapvető szempont, hogy egy file-ból a rekordokat milyen sorrendben kívánjuk feldolgozni (access path). Ahogy a COBOL-ban a programozónak 3 lehetőség közül kell választania egy file definiálásakor: szekvenciálisan, relatív rekord sorszám szerint, ill. kulcsmező segítségével dolgozza fel a fájlt; az RPG-ben is hasonló módokon kezelhetjük file-jainkat. (Ezekről szintén a megfelelő input specifikációban kell nyilatkoznunk.) Az, hogy a file-unkat milyen szervezésűnek és elérésűnek definiáljuk, a használható műveleteket is meghatározza. Az opciók:

A felhasználás szempontjából egy file lehet:

Az RPG programciklus

Az RPG tökéletesen támogatja a szekvenciális feldolgozást. Ez a feldolgozás rekordonkénti feldolgozás, mely egy-egy input rekord beolvasásából, annak feldolgozásából, majd szükség szerinti output rekorrdok kiiratásából áll. Nem szükséges a feldolgozás minden lépését programoznunk, mert a minden rekordnál ismétlődő mechanikus lépéseket az RPG maga elvégzi.

Ez a ciklikus vezérlés csak első látásra tűnik szokatlannak: hasonló elven működnek az ismert unixos filterek (sed, awk, stb.) is.

Az RPG program végrehajtásának menete (nem túl bonyolult RPG ciklus):

1. Fejléc - detail output
2. Rekord olvasás (a primary file-ból, ez a file irányítja a feldolgozás menetét)
3. Ha "End of file", akkor vége
4. Rekordváltozók törlése
5. Kalkuláció elvégzése (C kártyák)
6. Ismételd az 1. ponttól

Mivel ennek az implicit programciklusnak a pontos ismerete alapvető és nélkülözhetetlen az RPG nyelven írt programok megértéséhez, ill. írásához, a fentiek részletezésre (és pontosításra) szorulnak (a 47 pontból álló, teljes részletességű lépéssorozat közlésére itt nem vállalkozhatunk, megtalálható a nyelv refernciájában):

  1. Az első lépésben az RPG feldolgozza az output specifikációk fejléc és részletszámítás-kiírási(detail) sorait (magyarul kiírja a fejlécet, és a részletszámításokhoz rendelt kimenetet). Fetch overflow logic használata esetén (lásd alább), ha a lapváltás (overflow) indikátor be van kapcsolva, akkor az RPG kiírja a vonatkozó lapváltáshoz kapcsolódó sorokat.
  2. Majd beolvassa a következő rekordot, de nem szükségszerűen a primary file-ból, hanem esetleg valamelyik secondary file-ból. (Azt, hogy melyikből, pl. a match field (lásd fentebb) dönti el.) Ha az előző feldolgozott rekordban meg voltak adva előreolvasó(lookahead) mezők, akkor a rekord már a tárvan van, nem történik olvasás. Az RPG megállapítja a beolvasott rekord szerkezetét, és hogy a beolvasott rekord megfelel-e a programban megadott szerkezetnek. Ha nem, akkor a kivételkezelő rutinok kapják a vezérlést (lásd a kivételkezelés résznél).
  3. Ezután az RPG elvégzi az összesítő (total) számításokat, ezeket a control level indikátorokkal befolyásolhatjuk (lásd alább). A számítások elvégzése kifejezés alatt azt értjük, hogy a C kártyákon megadott utasítások (op-code-ok) közül végezzük el azokat, amelyeket összesítő számításnak specifikáltunk.
  4. feldolgozza az összesítő kiírásokat (az output sepcifikációk total output sorait). Megvizsgálja a lapváltó indikátorokat, és ha be van valamelyik kapcsolva, akkor a lapváltó rutinra kerül a vezérlés.
  5. megvizsgálja az LR indikátort (lásd lejjebb). Ha bekapcsolt, akkor kilép.
  6. A kiválasztott input rekordok mezői a feldolgozási területre másolódnak, és az RPG bekapcsolja a mező indikátortokat.
  7. az RPG elvégzi a részletszámításokat (azokat, amelyeket nem jelöltünk a control level indikátorokkal). Ez -- hasonlóan a total számítások elvégzéséhez -- a megfelelő C kártyákon található utasítások elvégzését jelenti. A 2. pontban beolvasott rekord adatait használja ehhez.
  8. elölről

Az első és az utolsó ciklus a fentiektől egy kicsit különbözik:

Az első ciklus

  1. feldolgozza a paramétereket, megnyitja a file-okat, inicializálja az adatokat,
  2. kiírja az 1P (first page) indikátorral jelzett rekordokat (az első rekord beolvasása előtt kiírhatunk konstans-jellegű információkat, mint a dátum, vagy az oldalszám).

A programozónak lehetősége van megadni (és megírni) egy inicializációs szubrutint, amelyet a first page (1P) kiírás előtt hajtja végre az RPG.

Az utolsó ciklusban, ha nincs több beolvasandó rekord, a program bekapcsolja az LR és az L1-L9 indikátorokat, elvégzi az összesítő számításokat és kiírásokat, lezárja a file-okat, és kilép.

Ha csak full procedural file-t definiálunk, vagy egy C-kártyán a NOMAIN specifikációt tesszük, a fordító nem generál ciklust.

lapváltáskezelés

Az RPG segítséget nyújt a programozónak, hogy új lapokra fejlécet szeretnénk nyomtatni, ill. hogy elkerülje, hogy nyomtatás közben a perforációra írjon, stb. Az RPG ciklus alap lapváltáskezelője az összesítő kiírások után ellenőrzi, hogy a lapváltó indikátor be van-e kapcsolva. Ha igen, akkor a lapváltó rutin kapja a vezérlést. Ha a programozó (pl. a jobb helykihasználás reményében) jobban a kezébe akarja venni az overflow indikátor figyelését, akkor specifikálhatja az ún. fetch overflow logic használatát: ekkor az overflow indikátort megvizsgálja a program minden olyan sor írásakor, amit fetch overflow-val specifikáltunk. (És természetesen a lapváltó rutint indítja el, ha bekapcsolt.)

A lapváltó rutin a következőt csinálja:

  1. a program megvizsgálja, hogy az előzőleg kiírt lapváltási sorok a fetch overflow logic-nak köszönhetően íródtak-e ki. (Azaz, hogy olyan sornál történt-e lapváltás legutóbb, amelyiknél a programozó a fetch overflowt specifikálta.) Ha igen, visszatér, ha nem akkor a 2. pontra lép.
  2. Kiír minden olyan output sort, amelyik az overflow indikátorral van ellátva

Az RPG űrlapjai

Minden RPG forrásprogramot speciális űrlapokra kell írni, amelyeket specifikációs lapoknak nevezünk. E lapokra kerülnek az RPG program utasításai, amelyek elterjedt neve az RPG-specifikáció. Az űrlapok egy-egy megfelelően kitöltött sora alapján készül el a forrásprogram egy-egy lyukkártyája. Minden sor 80 pozíciót tartalmaz és a sorok megfelelő pozíciószáma a mérvadó a kártya pozíciószámára nézve. A sor (egyben a kártya pozíciószáma) az űrlapokon a fejlécek alapján látható. Ötféle űrlap van, amelyeknek megfelelően hétféle programkártya lyukasztható.

Az űrlapok kitöltésének általános szabályai: Minden űrlap hosszabb-rövidebb mezőkre van osztva, és a felhasználó a forrásprogram megfelelő információit írja e mezőkbe. A bejegyzéseket alfanumerikus és numerikus csoportba soroljuk. A segítségükkel felvehető jelsorozat a szimbólum, amelynek előállítása az alábbi szabályok szerint oldható meg.

Ha a jelsorozat hossza rövidebb, mint az adott mező hossza, akkor a következő szabályok érvényesek:

A karakteres konstans mindazokat a jeleket is tartalmazhatja, amelyek az RPG jelkészletében nem találhatók meg, de a számítógép jelkészletében megvannak.

Kártyák leírása

A vezérkártya

Ez a kártya a 6. oszlopában kötelezően a H karaktert tartalmazza és ez a forrásprogram első feldolgozandó kártyája. Fő funkciója annak jelzése a fordítóprogram részére, hogy a forrásprogram kártyái következnek. Emellett bizonyos információkkal látja el a fordítóprogramot, amelyek részben a fordítás vezérléséhez szükségesek, részben pedig a létrehozandó tárgyprogram kialakítására vonatkozó előírásokat tartalmazzák.

A file leírása

Az egyes file-okat a file leírására szolgáló F-űrlapok segítségével definiáljuk, ahol általában egy file leírásához egy sorra van szükség, de adott esetben szükség lehet további információk megadására is, amelyeket a következőképpen adhatjuk meg:

Egy file-lal kapcsolatban vagy csak E-, vagy csak L-specifikáció alkalmazható. A file-típusa lehet:

A periféria adottságaitól függ, hogy milyen file-típus felvételére alkalmas.

A file-okat jellegük szerint csoportosíthatjuk:

A file rendeltetésének kódját a file-leírás F-űrlapján kell feltűntetni.

Az I-űrlap

A beolvasási műveleteket írja elő. Ezen a lapon kell specifikálni minden olyan file-t amellyel kapcsolatban beolvasásra kell számítani.

A C-űrlap

Ezen a lapon kell specifikálni minden nem input és nem output műveletet. Ezek azok a specifikációk amelyek leginkább megfelelnek a magas szintű nyelvek utasítás fogalmának.

Az O-űrlap

A kiírási műveletek leírására használhatjuk. Ezen specifikálunk minden eredményt szolgáltató műveletet, pl. sornyomtató vagy aktualizálandó file részére.