A Simula programozási nyelv

Szabványos könyvtárak

Bevitel és kivitel (I/O)

A nyelv be- és kiviteli eszközei alapvetően a "file" fogalmára épülnek. Ez az adatállomány első közelítésben valamilyen háttértárolón elhelyezkedő, szekvenciális, vagy címezhető módon szervezett adatok összessége. A file-ban tárolt adatok logikai egysége a rekord, ami karakterek rendezett sorozatából áll.
A be- és kivitel eszközeit a nyelv egy prefixes blokk segítségével vezeti be. Ezeket az eszközöket a "BASICIO" nevű osztály írja le, melyre azonban a felhasználói programokban közvetlenül nem lehet hivatkozni.

A felhasználó programja úgy működik, mintha a

   BASICIO (inlength, outlength) begin inspect SYSIN do
				       inspect SYSOUT do

					   <program>

				 end;

blokkba lenne beágyazva.
A be- és kivitel definíciójában szereplő nagybetűs attribútumokhoz a felhasználói programokban nem lehet hozzáférni. A "BASICIO" vázlatos szerkezete a következőképpen írható le:

 class BASICIO (INPUT_liNELENGTH, OUTPUT_liNELENGTH);
      integer INPUT_liNELENGTH, OUTPUT_liNELENGTH;

      begin
      ref(infile) SYSIN;

      ref(infile) procedure sysin;
	 sysin:-SYSIN;

      class FILE ........................;

      FILE class infile .................;

      FILE class outfile ................;

      FILE class directfile .............;

      outfile class printfile ...........;

      SYSIN:-new infile ("SYSIN");
      SYSOUT:-new printfile ("SYSOUT");
      SYSIN.open(blanks(INPUT_liNELENGTH));
      SYSOUT.open(blanks(OUTPUT_liNELENGTH));
      inner;
      SYSIN.close;
      SYSOUT.close;
   end BASICIO;

A "SYSIN" kártyakép jellegű szabványos bevitelt, "SYSOUT" pedig nyomtató jellegű szabványos kivitelt jelöl ki. Ezen file-ok megnyitását, ill. lezárását a "BASICIO" végzi a felhasználó programján kívül.

A "FILE" osztály

A Simula 67 programozási nyelvben egy általános "FILE" osztályt definiáltak a szerzők:

   class FILE(FILENAME, ...); value FILENAME; text FILENAME; ...

      virtual: procedure open, close;

      begin
      text image;
      Boolean OPEN;

      procedure setpos(i); integer i;

      integer procedure pos;

      Boolean procedure more;

      integer procedure length;

      ...

   end FILE;

Négy előre definiált file típus létezik, melyek ezen szülőosztály részosztályait képezik:
A felhasználó programjában ezen osztályok objektumai reprezentálnak egy konkrét file-t. Minden file objektumnak szöveges attribútum a fizikai file neve.
Az "image" változó egy szövegtárolóra hivatkozik, amely buffer-ként tárolja az éppen feldolgozás alatt levő file rekordját. Egy file lehet nyitott, vagy lezárt állapotban és ezt mutatja az OPEN Boolean típusú attribútum. A file kezdetben mindig zárt (eltekintve a fent említett SYSIN, ill. SYSOUT file-októl), de be- és kivitel nyilvánvalóan csak nyitott file-on történhet. Az open és close virtuális eljárások hajtják végre egy file megnyitását, ill. lezárását, a leszármazott osztályokban újradefiniálhatók. A

   Boolean procedure open(fileimage, ...); text fileimage;

eljárás paramétere egy text típusú buffer terület, az image erre fog hivatkozni.

Az "infile" osztály

Az "infile" osztály a "FILE" osztály leszármazottja, szekvenciális input file-ok kezelésére használható.

   FILE class infile;

      virtual: Boolean procedure endfile;
	       procedure inimage;

      begin

      Boolean procedure open(fileimage, ...); text fileimage;
      procedure close;

      Boolean ENDFILE;
      Boolean procedure endfile;

      procedure inimage;
      character procedure inchar;
      Boolean procedure lastitem;
      integer procedure inint;
      long real procedure inreal;
      integer procedure infrac;
      text procedure intext(w); integer w;

      ...

      ENDFILE:=true;

      ...

   end infile;

Az ENDFILE Boolean típusú attribútum jelöli azt, hogy a szekvenciális input file végére értünk. Az endfile virtuális eljárás ezen változó lekérdezésére szolgál. Az open és close műveletek az ENDFILE attribútumot megfelelő módon true, ill. false értékűre állítják be. Az inimage eljárás a fizikai file-ból egy rekordot olvas be a text típusú image-be. Futási hibát kapunk, ha a szöveg notext, ha az image mérete kisebb mint a beolvasott rekord mérete, ill. ha az inimage eljárás hívásakor az ENDFILE értéke true. Ha az image buffer-ben elfér a rekord, akkor balra igazítódik és a maradék rész szóközökkel töltődik fel. A pozíciójelző értéke 1-re állítódik.
Az inchar az image következő karakterét adja vissza, majd eggyel növeli a pozíciójelzőt. Ha a pozíciójelző az image végére mutat, akkor az inimage eljárás meghívva a következő rekord első karakterét adja és ezáltal lehetővé teszi a folyamatos olvasást.
Ha a file hátralevő része tartalmaz egy vagy több nem szóköz karaktert, akkor a lastitem függvény false értéket ad vissza és a pozíciójelzőt az első nem szóköz karakterre állítja.
Az inint, inreal, infrac eljárások az image megfelelő műveleteit meghívva az aktuális típusra konvertálják a buffer-ban levő adatot, feltéve, hogy az numerikus adat. Eközben tetszőleges számú szóköz karaktert átugorhatnak. Az intext eljárás a következő n karakterből álló szövegrész beolvasását végzi el. Ez átnyúlhat a rekordhatáron is.

Az "outfile" osztály

Az "outfile" osztály a "FILE" osztály leszármazottja, szekvenciális output file-ok kezelésére használható.

   FILE class outfile;

      virtual: procedure outimage;

      begin

      Boolean procedure open(fileimage, ...); text fileimage;
      procedure close;

      procedure outimage;
      procedure outchar(c); character c;
      text procedure ;
      procedure outint(i, w); integer i, w;
      procedure outfix(r, n, w); long real r; integer n, w;
      procedure outreal(r, n, w); long real r; integer n, w;
      procedure outfrac(i, n, w); integer i, n, w;
      procedure outtext(T); text T;

      ...

   end outfile;

Az open eljárás a pozíciójelző értékét 1-re állítja, a close művelet pedig a file lezárása előtt kiírja az image aktuális tartalmát. Az outimage eljárás egy rekordot ír az image buffer-ből a fizikai file-ba. Ezt követően szóközökkel tölti fel az image-t és a pozícióját egyre állítja. Az outchar művelet folyamatosan ír karaktereket az image buffer-ba, ha már nem fér bele több, akkor meghívja az outimage-t.
Az outint, outfix, outreal, outfrac eljárások az ún. kötött formátumú kivitelt valósítják meg. Mindegyiknek van egy integer paramétere, amely az image-be íródandó adat számára meghatározott résszöveg szélességét adja meg. Az outtext művelet a paraméterként megadott szöveget az image-be másolja, a pozíciójelző értékét a megfelelő módon beállítja.

A "directfile" osztály

A "directfile" osztály objektumai olyan fizikai file-t reprezentálnak, amelyben az rekordok sorszámozva vannak.

   FILE class directfile;

      virtual: Boolean procedure endfile;
	       procedure locate, inimage, outimage;

      begin
      integer LOC;

      integer procedure location;
      procedure locate(i); integer i;

      Boolean procedure open(fileimage, ...); text fileimage;
      procedure close;

      Boolean procedure endfile;
      procedure inimage;
      procedure outimage;
      character procedure inchar;
      Boolean procedure lastitem;
      integer procedure inint;
      long real procedure inreal;
      integer procedure infrac;
      text procedure intext(w); integer w;
      procedure outchar(c); character c;
      procedure outint(i, w); integer i, w;
      procedure outfix(r, n, w); long real r; integer n, w;
      procedure outreal(r, n, w); long real r; integer n, w;
      procedure outfrac(i, n, w); integer i, n, w;
      procedure outtext(T); text T;

      ...

   end directfile;

Az egyes rekordokat a sorszámuk azonosítja, az éppen aktuális rekord sorszámát a LOC változó tartalmazza.
A location függvény a LOC aktuális értékét adja vissza, míg a locate eljárással a LOC változó értékét állíthatjuk be. Az open eljárás a file megnyitása után az első rekordra állitja a LOC változót. Az endfile logikai függvény true értékkel tér vissza, ha a LOC aktuális tartalma nem utal fizikai rekordra.
Az inimage eljárás az éppen aktuális rekordot olvassa be, feltéve, hogy a LOC változó ténylegesen egy rekordra mutat. Ezt követően a LOC értéke eggyel növekszik.
Az outimage eljárás kiír egy rekordot /az image buffer tartalmát/ a fizikai file-ba, az aktuális pozícióra, majd a LOC értékét eggyel megnöveli. Az osztály többi művelete az "infile", ill. "outfile" osztályoknál leírtakkal azonos módon működik.

A "printfile" osztály

A "printfile" osztály objektumai egy nyomtatásra szánt kiviteli file-t reprezentálnak. Itt az image buffer a nyomtatott oldal egy sorát jelenti.

   outfile class printfile;

      begin
      integer ;

      integer procedure line;
      procedure linesperpage(n); integer n;
      procedure spacing(n); integer n;
      procedure eject(n); integer n;

      Boolean procedure open(fileimage, ...); text fileimage;
      procedure close;

      procedure outimage;

      ...

   end printfile;

A LINES_PER_PAGE változó az egy lapra kinyomtatható sorok maximális számát határozza meg. Ennek a változónak az értékét a linesperpage eljárással lehet beállítani.
Az outimage hívások alapértelmezésben egymás utáni sorokba írnak. A SPACING változóval azt az értéket lehet megadni, amellyel a következő nyomtatási művelet után a LINE változó megnövekszik. Ennek a változónak az értékét a spacing eljárással lehet beállítani, de futási hibát kapunk ha a paramétere kisebb 0-nál, vagy nagyobb LINES_PER_PAGE-nél.
A LINE változó a következő nyomtatandó sor sorszámát tartalmazza, értékét a LINE eljárás segítségével lehet beállítani. Ha a printfile objektum nincs megnyitva, akkor a LINE értéke 0.
Az eject eljárás egy lap n. sorszámú sorát jelöli ki a következő nyomtatási sorként.
Az outimage, open, close műveletek a korábbiakban leírtakkal azonos módon működnek, egy-két kiegészítéssel.

A Simula 67 nyelv által definiált szabványos osztályok kibővítik a felhasználónak nyújtott programozási eszköztárat. A SIMSET osztály vezeti be a listakezelést, a SIMULATION osztály pedig olyan programozási eszközöket definiál, amelyek szimulációs feladatok megoldását teszik lehetővé. Mindkét osztály a program bármely blokk szintjén hozzáférhető.

A "SIMSET" osztály

A "SIMSET" beépített osztály segítségével kétirányú ciklikus listákat kezelhetünk.

   class SIMSET;

      begin
      class linkage;
      linkage class head;
      linkage class link;

   end SIMSET;

A SIMSET osztályon belül deklarált szabványos osztályokban vannak definiálva a listakezeléshez szükséges hivatkozási típusú változók és eljárások. Mind a listáknak, mind pedig a lista elemévé váló objektumoknak olyan hivatkozásaik vannak, amelyek a következő (suc), és a megelőző (pred) elemre mutatnak. Ezért a listák és a lista elemek a közös adatokat, ill. eljárásokat egy "linkage" szülő osztályba tömörítik. A "linkage" osztály "head" részosztályához tartozó objektumok alkotják a listákat, a "link" részosztályához tartozók pedig a listaelemeket.

A "linkage" osztály

   class linkage;

      begin
      ref(linkage) SUC, preD;

      ref(link) procedure suc;
      ref(link) procedure pred;
      ref(linkage) procedure prev;

   end linkage;

A "linkage" osztály a listafejek és listaelemek közös szülőosztálya. A SUC és preD attribútumok az adott linkage típusú objektumot követő, ill. megelőző objektumra mutató hivatkozások. Ezek a változók kívülről nem érhetők el, csak a megfelelő lekérdező függvényeken keresztül. A suc és pred eljárások none értéket adnak, ha a SUC vagy preD által megjelölt objektum nem eleme egy listának. A SUC és preD attribútumokat csak a "link" és "head" osztályokon belül definiált eljárások segítségével lehet megváltoztatni. A prev függvény lehetővé teszi, hogy a listafejhez a lista első eleméből is hozzá lehessen férni.

A "link" osztály

   linkage class link;

      begin

      procedure out;
      procedure follow(x); ref(linkage) x;
      procedure precede(x); ref(linkage) x;
      procedure into(s); ref(head) s;

   end link;

A "link" osztály részosztályaihoz tartozó objektumok listaelemek lehetnek. Egy objektum egyidejűleg csak egy lista eleme lehet. A suc és pred eljárásokon kívül még további négy műveletet definiál. Az out eljárás kivesz egy elemet a listából, természetesen csak akkor, ha az eleme volt a listának. A follow és a precede eljárások kiveszik a listaelemet a listából, majd a paraméterként megadott "linkage" osztályon belüli attribútum mögé, ill. elé illesztik. Az into eljárás kiemeli a listaelemet a listából és utolsó elemként beilleszti a paraméterként megadott új listába. Ha a paraméter none értékű, akkor ez a művelet hatástalan.

A "head" osztály

   linkage class head;

      begin

      ref(link) procedure first;
      ref(link) procedure last;
      Boolean procedure empty;
      integer procedure cardinal;
      procedure clear;

      ...

   end head;

A "head" osztály vagy részosztályának objektumai listafejek lehetnek. Mivel ezek az objektumok nem lehetnek listaelemek, ezért minden egyes listához pontosan egy head tartozik. A lista első, ill. utolsó elemére a first, ill. last függvényekkel lehet hivatkozni. Az empty logikai függvény csak akkor ad true értéket, ha a listának egyetlen eleme sincs. A cardinal eljárás a listaelemek számát adja meg. A clear művelet kiüríti a listát. A "head" osztály a törzsében saját magára állítja az üres lista SUC, ill. preD attribútumait.

A "SIMULATION" osztály

A "SIMULATION" szabványos osztályt a szimulációs feladatok megoldását támogató eszköznek lehet tekinteni. A szimuláció során olyan nagy rendszereket vizsgálhatunk, ahol a valóságos megfigyelés túlságosan költséges, vagy akár megvalósíthatatlan is lehetne. így például szimulációs modell tárgya lehet egy gyártósor, egy forgalmi rendszer, vagy akár egy társadalmi rendszer is, ahol az egyének kölcsönhatásban állhatnak egymással. A legtöbb ilyen szimulációs rendszernek két alapvető tulajdonsága van:

Az első követelmény modellezéséhez elegendő annyi, hogy az egyes programok fel tudják függeszteni magukat, majd egy későbbi időpontban tovább folytathatóak legyenek ott, ahol korábban abbamaradtak. Tehát egy ütemező program vezérlése elegendő lehet.
Fontos feladat a rendszerben a szimulált idő nyilvántartása. A rendszer egy aktív folyamatának el kell tudnia engedni a vezérlést egy adott t időtartamra és vissza kell kapnia azt, amikor az időváltozót t-vel megnöveltük. Az ilyen jellegű feladatok megoldásához nyújt tehát segítséget a SIMULATION osztály. A kétirányú listák felhasználásával megvalósított SIMULATION osztály valójában osztályok és műveletek gyűjteménye.

   SIMSET class SIMULATION

      begin
      link class EVENT_NOTICE(EVTIME, PROC);
	 long real EVTIME; ref(process)PROC;

	 begin
	 ref(EVENT_NOTICE) procedure suc;
	 ref(EVENT_NOTICE) procedure pred;
	 procedure RANK(BEFORE); Boolean BEFORE;

      end EVENT_NOTICE;
      link class process;

      ref(head) SQS;

      ref(EVENT_NOTICE) procedure FIRSTEV;
      ref(process) procedure current;
      long real procedure time;
      procedure hold(T); long real T;
      procedure passivate;
      procedure wait(S); ref(head) S;
      procedure cancel(X); ref(process) X;
      procedure ACTIVATE(REAC, X, CODE, T, Y, PRIOR); value CODE;
	 ref(process) X, Y; Boolean REAC, PRIOR; text CODE;
	 long real T;
      procedure accum(a, b, c, d); name a, b, c; long real a, b, c, d;

      process class MAIN_PROGRAM;

      ...

   end SIMULATION;

A SIMULATION osztály nyelvi eszközöket vezet be egy folyamat modellezésére. Az "SQS" (SeQuencing Set) változó az időtengelyt reprezentáló listára hivatkozik. Az időtengely a tervezett végrehajtási sorrend listája, elemei az EVTIME attribútum növekvő értékei szerint rendezett eseményfeljegyzések. Az eseményfeljegyzés (EVENT_NOTICE) PROC attribútuma egy "process" objektumra hivatkozik és egy olyan eseményt fejez ki, amely annak az objektumnak a következő aktív fázisa. Egy process objektumra egyidejűleg legfeljebb egy eseményfeljegyzés hivatkozhat.
A végrehajtási sorrend listáján, vagyis az időtengelyen az első eseményfeljegyzés a jelenleg is aktív process objektumra vonatkozik. Ezt az objektumot a current eljárással lehet lekérdezni. Az első eseményfeljegyzés EVTIME értéke a szimulációs idő pillanatnyi aktuális értéke, amely a time eljárással lekérdezhető.

A "process" osztály

A process osztály részosztályaihoz tartozó objektumokat folyamatoknak nevezzük.

	link class process;

	   begin
	   Boolean TERMINATED;
	   ref(EVENT_NOTICE) EVENT;

	   Boolean procedure idle;
	   Boolean procedure terminated;
	   long real procedure evtime;
	   ref(process) procedure nextev;

	   ...

	end process;

Ezek az objektumok listába fűzhetők, az időtengelyre eseményfeljegyzés készülhet róluk és az ütemező utasítások megváltoztathatják állapotukat. A lehetséges állapotok:
Amikor létrehozunk egy folyamat objektumot, az a benne lévő detach utasítás hatására azonnal leválik, megszakítási pontja a detach utáni pont lesz. Az idle logikai függvény true értéket ad vissza, ha a folyamat az adott pillanatban nem szerepel a végrehajtási sorrendet előíró listában, azaz az időtengelyen. Ilyenkor a folyamatot tétlennek nevezzük, állapota pedig passzív, vagy befejezett. A terminated eljárással lekérdezhetjük, hogy az adott folyamat terminált-e már. Egy folyamat aktívvá válását a hozzárendelt eseményfeljegyzés az EVTIME attribútummal kijelölt szimulációs időpontra ütemezi. Ezt az időpontot az evtime eljárással lehet lekérdezni. A nextev eljárás azt a folyamatot adja meg, amelyre a következő eseményfeljegyzés vonatkozik az időtengelyen. Ha ilyen folyamat nem létezik, akkor visszatérési értéke none.

Az ütemező utasítás

	procedure ACTIVATE(REAC, X, CODE, T, Y, PRIOR); value CODE;
	   ref(process) X,Y; Boolean REAC, PRIOR; text CODE;
	   long real T;

Az aktuális paraméterlista az ütemező utasítás alapján határozható meg a következő szabályok szerint:
ütemezési típusszöveg típusú aktuális paraméter
üres"direct"
at aritmetikai kifejezés"at"
delay aritmetikai kif."delay"
before objektumkifejezés"before"
after objektumkif."after"

Az ACTIVATE ütemező utasítás célja a folyamat egy aktív fázisának egy ütemezése. Legyen X az ütemezés tárgyát kijelölő objektumkifejezés. Ha az ütemezési mód activate, akkor az utasítás hatástalan, kivéve, ha az X passzív folyamat. Ha az ütemezési mód reactivate és az X ütemezett, vagy éppen aktív folyamat, akkor a pillanatnyilag érvényes eseményfeljegyzés törlődni fog.
Az ütemezés az X-re vonatkozó eseményfeljegyzés legenerálásával és az időtengelyre való beszúrással történik meg. Az ütemezés típusát a fent leírt CODE paraméter határozza meg.
Egy eseményt többféleképpen tehetünk aktívvá:

A végrehajtási sorrendet meghatározó eljárások

A végrehajtási sorrendet kijelölő eljárások a szimulációs modellben a folyamatok kvázi-párhuzamos működésének megszervezésére szolgál. A hold utasítás (melynek T paramétere >=0 valós szám) az éppen aktív folyamat aktív fázisát felfüggeszti és annak következő aktív fázisát a time + T szimulációs időpontra ütemezi át. így az utasítás T időtartamú inaktív periódust jelöl ki. A passivate eljárás megszakítja az éppen aktív folyamat aktív fázisát és annak eseményfeljegyzését is törli. A folyamat passzívvá válik és a következő aktív fázisát a folyamaton kívülről, más folyamatokból kell majd ütemezni. Ez az utasítás tehát meghatározatlan időtartamú inaktív periódust jelöl ki. A wait eljárás a paraméterként megadott listába, mint várakozási sorba utolsó elemként beteszi az éppen aktív folyamatot és meghívja a passivate eljárást. A cancel eljárás (melynek X paramétere folyamat objektumra utaló hivatkozás) törli a megfelelő eseményfeljegyzést, ha az egyáltalán létezik. Ha a folyamat éppen aktív, vagy ütemezett, akkor passzívvá válik, egyébként az utasítás hatástalan.

A szimuláció főprogramja

	process class MAIN_PROGRAM;

	   begin
	   while true do
	      detach;

	end MAIN_PROGRAM;

A szimuláció főprogramja segítségével érhetjük el, hogy a SIMULATION blokkpéldány is úgy viselkedjen, mintha maga is egy folyamat lenne. E cél elérésére szolgál a MAIN_PROGRAM osztály, mivel annak egy objektuma a szimulációs kvázi-párhuzamos rendszer állandó komponense attól fogva, hogy a vezérlés belép a szimulációs blokkba, egészen addig, míg a vezérlés a blokk záró end-jén keresztül távozik. A szimulációs modellt a MAIN_PROGRAM egy objektumának legenerálása és a hozzá kapcsolódó 0 szimulációs időpontú fázis ütemezése indítja el.