4.1. Eljárás deklarációk
Egy eljárásfejbõl és
egy eljárástörzsobõl áll. A fej a szignatúrát (eljárás azonosítója, formális
paraméterek, visszatérési érték) tartalmazza, míg a törzs a deklarációkat és az
utasításokat. Az eljárás azonosítóját meg kell ismétleni az eljárás
deklarációjának végén. ( END ) Kétféle eljárás van: a normál eljárás és a
függvényeljárás. Az eljárásban deklarált objektumok (változó, konstans, típus,
eljárás) lokálisak! Tetszõleges szinten egymásba lehet ágyazni eljárásokat, az
eljárásban meghívhatjuk rekurzívan saját magát is. Az eljárásban a lokális
objektumokon és a formális paramétereken kívül látszanak még azok az objektumok,
amelyek az eljárás környezetében lett deklarálva, feltéve hogy nem takarják el
azonos nevû lokális objektumok.
ProcedureDeclaration = ProcedureHeading ";" ProcedureBody ident
ProcedureHeading = PROCEDURE [Receiver] IdentDef [FormalParameters]
ProcedureBody = DeclarationSequence [BEGIN StatementSequence] END
DeclarationSequence = {CONST {ConstantDeclaration ";"} | TYPE
{TypeDeclaration ";"} | VAR {VariableDeclaration ";"}} {ProcedureDeclaration ";"
| ForwardDeclaration ";"}
ForwardDeclaration = PRROCEDURE "^" [Receiver] IdentDef [FormalParameters]
Az elõre deklarálás (forward declaration) segítségével hivatkozhatunk elõbb
egy eljárásra, minthogy definiáltuk volna. (A definiálásnak azért még ugyanebben
a láthatósági blokkban meg kell történnie.)
Formális paraméterek
A formális paraméter az aktuális paraméterre utal.
A megfeleltetés az eljárás hívásakor történik. Az érték szerint átadott
paraméterek deklarációjánál nem kell a VAR kulcsszó, míg a cím szerintinél igen.
Egy függvény típusú eljárásnak mindenképpen kell paraméter listája (akár az üres
() lista). A formális paraméterek lokálisak az eljárásban, mintha az eljárás
hívásakor deklaráltuk volna oket.
FormalParameters = "(" [FPSection {";"
FPSection}] ")" [":" Qualident]
FPSection = [VAR] ident {"," ident} ":" Type
Mindegyik formális paraméter típusát meg kell határozni a paraméterlistában.
A cím szerinti paramétereknél a típusnak bázis típusának kell lennie az aktuális
paraméter típusának. Érték szerinti paraméternél az értékadás szabálya érvényes.
Ha a formális paraméter ARRAY OF T, akkor az aktuális paraméter bármilyen T
elemû tömb lehet. Ez az úgynevezett nyitott tömb (open array). Ha a formális
paraméter BYTE típusú, akkor az aktuális paraméter lehet CHAR vagy SHORTINT
típusú is. Ha a formális paraméter ARRAY OF BYTE típusú, akkor bármilyen
típusú aktuális paraméter megengedett! Ha a formális paraméter eljárás típusú,
akkor az aktuális paraméter lehet egy legkülsõ (0. szinten beágyazott) szinten
deklarált eljárás vagy megfelelõ típusú eljárásváltozó. Nem lehet azonban
elõredefiniált eljárás. Az eljárás visszatérési értéke nem lehet sem rekord, sem
tömb.
Példák:
PROCEDURE ReadInt ( VAR x : INTEGER );
VAR i : INTEGER;
ch : CHAR;
BEGIN
i := 0;
Read( ch );
WHILE ( "0" <= ch ) & ( ch <= "9" ) DO
i := 10 * i + ( ORD ( ch ) - ORD ( "0" ));
Read ( ch );
END;
x := i;
END ReadInt
PROCEDURE WriteInt ( x, n : INTEGER ); (* 0<= x <= 10000 *)
VAR i : INTEGER;
buf : ARRAY 5 OF INTEGER;
BEGIN
i := 0;
REPEAT
buf [ i ] := x MOD 10;
x := x DIV 10;
INC ( i );
UNTIL x = 0;
WHILE ni DO
Write ( " " );
DEC ( n );
END;
REPEAT
DEC ( i );
Write ( CHR ( buf [ i ] + ORD ( "0" )));
UNTIL i = 0;
END WriteInt
PROCEDURE log2 ( x : INTEGER ) : INTEGER;
VAR y : INTEGER;
BEGIN
y := 0;
WHILE x1 DO
x := x DIV 2;
INC ( y );
END;
RETURN y;
END log2
Típushoz kötött eljárások
Az Oberon-2 objektum-orientált nyelv, így
lehetõség van objektumosztályok definiálására, amelyek nemcsak adattagokkal
rendelkeznek, mint a rekordok, hanem metódusokkal is. Az objektumosztályokat
ugyanúgy kell definiálni, mint a rekordokat. Definíciós modulban a metódusok
fejlécét is a rekord mezõi közé kell írni, míg az implementációnál külön kell
definiálni oket. Ezeket nevezzük típushoz kötött eljárásoknak. Az osztályt,
melynek objektumaihoz az eljárás tartozik, fogadónak nevezzük, és ezt, mint
kitüntetett formális paramétert az eljárás neve elé kell írni.
ProcedureHeading = PROCEDURE [Receiver] IdentDef [FormalParameters]
Receiver = "(" [VAR] ident ":" ident ")"
Példák
PROCEDURE ( t : Tree ) Insert ( node : Tree );
VAR p, father : Tree;
BEGIN
p := t;
REPEAT
father := p;
IF node.key = p.key THEN
RETURN
END;
IF node.key < p.key THEN
p := p.left
ELSE
p := p.right
END
UNTIL p = NIL;
IF node.key < father.key THEN
father.left := node
ELSE
father.right := node
END;
node.left := NIL;
node.right := NIL
END Insert;
PROCEDURE ( t : CenterTree ) Insert ( node : Tree ); (* redefinition *)
BEGIN
WriteInt ( node ( CenterTree ).width );
t.Insert^ ( node ) (* calls the Insert procedure bound to Tree *)
END Insert;
Elõredefiniált eljárások
Függvény eljárások:
Név |
Argumentum típus |
Eredmény típus |
Leírás |
ABS ( x ) |
numerikus típus |
x típusa |
abszolút érték |
ADR ( v ) |
akármilyen |
LONGINT |
v változó címe |
ASH ( x, n ) |
x, n : egész |
LONGINT |
x * 2 ^ n, aritmetikai eltolás |
CAP ( x ) |
CHAR |
CHAR |
megfelelo nagybetû |
CHR ( x ) |
egész típus |
CHAR |
x ASCII kódú karakter |
ENTIER ( x ) |
valós típus |
LONGINT |
legnagyobb x-nél nem nagyobb egész |
LEN ( v, n ) |
v : tömb |
LONGINT |
v mérete az n. dimenzió mentén |
|
n : INTEGER |
|
(az elso dimenzió a 0.) |
LEN ( v ) |
v : tömb |
LONGINT |
LEN ( v, 0 )-val ekvivalens |
LONG ( x ) |
SHORTINT |
INTEGER |
konverzió nagyobbra |
|
INTEGER |
LONGINT |
|
REAL |
LONGREAL |
MAX ( T ) |
T=alaptípus |
T |
T maximális értéke |
|
T=SET |
INTEGER |
halmaz maximális eleme |
MIN ( T ) |
T=alaptípus |
T |
T minimális értéke |
|
T=SET |
INTEGER |
halmaz minimális eleme (0) |
ODD ( x ) |
egész típus |
BOOLEAN |
x MOD 2 = 1 |
ORD ( x ) |
CHAR |
INTEGER |
x ASCII kódja |
SHORT ( x ) |
LONGINT |
INTEGER |
konverzió kisebbre (csonkítás lehetséges) |
|
INTEGER |
SHORTINT |
|
LONGREAL |
REAL |
SIZE ( T ) |
akármilyen |
egész típus |
T mérete byte-okban |
Egyéb eljárások:
Név |
Argumentum típus |
Leírás |
ASSERT ( x ) |
x : logikai kifejezés |
kilép a programból, ha x értéke hamis |
ASSERT ( x, n ) |
x : logikai kifejezés, n : egész konstans |
kilép a programból n visszatérési értékkel, ha x értéke hamis |
COPY ( x, v ) |
x : karaktertömb vagy karakterfüzér, v : karaktertömb |
v := x |
DEC ( v ) |
egész |
v := v - 1 |
DEC ( v, n ) |
v, n : egész |
v := v - n |
EXCL ( v, x ) |
v : SET; x egész |
v := v - { x } |
HALT ( x ) |
egész konstans |
kilép a programból x visszatérési értékkel |
INC ( v ) |
egész |
v := v + 1 |
INC ( v, n ) |
v, n : egész |
v := v + n |
INCL ( v, x ) |
v : SET; x egész |
v := v + { x } |
NEW ( v ) |
mutató rekordra vagy rögzített méretû tömbre |
allokál egy v^ típusú objektumot |
NEW ( v, x0, ..., xn ) |
v : mutató nyílt tömbre, xi : egész |
allokál egy v^ típusú töböt x0..xn
méretekkel |
4.2. Fordítási egységek
A fordítási egység egy
modul vagy egy definíció (definíciós modul). A modul deklarációk (konstans,
típus, változó, eljárás) gyûjteménye és utasítások szekvenciája. A definíció egy
modulra vonatkozik. Azokat a deklarációkat tartalmazza, amelyek láthatóak egy
kliens modul számára. Oberon-2-ben ezt nem kell feltétlenül a programozónak
elkészítenie, hanem automatikusan is generálható a modulból. Ekkor a modulban
egy "*" karakternek kell követnie a kívülrõl látható azonosítók nevét, illetve a
csak olvasható változókat egy "-" jelnek.
CompilationUnit = Module | Definition Module = MODULE ident ";"
[ImportList] DeclarationSequence [BEGIN StatementSequence] END ident "."
ImportList = IMPORT import {"," import} ";"
Import = ident [":" ident]
Definition = DEFINITION ident ";" [ImportList] DefSequence END ident "."
DefSequence = [CONST {ConstDeclaration ";"}] [TYPE {TypeDeclaration ";"}]
[VAR {VariableDeclaration ";"}] {ProcedureHeading ";"}
Az import listában a fordítási egységben kliensként használt modulokat kell
felsorolni. Egy M modulból exportált x objektumra M.x-ként lehet hivatkozni. Ha
imoprtálásnál "M0 : M"-et használtunk, akkor az M0.M.x helyett használhatjuk az
M0.x-et. A BEGIN utáni utasítássorozat akkor hajtódik végre, amikor a modul a
rendszerhez adódik (betöltõdik). Ez az inicializáló rész. A definícióban egy
rekord típusnak csak egy részét is deklarálhatjuk (ez lesz a publikus
projekciója). Az itt deklarált részek láthatóak a klienseknél, a többi nem.
Példa:
MODULE Trees;
IMPORT Texts, Oberon;
(* exports: Tree, Node, Insert, Search, Write, Init *)
(* exports read-only: Node.name *)
TYPE
Tree* = POINTER TO Node;
Node* = RECORD
name- : POINTER TO ARRAY OF CHAR;
left, right: Tree
END;
VAR w : Texts.Writer;
PROCEDURE ( t : Tree ) Insert* ( name : ARRAY OF CHAR );
VAR p, father : Tree;
BEGIN
p := t;
REPEAT
father := p;
IF name = p.namel^ THEN
RETURN
END;
IF name < p.name^ THEN
p := p.left
ELSE
p := p.right
END
UNTIL p = NIL;
NEW ( p );
p.left := NIL;
p.right := NIL;
NEW( p.name, LEN ( name ) + 1 );
COPY( name, p.name^ );
IF name < father.name^ THEN
father.left := p
ELSE
father.right := p
END
END Insert;
PROCEDURE ( t : Tree ) Search* ( name : ARRAY OF CHAR ) : Tree;
VAR p : Tree;
BEGIN
p := t;
WHILE ( p # NIL ) & ( name # p.name^ ) DO
IF name < p.name^ THEN
p := p.left
ELSE
p := p.right
END
END;
RETURN p
END Search;
PROCEDURE ( t : Tree ) Write*;
BEGIN
IF t.left # NIL THEN
t.left.Write
END;
Texts.WriteString ( w, t.name^ );
Texts.WriteLn ( w );
Texts.Append ( Oberon.Log, w.buf );
IF t.right # NIL THEN
t.right.Write
END
END Write;
PROCEDURE Init* ( t : Tree )
BEGIN
NEW ( t.name, 1 );
t.name [ O ] := OX;
t.left := NIL;
t.right := NIL
END Init;
BEGIN
Texts.OpenWriter ( w )
END Trees.
Az ebbol automatikusan generált definíciós állomány:
DEFINITION Trees;
IMPORT Texts, Oberon;
TYPE
Tree = POINTER TO Node;
Node = RECORD
name- : POINTER TO ARRAY OF CHAR;
left, right: Tree
PROCEDURE Insert ( name : ARRAY OF CHAR );
PROCEDURE Search ( name : ARRAY OF CHAR ) : Tree;
PROCEDURE Write;
END;
PROCEDURE Init ( t : Tree );
END Trees;