Success és Failure
A Success és a Failure jelzések, amelyek nem sorolhatók az adattípusok közé. Egy utasítás (statement) végrehajtása alatt jelennek meg. Például az INPUT és OUTPUT változók segítségével file-ból/ba is tudunk olvasni/írni. File vége jel olvasása esetén az INPUT változó nem kap értéket, hanem failure lesz az eredmény.
Egy SNOBOL program utasítások sorozatából áll, a végrehajtás során soronként megy végig az utasításokon.
Az utasítások alakja:
címke törzs :GOTO
-
cimke
Az utasítás neve. A sor első karakterén, számmal vagy betűvel kell kezdődnie, nem lehet benne szóköz vagy tabulátor. Opcionális, ha kihagyjuk, akkor az utasítás első karakter pozícióján szóköznek vagy tabulátornak kell lennie.
-
:GOTO
Opcionális. A normális szekvenciális végrehajtást megtöri. Utasítás végén van, kettősponttal kezdődik, a kettőspontot meg kell előznie egy white space-nek. Alakja lehet:
- :(címke)
-
:S(címke)
ha az utasítás törzsben levő kifejezés 'success', akkor a címkére ugrunk
-
:F(címke)
ha az utasítás törzsben levő kifejezés 'failure', akkor a címkére ugrunk
-
:S(címke1) F(címke2)
A címke - nem meglepő módon - azt a helyet mutatja meg, hogy a program végrehajtása hova ugorjon a jelen utasítás befejezte után. Az S illetve az F azt jelzi, hogy success vagy failure jelzés esetén kell a címkére ugrani (ellenkező esetben jön a következő sor, mint rendesen), ha nincs S illetve F, akkor feltétel nélkül ugrik. Lényeges megjegyezni, hogy ezekkel lehet ciklust, elágazást megvalósítani.
Egy egyszerű program:
N = 0
COPY OUTPUT = INPUT :F(DONE)
N = N + 1 :(COPY)
DONE OUTPUT = 'THERE WERE ' N ' LINES'
END
Az 1. sor az N értékét 0-ra állítja.
A 2. sorban, ha van helyes input érték (nem nyomtunk 'CTRL+Z'-t vagy még nem vagyunk a bemeneti fájl végén), akkor azt visszhangozza a képernyőre vagy fájlba írja, és mivel volt helyes input (success, és nem failure), ezért a következő sorra ugrik a végrehajtás.
A 3. sorban N értéke 1-gyel nő, és irány a COPY címkés sor.
Ha nincs helyes input érték, akkor a végrehajtás a 4. sorra ugrik, ahol az OUTPUT változó megkapja az N értékét.
Ennek a programnak a 2. és 3. sora így együtt hasonlít az elöltesztelő (while) ciklusra.
Függvények
Egy függvény eredményének két része van:
- a success vagy failure jelzés,
- success esetén a függvény visszatérési értéke, amely bármilyen adattípus lehet.
FUGGVENY_NEVE(ARG1, ARG2, ..., ARGn)
Ha nem adunk meg megfelelő számú argumentumot, akkor a fordító a hiányzó argumentumokat null stringgel helyettesíti és így hívja meg a függvényt.
Kétféle függvény van:
-
predikátumfüggvény
sikeres végrehajtás esetén null stringet ad vissza.
-
egyéb függvények
más programozási nyelvek függvényeihez hasonlóak.
Természetesen mi is definiálhatunk új függvényeket, mint ezt az operátoroknál is megtehettük.
Predikátumfüggvények
-
IDENT(S,T)
S és T azonosak.
-
DIFFER(S,T)
S és T különböző, az IDENT ellentétje.
-
EQ(X,Y)
X és Y integerek egyenlőek.
-
NE(X,Y)
X és Y integerek nem egyenlőek.
-
GE(X,Y)
X integer nagyobb vagy egyenlő, mint Y.
-
GT(X,Y)
X integer nagyobb mint Y.
-
LE(X,Y)
X integer kisebb vagy egyenlő mint Y.
-
LT(X,Y)
X integer kisebb mint Y.
-
INTEGER(X)
X integer, vagy string, amit integerré tud konvertálni.
-
LGT(S,T)
S string lexikálisan nagyobb mint T string.
Néhány egyszerű programrészlet:
N = 3
EQ(N, 3)
* Success
IDENT(3, "3")
* Failure -- integer és string
INTEGER('47')
* Success
LGT('ABC', 'ABD')
* Failure
N = LT(N,10) N + 1 :S(LOOP)
* ha 10-nél kisebb N értéke, akkor N 1-gyel növekszik,
* LT(N,10) ekkor a null string, és ezt konkatenáljuk N + 1-hez
Egyéb függvények
-
DATE()
visszatér egy stringként az aktuális idővel és dátummal.
-
DUPL(S,N)
az S stringet N-szerezi.
-
REMDR(X,Y)
X / Y maradéka.
-
REPLACE(S1,S2,S3)
az S1 stringbe behelyettesíti S3-at az S2 alapján.
-
SIZE(S)
visszatér S string hosszával.
-
TRIM(S)
visszatér S stringgel a string végén lévő szóközök nélkül.
Néhány egyszerű programrészlet:
OUTPUT = 'Az aktualis datum és ido: ' DATE()
* Az aktualis datum és ido: 02-07-06 01:05:08.93
OUTPUT = DUPL('ABC', 5)
* ABCABCABCABCABC
OUTPUT = TRIM('TRAILING BLANKS ') 'GONE'
* TRAILING BLANKSGONE
OUTPUT = REPLACE('spoon','so','SO')
* SpOOn -- az S2-ben szereplő karaktereket cseréli ki S3 alapján
Megjegyzés: a SNOBOL4+ már számos új beépített függvénnyel rendelkezik. link
Függvény definiálás
A beépített DEFINE függvénnyel tudunk definiálni egy új függvényt. Hívjuk az új függvényünket SHIFT-nek, ami egy string karaktereit rotálja. A függvényben megadhatjuk, hogy a string elejéről mennyit tegyen a végére. Például, a SHIFT('ENGRAVING',3) visszatér a 'RAVINGENG' stringgel. A függvényünknek két formális paramétere lesz: az S (string) és az N (karakterek száma). A függvény definíció tehát így néz ki:
DEFINE('SHIFT(S,N)')
Más nyelvekkel ellentétben a SNOBOL4-ben a függvény definíciók nem fordítási, hanem futási időben értékelődnek ki.
Már deklaráltuk a függvény nevét és a formális paramétereit, de még nem implementáltuk, meg kell írni a függvény törzsét is. Nagyon egyszerű szabályt ad erre a SNOBOL4, amikor a függvény előkerül egy utasításban, akkor a SHIFT nevű címkére ugrik a vezérlés. Persze a vezérlést majd vissza kell adni a hívónak, erre szolgál a RETURN címke.
A függvény törzse ezek után:
SHIFT S LEN(N) . FRONT REM . REST
SHIFT = REST FRONT :(RETURN)
Az 1. utasítás az S stringet két részre osztja, az első N hosszú stringet a FRONT nevű változóba teszi, míg a maradékot a REST-be.
A 2. utasítás a REST és a FRONT-ot összekonkatenálja, és a függvény visszatér ezzel az értékkel.
Az utasítás GOTO része alapján visszatér a hívóhoz a vezérlés.
Mi van akkor, ha pl. N-nek az S string hosszánál nagyobb értéket adunk? Azzal bíza bajban leszünk, de erre is van kibúvó a SNOBOL-ban. Az FRETURN címke alapján a függvény visszatér failure jelzéssel a hívóhoz:
SHIFT S LEN(N) . FRONT REM . REST :F(FRETURN)
SHIFT = REST FRONT :(RETURN)
Függvény és operátor szinonimák
Szinonimákat az OBSYN függvénnyel lehet megadni, melynek 3 argumentuma van:
OPSYN(new name, old name, i)
A 'new name' definiálja az 'old name' egy szinonimáját. A 3. argumentum értéke lehet 0, 1, vagy 2, attól függően, hogy függvénynek, unáris operátornak, vagy bináris operátornak szeretnénk szinonimát definiálni.
Néhány egyszerű példa:
* függvény szinonima
OPSYN('LENGTH', 'SIZE', 0)
OUTPUT = LENGTH('RABBIT')
* 6
* operátor szinonima
OUTPUT = 1 # 1
* Execution error #5, Undefined function or operation
OPSYN('#', 'DIFFER', 2)
OUTPUT = 1 # 2
* Failure -- nincs DIFFER operátor a SNOBOL-ban
OPSYN('PLUS', '+', 2)
OUTPUT = PLUS(4, 5)
* 9
Fájl és egységszám
- A megtévesztések elkerülése végett: az Input és Output nevek változót és függvényt is jelölnek.
- A SNOBOL egyszerre 16 file-t tud kezelni.Ezek között lehetnek disk file-ok és device-ok is (pl. nyomtató).
-
Minden file-t egy "egység számmal" (unit number) azonosít. Vannak előredefiniált egységszámok, pl.
a billentyűzeté (ami az Input változónak felel meg) az 5,
a képernyőé (Output változó) 6.
- A string az egyetlen adattípus, amit tud file-ból olvasni/írni. Output esetén automatikusan konvertál stringgé.
- Az Input és Output függvény arra jó, hogy egy-egy "egység számot" egy változóhoz vagy egy adott file-hoz csatoljunk.
File és "egység szám" összekapcsolása:
Az Input függvény használata
INPUT('variable',unit,length,'filename')
Paraméterek:
-
variable
ezentúl ezt a változót az Input változóhoz hasonlóan használjuk a 'filename' nevű file-ból való olvasásra,
-
unit
ez az egységszám, amit file-hoz rendel,
-
length
sor hossza (alapértelmezett értéke 80),
-
filename
a file neve; ha nincs megadva, akkor a parancssorban keres unit egységszámú file-t.
A függvény visszatérési értéke:
- sikeres végrehajtás esetén: null string
- sikertelen végrehajtás esetén: nincs (ekkor nincs ilyen file vagy nem tudja megnyitni)
Néhány egyszerű programrészlet:
INPUT('READLINE', 1, , 'TEXT.IN') :S(OK)
OUTPUT = 'Could not find file' :(END)
OK . . .
* TEXT.IN file-t megnyitja olvasásra az 1-es egységszámmal
* parancssorban: /1=TEXT.IN
INPUT('READLINE', 1) :S(OK)
OUTPUT = 'Could not find file' :(END)
OK . . .
* ugyanaz, mint az előző
LINE = READLINE :F(END.OF.FILE)
File vége észlelésénél failure jelet kap (a művelet sikertelen). Minden file-végénél megáll a beolvasással. Ha egy sor hosszabb a megadott hossznál (a fenti length érték), akkor a sor végét levágja. Az end-of-file karaktert nem veszi bele a stringbe.
Ha a sor rövidebb a megadottnál, akkor szóközökkel tölti fel a sor végét a megadott hosszig. Ez néhol zavaró lehet, ezért van szükség egy szóközlevágó függvényre (TRIM), amely a string végén levő szóközöket eltávolítja:
LINE = TRIM (READLINE)
Az Output függvény használata
OUTPUT('variable',unit,length,'filename')
A függvény paraméterei az Input függvényével megegyeznek.
A függvény visszatérési értéke:
- sikeres végrehajtás esetén: null string
- sikertelen végrehajtás esetén: nincs (ekkor nincs ilyen file vagy nem tudja megnyitni)
Ha a sor, amit ki akarunk írni, hosszabb, mint a length értéke, akkor több sorba tördeli. Minden sor végére CR LF-et rak (sor vége).
Az I/O alapértelmezett értékeket meg lehet változtatni a parancssorban: pl. I=f1 /O=f2. Így az Input változóhoz f1-et, az Outputhoz f2 file-t rendeli.
Egy egyszerű program file-ok használatára:
* hossz.sno tartalma
LOOP S = TRIM(INPUT) :F(END)
OUTPUT = SIZE(S) ' ' S :(LOOP)
END
A program meghívása:
parancssor> vsnobol4 hossz /i=text /o=text
A program a text.in input file minden sorának hosszát és a megfelelő sorát egymás mellé írva soronként kiírja a text.out nevű fájlba.
A program 1. sora az aktuális bemeneti sor végén levő szóközöket levágja.
A 2. sor egy egyszerű konkatenáció. Addig folyik a beolvasás, amíg a file-nak nincs vége.
Kulcsszavak
Az Input/Output megengedte, hogy a programunk kommunikáljon a külvilággal. De jó lenne, ha programunk magával a SNOBOL rendszerrel is tudna kommunikálni. A kulcsszavak által magunk tudjuk módosítani a SNOBOL viselkedését, és információkat szerezhetünk a rendszerről. A kulcsszavak '&amap;' jellel kezdődnek, melyet egy alfabetikus név követ. Az utasításokban hasonlóképpen tudjuk használni őket, mint a változókat.
-
&TRIM
törli a string végén levő szóközöket, a &TRIM = 1 hatása azonos az előző példában látott TRIM(INPUT)-éval, a SNOBOL4 programok 1. sora gyakran a '&TRIM = 1'-gyel kezdődik.
-
&MAXLNGTH
maximális string hossz, alapesetben 5000 hosszú lehet egy string, ezt megváltoztathatjuk.
-
&DUMP
debugolásra használható, ha pozitív értéket kap, akkor a változó neveket ábécé sorrendben írja ki, negatív érték esetén nem rendez.
-
&ALPHABET
komplett karakter halmaz.
-
&LCASE
kisbetűk, "abcdefghijklmnopqrstuvwxyz".
-
&UCASE
nagybetűk, "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
INCLUDE utasítás
A SNOBOL4+ tartalmazza az '-INCLUDE' vezérlő utasítást, ami lehetővé teszi, hogy a program file-ba belevegyük egy másik file kódját. Például nézzük a következő programot:
* main.sno
OUTPUT = 'Here is the first line,'
-INCLUDE "subprog.sno"
OUTPUT = 'and here is the third line.'
END
* subprog.sno
OUTPUT = 'this is in the subprogram, '
* a main.sno ekvivalens a következőkkel
OUTPUT = 'Here is the first line,'
OUTPUT = 'this is in the subprogram,'
OUTPUT = 'and here is the third line.'
END