A Modula3 programozási nyelv

Példaprogramok

1. Példa (típus ekvivalencia)

A program a típusekvivalenciára mutat példát.

CONST N=10; TYPE T1=[1..10]; T2=[1..N]; (* T1 és T2 ekvivalensek *) TYPE T1 = {A, B, C}; T2 = {A, B, C}; U1 = [T1.A..T1.C]; U2 = [T1.A..T2.C];
T1 és T2 azonos típusú, mert kiterjesztett definíciójuk megegyezik. T1.C=T2.C, emiatt U1 és U2 is megegyezõ típusúak. T1 és U1 ugyan ugyanazokat az értékeket tartalmazzák, típusuk azonban különböző, mert T1 kiterjesztett definíciója felsorolás, U1 pedig részintervallum.

2. Példa (TEXT típus)

A példakód egy TEXT típusú érték kiírását és egy másolást mutat be.

SIO.PutText("Ez egy TEXT.\n"); SIO.PutChar(Text.GetChar(text,Text.Length(text)-1));

3. Példa (rekord)

Egy rekord létrehozása a következő képpen néz ki.

TYPE Adat = RECORD nev,cím:TEXT; kor:CARDINAL; END;

4. Példa (halmaz)

A példa egy halmaz létre hozását és használatát szemlélteti.

TYPE Gomb={bal,kozep,jobb}; Eger=SET OF Gomb; VAR eger:Eger; ... eger:=Eger{}; eger:=eger+Eger{Gomb.bal}; IF Gomb.bal IN eger THEN ...

5. Példa (tömb)

A tömbkezelést szemlélteti a következő példa:

(* Példa fix hosszú tömbtípusra: *) TYPE Tomb1=ARRAY [1..3],[1..2] OF REAL; (* Példa nyitott (open) tömbre, melynek hossza futási idõben derül ki: *) TYPE Tomb2=ARRAY OF REAL; VAR t:Tomb2; ... t:=NEW(REF Tomb2,10);

6. Példa (deklarációk)

A példa a nyelvben használható változók deklarációját szemlélteti.

CONST Pi = 3.14; (* REAL *) Maxsize = 30; (* INTEGER *) Space = ' '; (* CHAR *) MaxValue: INTEGER = 5 * (25 - 3); (* INTEGER *) MinValue = 2; (* INTEGER *) RangeValue = MaxValue - MinValue + 1; (* INTEGER *) Name = "Arnie Shoestring"; (* TEXT *) Caps = SET OF CHARACTER{'A'..'Z'}; (* SET OF CHARACTER *) TYPE Index = [1..Maxsize]; (* Index *) Letters = ['a'..'z']; (* Index *) Colors = {Red, Green, Blue, Yellow}; (* Felsorolási *) ArrType = ARRAY Colors OF INTEGER; (* Tömb *) ArrType2 = ARRAY [1..5] OF CHAR; (* Tömb *) SetType = SET OF Letters; (* Halmaz *) Ptr = REF Student; (* Referencia *) Student = RECORD (* Rekord *) name : TEXT; id : INTEGER; gpa : REAL; next : Ptr; END; VAR n : INTEGER := -15; (* INTEGER *) nonneg : CARDINAL := 5; (* CARDINAL *) x : REAL := 3.0; (* REAL *) ch : CHAR := 'Q'; (* CHAR *) done : BOOLEAN := TRUE; (* BOOLEAN *) str : TEXT := "Test"; (* TEXT *) arr : ArrType := ArrType{0,1,2,3}; (* ARRAY *) arr2 : ArrType2 := ArrType2{' ', ..}; (* ARRAY *) inFile : Rd.T; (* Reader *) outFile : Wr.T; (* Writer *) ltrSet : SetType := SetType{'a'..'d','z'}; (* SET *) head : Ptr := NIL (* Pointer *) st : Student (* RECORD *) := Student{"Joe", 15426, 3.35, NIL}; PROCEDURE One(y: REAL; VAR c: ArrType; x: INTEGER := 5) = (* Példa eljárás definiálására. y egy érték szerinti, c egy cím szerinti paraméter. x érték szerinti paraméter default értékkel. *) VAR i: INTEGER; (* lokális változó *) BEGIN (* eljárás törzs *) ; . . . ; END One; PROCEDURE Max(a, b: INTEGER): INTEGER = (* Példa függvény definiálására. *) VAR max: INTEGER; BEGIN max := a; IF a < b THEN max := b END; RETURN max; END Max;

7. Példa (generic)

A következő példa bemutatja, hogy a Modula3 nyelvben hogyan lehet a gnericet használni.

GENERIC INTERFACE Stack(Elem); (*Elem.T nem lehet nyitott tömb!!!*) TYPE T <: REFANY; PROCEDURE Create(): T; PROCEDURE Push(VAR s: T; x: Elem.T); PROCEDURE Pop(VAR s: T): Elem.T; END Stack. GENERIC MODULE Stack(Elem); REVEAL T = BRANDED OBJECT n: INTEGER; a: REF ARRAY OF Elem.T; END; PROCEDURE Create(): T = BEGIN RETURN NEW(T, n := 0, a := NIL) END Create; PROCEDURE Push(VAR s: T; x: Elem.T) = BEGIN IF s.a = NIL THEN s.a := NEW(REF ARRAY OF Elem.T, 5) ELSIF s.n > LAST(s.a^) THEN WITH temp = NEW(REF ARRAY OF Elem.T, 2 * NUMBER(s.a^)) DO FOR i := 0 TO LAST(s.a^) DO temp[i] := s.a[i] END; s.a := temp; END END; s.a[s.n] := x; INC(s.n); END Push; PROCEDURE Pop(VAR s: T): Elem.T = BEGIN DEC(s.n); RETURN s.a[s.n]; END Pop; BEGIN END Stack.;
Példányosítás INTEGER típus paraméterrel:
INTERFACE Integer; TYPE T = INTEGER; END Integer. INTERFACE IntStack = Stack(Integer) END IntStack. MODULE IntStack = Stack(Integer) END IntStack.
Az implementáló moduloknak nem kell leellenõrizniük a nem példányosított generic-ek típusait, de a saját interface-eik típusát igen:
INTERFACE String; TYPE T = ARRAY OF CHAR; END String. INTERFACE StringStack = Stack(String) END StringStack. MODULE StringStack = Stack(String) END StringStack.
A fordító hibát fog jelezni az utolsó sor fordításakor ugyanis ekkor a modul Push mûveletében a NEW operátor paraméterei hiányosak lesznek. Ennek elkerülése végett nem szabad nyitott tömbökkel (String interface T típusa) mint aktuális paraméterekkel példányosítani generikus fordítási egységeket.

8. Példa (kivételkezelés)

A nyelv által támogatott kivételkezelésre mutat példát az alábbi kód.

EXCEPTION FileError(TEXT); ... VAR rd1,rd2 :Rd.T; (* Az Rd.T egy input stream, az Rd interfész része *) val1,val2 :ARRAY [1..10] OF REAL; BEGIN TRY IF NOT SF.FileExists(File1) THEN RAISE FileError(File1) END; (* SF: Simple File interfész *) IF NOT SF.FileExists(File2) THEN RAISE FileError(File2) END; (* hiba kiváltása *) rd1:=SF.OpenRead(File1); (* olvasás egy fájlból stream-be*) rd2:=SF.OpenRead(File2); GetRealArray(rd1, val1); (* saját, megírt eljárásunk *) GetRealArray(rd2, val2); ... EXCEPT | FileError(fname) => SIO.PutText(fname & "nem létezik!\n"); | SIO.Error => SIO.PutText("Rossz formátum!"); END; (* TRY-EXCEPT *) ...

9. Példa (objektum)

A példa az objektumkezelésre mutat példát.

... TYPE ET = INTEGER; Stack = OBJECT; top : Node := NIL; METHODS push(elem : ET) := Push; pop() : ET := Pop; empty() : BOOLEAN := Empty; END; Node = REF RECORD info : ET; next : Node END; PROCEDURE Push(stack : Stack; elem : ET) = ... END Push; PROCEDURE Pop(stack : Stack) : ET = ... END Pop; PROCEDURE Empty(stack : Stack) : BOOLEAN = ... END Empty;

10. Példa (NARROW)

A Modula3 nyelvben található NARROW utasítás működését szemlélteti.

TYPE Super=OBJECT METHODS m1():=P1 END; Sub=Super OBJECT METHODS m2():=P2 END; VAR super:=NEW(Super); sub:=NEW(Sub); ... BEGIN super.m1(); (* helyes *) sub.m1(); (* helyes *) sub.m2(); (* helyes *) super:=sub; (* értékadás *) super.m2(); (* ez hiba *) NARROW(super, Sub).m2(); (* ez helyes *) ...

11. Példa (branded és reveal)

Az egységbe zárásra mutat példát a következő kód.

INTERFACE ... TYPE T:REFANY; ... MODULE ... REVEAL T= BRANDED REF RECORD x,y:INTEGER; END;

12. Példa (Hello World)

A programozási nyelvek tanításának első példaprogramja, azaz Hello World.

MODULE Hello EXPORTS Main; (* Main : predefinit, üres interfész *) FROM SIO IMPORT Put; BEGIN Put("Hello world!\n"); END Hello.

13. Példa (egy teljes objektum- típus specifikálása, implementálása és felhasználása)

A kód szemlélteti hogy, hogyan lehet egy saját objektumot létrehozni és használni.

INTERFACE PiggyObj; (* Malacpersely *) TYPE T <: Public; (* rejtett altípus *) Public = OBJECT METHODS init():T; deposit(cash:CARDINAL); (* pénz elhelyezése a malacperselyben *) smash():CARDINAL; (* pénz kivétele, a persely összetörése *) END; END PiggyObj. *** MODULE PiggyObj; REVEAL T=Public BRANDED OBJECT contents:INTEGER; OVERRIDES init:=Init; deposit:=Deposit; smash:=Smash; END; PROCEDURE Init(t:T):T= BEGIN t.contents:=0; RETURN t END Init; PROCEDURE Deposit(t:T; amount:CARDINAL)= BEGIN <* ASSERT t.contents >= 0 *> (* elöfeltétel: nem törött a persely *) INC(t.contents, amount); END Deposit; PROCEDURE Smash(t:T):CARDINAL= VAR s:CARDINAL:=t.contents; BEGIN t.contents:=-1; (* persely összetörve *) RETURN s (* visszatér az eredeti tartalommal *) END Smash; BEGIN END PiggyObj. *** MODULE PiggyBank EXPORTS Main; (* Malacpersely felhasználása *) IMPORT PiggyObj; FROM SIO IMPORT PutText,PutInt,GetInt,Nl; TYPE PiggyBanks=ARRAY [0..1] OF PiggyObj.T; VAR sty:PiggyBanks; amount,index:INTEGER; active:=NUMBER(PiggyBanks); (* mûködõ; perselyek száma *) BEGIN PutText("Malacpersely:\n"& "Pozitív összeg halmozódik, negatív hatására összetörik a persely.\n"& "Páratlan összegek az 1-es, párosak a 0-s perselybe kerülnek.\n"); FOR s:=FIRST(sty) TO LAST(sty) DO sty[s]:=NEW(PiggyObj.T).init(); (* objektum létrehozása és init. *) END; WHILE active>0 DO amount:=GetInt(); index:=ABS(amount) MOD NUMBER(sty); IF amount>=0 THEN IF sty[index]#NIL THEN sty[index].deposit(amount) END ELSE PutText("A persely kiürített tartalma:"); PutInt(index,1); PutInt(sty[index].smash(),6); Nl(); sty[index]:=NIL; (* objektum törlése *) DEC(active); (* aktív perselyek száma csökken *) END; END; END PiggyBank.

14. Példa Párhuzamos környezetben használható verem monitorral

A párhuzamosság nyelvi elemeit felhasználó példaprogram egy vermen alkalmazva.

(* Ez egy olyan verem, amely kiürülés után nem hibát ad a pop mûveletre, hanem megvárja, amíg valaki tesz bele egy elemet, és azt adja vissza *) TYPE WaitStack = MUTEX OBJECT elems: ARRAY [1..100] OF INTEGER; top: CARDINAL; arrive: Thread.Condition; METHODS init(): WaitStack := Init; push(e: INTEGER) := Push; pop(): INTEGER := Pop; END; PROCEDURE Init(s: WaitStack): WaitStack = BEGIN s.top := 0; s.arrive := NEW(Thread.Condition); RETURN s; END Init; PROCEDURE Push(s: WaitStack; e: INTEGER) = BEGIN LOCK s DO INC(s.top); s.elems[s.top] := e; END; (* s.top > 0 *) Thread.Signal(s.arrive); END Push; PROCEDURE Pop(s: WaitStack): INTEGER = VAR e: INTEGER; BEGIN LOCK s DO WHILE s.top = 0 DO Thread.Wait(s, s.arrive); END; e := s.elems[s.top]; DEC(s.top); END; RETURN e; END Pop;

15. Példa Lineáris keresés tömbbel

A program bemutatja, hogy hogyan lehet a tömbön keresését végrehajtani Modula3 nyelven.

CONST N = 10; TYPE Array = ARRAY [1..N+1] OF INTEGER; VAR a: Array; x, i: INTEGER; BEGIN a[LAST(a)]:=x; I:=FIRST(a); WHILE x#a[i] DO INC(i) END; IF i=LAST(a) THEN SIO.PutText(“Not found.”); ELSE SIO.PutText(“Found at position: ”); SIO.PutInt(i) END;

16. Példa Euklideszi algoritmus

Az euklideszi algoritmust megvalósítása Modula3 nyelven.

MODULE Loop EXPORTS Main; IMPORT SIO; VAR a,b,x,y,: INTEGER; BEGIN SIO.PutText(“Euclidean algorithm: Enter pairs of numbers\n”); LOOP a:=SIO.GetInt(); IF a<=0 THEN EXIT END; b:=SIO.GetInt(); IF b<=0 THEN EXIT END; x:=a; y:=b; LOOPIF x>y THEN x:= x-yELSIF y > x THEN y:=y-x ELSE EXIT END END; SIO.PutText(“Greatest common divisor = ”); SIO.PutInt(x); SIO.Nl(); END; SIO.PutText(“End of algorithm\n”); END Loop;

17. Példa (Filekezelés)

A nyelv támogatja az állománykezelést, amire az alábbi kód mutat példát. A példa az állományból való olvasást szemlélteti.

MODULE ReadFile EXPORTS Main; IMPORT Rd, FileRD, SIO, SF; CONST FileName = „input.dat”; VAR rd: RD.T; t: TEXT; BEGIN IF SF.FileExists(FileName) THEN rd:=FileRd.Open(FileName); WHILE NOT Rd.EOF(rd) DO t:=Rd.GetLine(rd); SIO.PutText(t); SIO.Nl(); END; Rd.Close(rd); END; END ReadFile.

18. példa (file-kezelés)

A nyelv támogatja az állománykezelést, amire az alábbi kód mutat példát. A példa az állományba való írást szemlélteti.

MODULE Main; IMPORT IO, Rd, Wr; VAR inFile: Rd.T; outFile: Wr.T; num: INTEGER; BEGIN outFile := IO.OpenWrite("numbers.dat"); FOR i := 1 TO 10 DO IO.PutInt(i, outFile); IO.Put("\n", outFile); END; Wr.Close(outFile); inFile := IO.OpenRead("numbers.dat"); REPEAT num := IO.GetInt(inFile); UNTIL num = 10; Rd.Close(inFile); END Main.

19. példa (File-kezelés, kivételkezelés)

A program az állománykezeléskor keletkező hibákat kezeli le.

MODULE FileCopy EXPORTS Main; (* Copy a file of integer values to another file. Example for delaying exceptions: The output file is always closed *) IMPORT SF, SIO; PROCEDURE IntegerCopy() RAISES {SIO.Error} = VAR in:= SF.OpenRead(); (* opens input file *) out:= SF.OpenWrite(); (* opens output file *) count: CARDINAL:= 0; (* counts successfully read values *) BEGIN TRY WHILE NOT SIO.End(in) DO SIO.PutInt(SIO.GetInt(in), 6, out); IF SIO.TermChar(in) = '\n' THEN SIO.Nl(out) END; INC(count); END; (*WHILE*) FINALLY (* always close files *) SIO.PutInt(count); SIO.PutText(" values copied"); SIO.Nl(); SF.CloseRead(in); SF.CloseWrite(out); END; (*TRY FINALLY*) END IntegerCopy; BEGIN SIO.PutText("File copy program\n"); TRY IntegerCopy(); EXCEPT (* any exception handling AFTER closing *) SIO.Error => SIO.PutText("!Error!\n"); END; END FileCopy.

20. példa (Prímteszt)

A program egy prímteszt kódját mutatja be.

MODULE Prim EXPORTS Main; (*21.09.93. LB*) (* Prime number testing with Repeat *) IMPORT SIO; VAR candidate, i: INTEGER; <*FATAL SIO.Error*> (* to supress compiler warnings *) BEGIN SIO.PutText("Prime number test\n"); REPEAT SIO.PutText("Please enter a positive number; enter 0 to quit. "); candidate:= SIO.GetInt(); IF candidate > 2 THEN i:= 1; REPEAT i:= i + 1 UNTIL ((candidate MOD i) = 0) OR (i * i > candidate); IF (candidate MOD i) = 0 THEN SIO.PutText("Not a prime number\n") ELSE SIO.PutText("Prime number\n") END; (*IF (candidate MOD i) = 0 ...*) ELSIF candidate > 0 THEN SIO.PutText("Prime number\n") (*1 and 2 are prime*) END; (*IF candidate > 2*) UNTIL candidate <= 0; END Prim.

21. példa (Párhuzamosság)

A nyelv által szolgáltatott nyelvi elemek használatára mutat példát az alábbi kód.

MODULE ParMax EXPORTS Main; (*22.02.95. LB*) (* Calculating maximum of four numbers in parallel *) IMPORT SIO, Thread; <* FATAL SIO.Error *> (*suppress warnings*) TYPE Closure = Thread.Closure OBJECT a, b, result: INTEGER; (*parameters and result in Closure*) OVERRIDES apply:= Start END; (*Closure*) VAR cl := NEW(Closure); thread: Thread.T; a: ARRAY [1..4] OF INTEGER; (*stores data*) max: INTEGER; (*max stores maximum of all a[i]*) PROCEDURE Start(cl: Closure): REFANY = (*invokes Max*) BEGIN cl.result:= Max(cl.a, cl.b); (*result stored in Closure*) RETURN NIL (*return value not used*) END Start; PROCEDURE Max(a, b: INTEGER): INTEGER = (*maximum of 2 numbers*) BEGIN IF a > b THEN RETURN a ELSE RETURN b END END Max; BEGIN SIO.PutLine("Type in four numbers, please"); FOR i:= 1 TO 4 DO a[i]:= SIO.GetInt() END; cl.a:= a[1]; cl.b:= a[2]; (*parameters set in Closure*) thread:= Thread.Fork(cl); (*created thread starts; computes Max(a[1], a[2])*) max:= Max(a[3], a[4]); (*main thread computes maximum of rest*) EVAL Thread.Join(thread); (*partial results available*) max:= Max(max, cl.result); (*final result computed*) SIO.PutText("Max = "); SIO.PutInt(max); SIO.Nl() END ParMax.

22. példa (Adattípusok - verem)

Egy példányosítással létrehozott verem kódját mutatja be az alábbi példa.

INTERFACE Stacks; (*14.07.94 RM, LB*) (* Abstract generic stack. *) TYPE T <: REFANY; (*type of stack*) ET = REFANY; (*type of elements*) PROCEDURE Create(): T; (*creates and intializes a new stack*) PROCEDURE Push(VAR stack: T; elem: ET); (*adds element to stack*) PROCEDURE Pop(VAR stack: T): ET; (*removes and returns top element, or NIL for empty stack*) PROCEDURE Empty(stack: T): BOOLEAN; (*returns TRUE for empty stack*) END Stacks. MODULE Stacks; (*14.07.94 RM, LB*) (* Implementation of the abstract, generic stack. *) REVEAL T = BRANDED REF RECORD info: ET; next: T; END; (*T*) PROCEDURE Create(): T = (*creates and intializes a new stack*) BEGIN RETURN NIL; (* a new, empty stack is simply NIL *) END Create; PROCEDURE Push(VAR stack: T; elem:ET) = (*adds element to stack*) VAR new: T := NEW(T, info:= elem, next:= stack); (*create element*) BEGIN stack:= new (*add element at top*) END Push; PROCEDURE Pop(VAR stack: T): ET = (*removes and returns top element, or NIL for empty stack*) VAR first: ET := NIL; (* Pop returns NIL for empty stack*) BEGIN IF stack # NIL THEN first:= stack.info; (*copy info from first element*) stack:= stack.next; (*remove first element*) END; (*IF stack # NIL*) RETURN first; END Pop; PROCEDURE Empty(stack: T): BOOLEAN = (*returns TRUE for empty stack*) BEGIN RETURN stack = NIL END Empty; BEGIN END Stacks.