Az OCCAM programozási nyelv

Típusok, típuskonstrukciók

Egyszerű adattípusok

BOOL

Logikai típus true és false értékekkel.

BYTE

Byte típus, tehát egész szám 0 és 255 között.

INT

Előjeles egész típus, hossza implementációfüggő.

INT16

Előjeles egész típus -32768 -tól 32767 -ig.

INT32

Előjeles egész típus 32 biten ábrázolva.

INT64

Előjeles egész típus 64 biten ábrázolva.

REAL32

Valós szám előjellel, 8 bites exponenssel és 23 bites számmal.

REAL64

Valós szám előjellel, 11 bites exponenssel és 52 bites számmal

Mutatók

Az OCCAM nyelv nem használ mutató típust.

Típuskonstrukciók

1. Tömb típus(ok)

Lehetőségünk van tömböket létrehozni bármely egyszerű típusból vagy nevezett típusból. A tömb indexei a nemnegatív egész számok lehetnek. Többdimenziós tömböket is készíthetünk, sőt, a dimenziók számára nincs felső korlát. Pl.:

[4][5] INT
egy 4x5-ös integer tömb.

Nevezett típus létrehozása tömbből:

DATA TYPE MATRIX IS [10][10] INT :
egy 10x10-es integer mátrix típus, MATRIX névvel.

Az indexhatár lehet kifejezés is, ha kiértékelhető fordítási időben és pozitív egész értékű. Két tömb típusa megegyezik, ha ugyanazok az indexhatárai és az alaptípusuk megegyezik.

Tömbök használata: van indexhatár-ellenőrzés (az index nem lehet negatív, és 0..n-1 közé kell hogy essen). Pl.:

data[0] (data [5]REAL32);
data[5][0] (data [9][10]REAL32);
Lehet a tömb egyes szegmenseire is hivatkozni.(ld. Később)

2. Rekord típus

Egy rekord típus valamilyen, akár különböző típussal rendelkező mezőkből áll, így logikai egységbe foglalhatóak összetartozó egységek. Pl.:

DATA TYPE COMPLEX IS
RECORD
REAL real :
REAL imag :
:

Ez egy komplex számot reprezentáló rekord típus megvalósítása OCCAM-ban. Egy rekord mezői lehetnek egyszerű típusok, nevezett típusok és ezekből képzett tömbök is. Rekord típusú literálok képzésére van lehetőségünk, ezeket egy rekordnak értékül lehet adni. Feltétele, hogy a rekord mezőinek típusának megfeleljenek a literál mezői. Pl.:

[0.0(REAL), 1.0(REAL)] (COMPLEX)

Az egyes mezőkre külön lehet hivatkozni, eltérő szintaxissal, mint c-ben: Pl.: COMPLEX c;

c[real] = 21 // a c complex szám valós része legyen 21.

A rekordok és a tömbök tetszőleges mélységben egymásba ágyazhatók: Pl.:

installation[i][size][width] (tömbben rekord, és annak az egyik mezője egy újabb rekord.)

Lehetőségünk van létrehozni üres rekordot is:

DATA TYPE NONE
RECORD
:

Ekkor a típus NONE-lesz, a példányai pedig ilyen alakúak lehetnek: [](NONE)

3. Unió típus (3-as verziótól)

Occam-ban lehetőségünk van unió típust is létrehozni, amit a legelterjedtebb nyelvek nem támogatnak, cask közvetett módon öröklődéssel.

Az unió segítségével többek között több reprezentációt adhatunk meg egy típushoz, ezzel is segíti a nyelv a platformfüggetlenséget. Pl.:

DATA TYPE CARTESIAN
RECORD
REAL32 real, imag :
:
DATA TYPE POLAR
RECORD
REAL32 mod, arg :
:
DATA TYPE COMPLEX
UNION
CARTESIAN c :
POLAR p:
:

Itt a complex típusnak kétféle ábrázolási módot engedünk meg. Ekkor egy COMPLEX x változónak így lehet értéket adni:

COMPLEX x :
x := (c :- [0.0(REAL32), 1.0(REAL32)](CARTESIAN))(COMPLEX)

4. Variáns rekord, halmaz típuskonstrukció

Ezek nem állnak rendelkezésre OCCAM-ban.

5. Táblák, sztringek

A táblák az OCCAM nyelv speciális literáljai, melyek egy adott típusból való elemek tömbjei. A sztring egy speciális tábla, ahol az alaptípus byte. Pl.:

A sztringeket írhatjuk több sorba is, tehát nem kell egy hosszú sztringet besűríteni egy sorba, de ekkor a sor végére, és a következő sor elejére * -ot kell írni. A sztring második sorának beljebb kell kezdődnie, mint ahol a sztringdefiníció kezdődött. Pl.:

occam := "Beware the jabberwock my son, the jaws that bite, the*
       * claws that catch, beware the jubjub bird, and shun the*
       * frumious bandersnatch."

6. Csatorna típus

Bővebb leírás itt található.

7. Timer típus

Bővebb leírás itt található.

Altípusképzés

Igazi altípusképzésről nem beszélhetünk, viszont lehetőség van ún. nevezett típusok létrehozására, melyek ugyanazzal az értékkészlettel rendelkeznek, mint a típus, amiből képezzük őket.

DATA TYPE COST IS REAL32 :"
DATA TYPE WEIGHT IS REAL32 :"

Hasznos lehet ez pl. olyankor, ha több különböző változó ugyanazzal az egyszerű típusú értékkészlettel rendelkezik. Pl., ha van egy COST és egy WEIGHT típusú változónk, biztosak lehetünk benne a típusellenőrzés miatt, hogy COST nem lett WEIGHT típusúnak értékül adva, vagy egy függvénynek nem COST-ot adunk át, mikor WEIGHT-et vár.
Érdekesség:

DATA TYPE MONEY IS INT64 :"
MONEY a :"
DATA TYPE MONEY IS INT64 :"
MONEY b :"

Ebben az esetben a és b típusa különbözik, mert minden új típus bevezetésénél (akár az eddigivel megegyező nevű) kapunk egy új típust.

Típuskonverzió

A nyelvben automatikus típuskonverzió nincs, viszont van lehetőség típuskonverzióra, mint operátor, nem tömb numerikus típusokra. Ha a konverziókor csökken a számunk pontossága, lehetőségünk van a TRUNC kulcsszó használatára, ami csonkolja a számot, vagy a ROUND használatára, amely a kerekítésnek felel meg.
Logikai értékekre:

BOOL 1

 megfelel a true-nak

BOOL 0 

 megfelel a false-nak

INT TRUE

 1

INT FALSE

 0

Ha integer vagy byte és valós számok között konvertálunk vagy fordítva, meg kell mondanunk, hogy kerekítéssel vagy csonkolással működjön a konverzió. Pl.: legyenek n, m INT64 változók, n=255 és m=3, ekkor:

BYTE n

 egy byte értéket készít, 255

REAL32 ROUND n

 REAL32, értéke 255.0

REAL64 TRUNC n

 REAL64, értéke 255.0

REAL64 ROUND (n*m)

 REAL64, értéke 765.0

(REAL64 ROUND n) * (REAL64 ROUND m)

 REAL64, értéke 765.0

Rekord típusok „konverziójára” is van lehetőség: Pl:

[550, 1000](RECTANGLE) // az 550,1000 –ből egy RECTANGLE típusú rekordot csinál.

Változók

Minden változónkat deklarálnunk kell használat előtt, vagyis hozzárendelni egy típust a változóhoz. (Az OCCAM szigorúan típusos nyelv.) Pl.:

BOOL flag :
REAL32 x, y :
[5] INT ujjak :

Deklaráció

Ugyanúgy megy, mint c-ben, a változónak kezdőértéket nem adhatunk:
<változó deklaráció> ::= <típusnév> <változó nevek>{,<változó nevek>}:
pl .:

INT i, j, k :

Konstansdeklarációk

Az OCCAM biztosít lehetőséget konstansok deklarálására a következőképp:
VAL <Adattípus> <név> IS <kifejezés>:
Itt a név változó nem kaphat új értéket, típusa Adattípus lesz, a kifejezésnek pedig futásidőben kiértékelhetőnek kell lennie. Például:

VAL INT Min IS (Max-Max) + 1:

Szegmensek

Lehetőségünk van tömbökből több elemre hivatkozni, ezt hívjuk most szegmensnek. A szegmens maga is egy tömb, nulla vagy több elemmel. Töbök és szegmensek, ha típusuk megfelelő, egymásnak értékül adhatóak. Pl.:
legyenek [9] INT clock , [8][9][10]REAL32 data !
Ekkor :

BYTE n

 egy byte értéket készít, 255

REAL32 ROUND n

 REAL32, értéke 255.0

REAL64 TRUNC n

 REAL64, értéke 255.0

REAL64 ROUND (n*m)

 REAL64, értéke 765.0

(REAL64 ROUND n) * (REAL64 ROUND m)

 REAL64, értéke 765.0

Változók láthatósága

A változó és a típusok hatóköre: Kezdődik a típus vagy a változó deklarációját lezáró ’:’ utáni sor elejétől és a blokk végéig tart. Külső blokkban lévő változót felül lehet deklarálni belső blokkban, ekkor az újbóli hivatkozás a változóra már a belső blokkban deklaráltra fog vonatkozni. Nincs lehetőség a külső blokkbeli változóra hivatkozni.
Pl.:

INT x : -- integer x
SEQ -- hatóköre az integer x-nek
    dm ? x --
    ALT --
    REAL32 x : -- REAL32 x elrejti az integer x-et
    rs ? x -- hatóköre az REAL32 x-nek
    ... --Hatókör vége
    dm ? y --
    ... --
    ... --

Nevek rövidítése

Lehetőségünk van a programunkban használt nevek rövidítésére. Ld. még a paraméterátadási módoknál . Pl.:

clock FROM 0 FOR 2

 clock első két komponense, típusa [2] INT

data FOR n

 data első n komponense, típusa [n][9][10] REAL 32

data FOR m FOR 0

 üres szegmens, típusa [0][9][10] REAL 32

Amíg az átnevezés hatóköre tart, addig nem lehet használni az eredeti változót, amit átneveztünk. Ez hatékonysági megfontolások miatt lett így specifikálva.
Pl.:

x IS y[0]
SEQ
    x := y[3] -- ez nem megengedett
    z IS y[3] --ez megy
this IS y[i]:
next IS y[i+1]:
SEQ
    …
    i := i+1 -- nem megengedett, mert az i használt az y szelektálására egy belső scope-ban
i := i+1 -- ebben a scope-ban már helyes

Lehetőségünk van nemcsak változók, hanem értékek elnevezésére is. Ld: Konstansdeklarációk .

Kifejezések, operátorok

A kifejezések operandusokból, operátorokból és zárójelekből állhatnak, kiértékelés után egy értékkel és egy típussal rendelkeznek. Az operandusok lehetnek változók, literálok, egy tábla, vagy egy újabb kifejezés zárójelek közt.

Operátorok

OCCAM-ban nincs operátor precedencia, ezért a kiértékelési sorrendet zárójelekkel kell meghatározni. Az operátorok:

 +

 összeadás

 >>

 balra tolás

 -

 kivnás

 << 

 jobbra tolás 

 *

 szorzás

 AND 

 és

 /

 osztás

 OR

 vagy

 \REM

 maradék

 NOT

 nem

 PLUS

 modulo összeadás

 =

 egyenlő

 MINUS

 modulo minusz

 <>

 nem egyenlő

 TIMES

 modulo osztás

 >

 nagyobb

 /\BITAND

 bitszintû és

 <

 kisebb

 \/BITOR

 bitszintû vagy

 <=

 kisebb egyenlő 

 ><

 bitszintû kizáró vagy 

 >=

 nagyobb egyenlő 

 ~

 bitszintû nem 

 AFTER 

 később mint

 SIZE

 tömb mérete

 BYTESIN 

 tömbelem mérete byte-ban 

Adattípusok operátorai:

 MOSTNEG 

 a típus legkisebb negatív értéke 

 SIZE 

 a tömb mérete (integer) 

 MOSTPOS

 a típus legnagyobb pozitív értéke

 BYTESIN 

 egy rekordban hossza byte-ban 

 OFFSETOF

 egy rekord mező eltolása byte-ban 

 

 

Konverziók

1. Retyping

A retyping (újratípusozás) konverzió egy szintaktikus specifikáció, (definíció) amely az egyik adattípust egy bit minta segítségével egy másikká alakítja a saját hatókörén belül. Ez a konverzió háromféle lehet:

2. Változók és kifejezések konvertálása

Formális definíció:

Definition ::= specifier name RETYPES variable
| VAL specifier name RETYPES expression

A retyping (újratípusozás) konverzió függ a számítógépbeli pontos ábrázolástól. Annak érdekében vezették be, hogy hordozható legyen a program a különböző architektúrák között. Az újratípusozás konverzió egy bit minta segítségével leszűkíti a típust, és ennek az új típusnak ad egy új nevet.
Pl.:
kifejezés értékét konvertáljuk:

VAL REAL32 root.NaN RETYPES #7F840000(INT32) : VAL INT64 pattern RETYPES 42.0(REAL64) :

A második példában a 42.0 real típusú változót konvertáljuk int64-é, ami ezután pattern névvel hivatkozható. A retyping konverzió egy új típust specifikál egy meglévő változóból ugyanazzal a hosszal.
Pl.:
Változót konvertálunk:

INT64 condition :
...
SEQ
[8]BYTE state RETYPES condition :
...

Ebben a példában a condition változóra state névvel, mint egy 8 hosszú byte-okból álló tömbhöz lehet hozzáférni a SEQ blokkon belül.
A változót, amit újratípusoztunk nem lehet használni azon a blokkon belül, ahol ezt megtettük.
Ha a retyping konverziónál a céltípus egy tömb, akkor annak a tömbnek adhatunk üres dimenziót, és majd a fordító meghatározza, hogy mekkora legyen a tömb az átkonvertálandó típus függvényében, ezt meg tudja tenni, mivel az OCCAM szigorúan típusos nyelv.
Pl.:

[10]REAL64 w :
SEQ
[]BYTE bw RETYPES w :
-- here we can send the binary array to a file
...
[10][]INT iw RETYPES w :
-- here we can look at each REAL as a bit pattern
...

3. Csatorna protokolljának konvertálása

Formális definíció:

Definition ::= specifier name RETYPES channel :

A csatornák protokolljára azért van szükség, hogy a fordító ellenőrizni tudja a kimenő és a bemenő üzenetek típusát a csatornán. Néha nélkülözhetetlen elfogadni egy csatornára más protokollokat is, mint amit eredetileg definiáltunk hozzá.
Pl.:

PROC real.buffer (CHAN OF REAL32 rin, rout)     REAL32 r :
    WHILE TRUE
       SEQ
       rin ? r
       rout ! r
:
PROTOCOL COMPLEX IS REAL32; REAL32 :
PROC generate.complex (CHAN OF COMPLEX c)
   ... process outputting complex values on c
:
PROC consume.complex (CHAN OF COMPLEX c)
   ... process inputting complex values on c
:
CHAN OF COMPLEX cin, cout :
PAR
    generate.complex (cin)
    CHAN OF REAL32 crin RETYPES cin :
    CHAN OF REAL32 crout RETYPES cout :
    real.buffer (crin, crout)
    consume.complex (cout)

Ez egy triviális példa, ami néha felmerül a programozás során. A real.buffer nevű procedúra egy általános célú eljárás és nem felülírható. A generate.complex nevű eljárás csak az output-ot írja complex számokkal, amelyek párok a COMPLEX protokoll alkalmazásával. A cin, cout COMPLEX csatornákat átkonvertáljuk REAL típusúvá és ezt buffereljük, majd utána egyéb konverzió nélkül fel tudjuk dolgozni a bufferelt értékeket COMPLEX típusúként.

4. Konverzió (reshaping)

Formális definíció:

Definition ::= specifier name RESHAPES variable
    | VAL specifier name RESHAPES expression
    | specifier name RESHAPES channel

Ez egy speciális retyping konverzió, a tömbök aldimenzióinak átvariálására valók.
Pl.:

VAL [2][6]REAL32 nums IS [[0.0, 1.0, 2.1, 3.1, 4.2, 5.2] [6.3, 7.3, 8.4, 9.4, 10.5, 11.5]] :
SEQ
    -- itt a nums két tömb, egyenként hat elemmel
    ...
    VAL [6][2]REAL32 nums.6.2 RESHAPES nums :
    SEQ
    -- itt a nums hat tömb egyenként két elemmel
    ...
    VAL [12]REAL32 nums.12 RESHAPES nums :
    SEQ
    -- itt a nums egy 12 elem hosszú egydimenziós tömb
    ...
    VAL [2][2][]REAL32 nums.2.2. RESHAPES nums :
    SEQ
    -- itt a nums egy három dimenziós tömb
    ...