ÚVOD DO PROGRAMOVACÍHO
JAZYKA REXX

 

 

Rexx se používá  jako makrojazyk editorů a textových procesorů; jako povelový jazyk databázových, dialogových, operačních systémů a systémů řízení počítačové sítě; jako jazyk pro tvorbu skriptů umožňujících automatizovat a integrovat aplikace. V tomto článku bych ale chtěl ukázat, že Rexx je také zajímavý programovací jazyk. Jako formu výkladu jsem zvolil svérázný úvod do jazyka, ve kterém se soustředím především na neobvyklé výrazové prostředky, nevyskytující se ve svém souhrnu v jiném programovacím jazyce.

Místo kapitoly "Typy, konstanty a proměnné"

V programech napsaných v jazyce Rexx chybí deklarace a typy, protože:
  • veškeré údaje jsou znakové řetězce proměnné délky;
  • symbol je vyhlášen za jméno proměnné, až když je mu přiřazena hodnota při provádění programu;
  • operandem aritmetické operace je řetězec znaků, který je zápisem desítkového čísla s případnými mezerami na začátku a na konci;
  • přesnost výpočtu - počet platných číslic výsledku aritmetické operace - lze zadat příkazem numeric digits.

Přesnost výpočtu

Kolik číslic má  číslo N-faktoriál a jak vypadá  prvních třináct číslic? Pro N rovno 16 nejprve vypočteme číslo 16!, pak sečteme počet znaků v zápise čísla a nakonec přečteme prvních třináct znaků zleva. Ale co když je N rovno 1000? Odpověď vypíše na obrazovku následující program příkazy say.

/* Rexx program UHLER */
Vysledek = NFAKT(1000)
say "Počet číslic =" LENGTH(Vysledek)
say "Prvních třináct číslic =" LEFT(Vysledek, 13)

V zápise programu je mezera, například za konstantou "Počet číslic =", operátorem operace zřetězení s vložením jedné mezery. Program je tak krátký, protože jsem využil funkce LEFT a LENGTH, které jsou součástí jazyka a nazývají se proto vestavěné (built-in). Ale funkce NFAKT není vestavěná   a pokud tuto funkci nenapsal už někdo před námi a není při provádění programu UHLER dostupná, musíme si ji napsat sami.

/* Rexx funkce NFAKT - výpočet faktoriálu */
N = ARG(1)
numeric digits 3000
Nfaktorial = 1
do J = 2 to N
  Nfaktorial = Nfaktorial * J
end
return Nfaktorial

Funkce uložená  na disku jako samostatný soubor, se nazývá  vnější. Připojíme-li za poslední řádek programu UHLER následující dva řádky:

exit
NFAKT: procedure

a dále text funkce NFAKT, bude NFAKT funkcí vnitřní. Příkaz exit explicitně ukončuje provádění hlavního programu, které by jinak pokračovalo chybným vykonáním příkazu procedure s návěštím NFAKT; příkaz procedure bez klíčového slova expose určuje, že volající program a volaná  funkce nesdílí žádné proměnné. Spustíme-li program UHLER, objeví se na obrazovce:

Počet číslic = 2568
Prvních třináct číslic = 4023872500770

V řešení čtvrtého cvičení v odstavci 1.2.5 knihy D. E. Knutha The Art of Computer Programming, díl 1., čteme: Přesnou hodnotu 1000! určil jako první H. S. Uhler po mnohaletých trpělivých výpočtech na kalkulátoru. Výsledek uveřejnil v časopise Scripta Mathematica 21 (1955), ss. 266-267 a začíná: 402 38 726 00 770 ...

Cvičení 1

Operátorem operace umocnění je **. Kolik číslic má číslo devět na devátou na devátou, tj. 9**(9**9)?

Zpracování slov

Rexx definuje slovo jako neprázdný řetězec znaků, který neobsahuje mezeru. Práci se slovy usnadňují vestavěné funkce a příkaz parse. Například funkce WORDS(řetězec) vrací počet slov řetězce. Můžeme si to ověřit, zadáme-li jako argument větu, jednoznačně definující číslo K takto: Buď K nejmenší přirozené číslo, které nelze definovat méně než čtrnácti českými slovy. Výsledek - pointa Berryho antinomie ze skript E. Fuchse Teorie množin (UJEP Brno, 1974) - nás donutí slova ve větě opravdu spočítat. Ale co když oddělovačem slov bude jiný znak než mezera? Předpokládejme, že oddělovač (právě jeden znak) je uložen v proměnné Oddelovac. Pak následující fragment programu vypíše všechna slova zadaného textu v tomto obecném případě.

Om = Oddelovac || " "; Mo = REVERSE(Om)
Text = TRANSLATE(Text, Om, Mo)
do J = 1 to WORDS(Text)
  say TRANSLATE(WORD(Text, J), Om, Mo)
end

Vestavěná  funkce WORD(řetězec, n) vrací n-té slovo řetězce. Symbol || je operátor operace zřetězení bez vložení mezery. A funkce REVERSE? Vzpomeňte si na Příběh z Rozeklaných hor od Edgara Allana Poa; ... - vždyť Bedlo bez e - co to je jiného než Oldeb obráceně? Následující program zobrazí na displeji OLDEB.

/* BEDLO */ say REVERSE(LEFT(Bedloe, 5))

Funkce TRANSLATE(řetězec, šifrovaná_abeceda, abeceda) zamění každý v řetězci se vyskytující znak z abecedy odpovídajícím znakem z šifrovací_abecedy (jde o jednoduché substituční šifrování). Když bude v proměnné Pergamen uložen kryptogram kapitána Kidda, ze slavné povídky Zlatý brouk Edgara Allana Poa, začínající řetězcem znaků: 53++!305))6*;, pak následující příkaz

say TRANSLATE(Pergamen, ,/* pokračování příště */
    "adeghinortlsbpvwmuycf", "5!8346*+(;0)2.']9?:-1")

nám odkryje záhadu pergamenu. Řešení začíná: agoodglassint.

Příkaz interpret

Příkaz interpret výraz nejprve vyhodnotí výraz a výsledný řetězec znaků provede jako příkaz nebo fragment programu. Program USHER vytváří prostředí, ve kterém můžeme zadat interpretu jazyka Rexx k provedení příkazy (i příkazy operačního systému) nebo jednořádkové programy.

/* Rexx program USHER */
do forever
  say 'Zadej fragment Rexx programu:'
  parse pull Fragment
  call INTERPRETUJ Fragment
end
/* Subroutine INTERPRETUJ */
INTERPRETUJ: procedure
  interpret ARG(1)
return

Příkaz parse pull přijme řádek textu odeslaný z klávesnice a příkaz interpret jej vykoná. Můžeme tedy například napsat:

if RANDOM(1, 2) = 1 then say "Hlava"; else say "Orel"

Totéž je v manuálu uvedeno jako samostatný program. USHER nás naučí spoustu věcí aniž bychom museli použít editor. Při vyhodnocování výrazů a studiu vestavěných funkcí nám pomůže následující program, zapsaný na jednom řádku jako vstup pro program USHER:

do until Exp = ""; say "?"; parse pull Exp; interpret "say" Exp; end

Uveďme si příklad možné konverzace:

?
1 + (2 * 12)
25
?
"[" || SPACE(" Edgar  Allan     Poe ") || "]"
[Edgar Allan Poe]

Povšimněte si, že jméno proměnné, v tomto případě Exp, může být vytvořeno až za běhu programu. Příkaz procedure v programu USHER zajistí, aby dynamicky vytvořené jméno proměnné existovalo jen po dobu provádění podprogramu INTERPRETUJ. Chceme-li, aby hodnota určité proměnné, nazvěme ji třeba Global, byla dostupná i při dalším volání podprogramu, musíme změnit jeho první řádek na:

INTERPRETUJ: procedure expose Global

... i dospělý člověk je schopen hypnoticky poslechnout návod na podivně vyhlížející věcičce "Malý kouzelný vyrážeč pojistek: Vlož do zásuvky a ZASUŇ!", napsal B. Higman v knize Porovnávací studie programovacích jazyků. Nejprve si zjistěte, jakým způsobem můžete přerušit aktivní proces ve vámi používaném systému, potom zadejte:

/* Pád do Malströmu */ interpret ARG(1)

a pak si zkuste představit, co vlastně prováděl interpret jazyka, který "hypnoticky poslechl" vás. V programu USHER je použit "nekonečný" cyklus se záhlavím do forever. Jak se vlastně ukončí jeho provádění? Zadáme-li příkaz exit nebo dopustíme-li se například syntaktické chyby. Druhé "řešení" ukazuje, že program USHER je nutné ještě rozšířit. Pro ošetření chyb je v jazyce Rexx k dispozici příkaz signal. Při rozšiřování programu USHER se můžete inspirovat programy REXXTRY v systému OS/2. Využitím interpretace v programování (pro zkrácení textu programu) se zabývá J. Bentley v knize Perly programování.

Cvičení 2

Podle F. M. Whyta se typ podvozku parní lokomotivy označoval trojčíslím. Například u lokomotivy Santa Fe třídy 3700 z roku 1917 (podívejte se na obrázek):

Santa Fe 3700 (4-8-2) měla 14 kol

bylo uspořádání kol popsáno jako 4 - 8 - 2. První a poslední číslo ukazovalo počet nespřažených předních a zadních kol, prostřední číslo ukazovalo počet spřažených neboli hnacích kol. Napište příkaz, který pro správně zadanou hodnotu typu podvozku, uloženou v proměnné Typ, určí, kolik měla lokomotiva celkem kol a výsledek zobrazí.

Funkce SOURCELINE

V článku Reflections on Trusting Trust (CACM, č. 8 1984) se K. Thompson zmiňuje o úloze napsat co nejkratší program, který by na výstupu produkoval svou věrnou kopii. Nejkratší program v jazyce Rexx, který splňuje zadání, je (v prostředí TSO/E by musela být úvodní poznámka /*Rexx*/):

/**/say SOURCELINE(1)

Funkce SOURCELINE(n) vrací hodnotu n-tého řádku programu. Předpokládejme, že máme zobrazit zprávu:

+-------------------+
| Zvýrazněná zpráva |
+-------------------+

Můžeme napsat program s třemi příkazy say. Výhodu složitějšího programu POZOR poznáme při opakovaných změnách zprávy.

/* Rexx program POZOR
+-------------------+
| Zvýrazněná zpráva |
+-------------------+
*/
do J = 2 while SOURCELINE(J) <> "*/"
  say SOURCELINE(J)
end

V jazyce Rexx je i řádek programu znakovým řetězcem přístupným k zpracování.

Cyklus s více výstupy

Užitečnost takového cyklu dokazoval G. V. Bochmann v práci Multiple Exits from a Loop Without the GOTO (CACM, č. 7 1973) na řešení úlohy: Je dán vektor N čísel, najděte index prvního, například nulového, prvku.
O čtrnáct let později byl publikován dopis F. Rubina redakci časopisu CACM (č. 3, 1987), ve kterém je, jako příklad efektivního použití příkazu goto, uvedeno řešení úlohy: Je dána matice typu NxN, najděte index prvního nulového řádku.
Je možné, že v roce 2001 (1987 + 14) vyjde příspěvek o výhodách strastiplného putování programem s příkazy goto, obsahující úlohu: Je dáno trojrozměrné pole M matic typu NxN, najděte index první nulové matice.
Program ODYSEA ukazuje řešení v jazyce Rexx už nyní.

/* Rexx program ODYSEA */
M = 6; N = 100
X. = 0
X.1.1.1 = 1; X.2.94.15 = 1; X.3.16.8 = 1
X.4.5.2 = 1; X.5.16.30 = 0; X.6.86.3 = 1
do I = 1 to M
  do J = 1 to N
    do K = 1 to N
      if X.I.J.K <> 0 then iterate I
    end
  end
  leave I
end
if I<=M then say I || ". matice je nulová"
  else say "Nulová matice neexistuje"

Příkaz iterate I ukončuje provádění vnitřních cyklů a výpočet pak pokračuje další iterací hlavního cyklu s řídicí proměnnou I. Příkaz leave I ukončuje provádění hlavního cyklu s řídicí proměnnou I.
Příkaz cyklu v kombinaci s příkazy iterate a leave umožňuje přehledně zapsat i neobvyklé řídicí struktury (viz obrázek), jinak známé jen z teorie, například z dodatku J. Hořejše ke knize Z. Manny Matematická teorie programů.

do-while/until-leave/iterate-end struktury

Zápis X.I.J.K označuje prvek pole X (obdoba zápisu X(I, J, K) ve FORTRANu nebo X[I, J, K] v Pascalu). Tak jako kterákoliv jiná proměnná i prvek pole alokuje paměť, až když je mu přiřazena hodnota. V případě programu ODYSEA alokuje paměť pouze 6 prvků.

Zajímavý je případ, když se hodnota přiřadí přímo jménu pole:

X. = 0

V dalším průběhu provádění programu pak bude každý prvek pole, kterému nebyla explicitně přiřazena hodnota, považován za nulový.

Asociativní pole

Vnitřní funkce SLOVA určí všechna slova, která se v zadaném textu vyskytují alespoň K-krát.

/* Rexx funkce SLOVA */
SLOVA: procedure
   Text = ARG(1); K = ARG(2)
   Seznam. = 0
   Vysledek = ""
   do J = 1 to WORDS(Text)
    Slovo = WORD(Text, J)
    Seznam.Slovo = Seznam.Slovo + 1
    if Seznam.Slovo = K then Vysledek = Vysledek Slovo
  end
return Vysledek

Hodnotou proměnné Slovo může být obecně libovolný řetězec znaků. Seznam.Slovo pak označuje prvek pole určený touto hodnotou jako indexem.
    M. F. Cowlishaw, autor jazyka Rexx, uvedl v článku The design of the Rexx language. IBM Systems Journal, r. 23, č. 4 1984, ss. 326-335, příklad vnitřní funkce, která vypustí duplicitní slova v posloupnosti slov. Jde o speciální případ funkce SLOVA pro K = 1.

jen1: procedure
  parse arg text
  seznam. = 0
  vysledek = ''
  do while text <> ''
    parse var text slovo text
    if seznam.slovo then iterate
    seznam.slovo = 1
    vysledek = vysledek slovo
  end
return vysledek

Jak vidíte, jedno a totéž je možné v jazyce Rexx vyjádřit různými prostředky a sami si můžete zvolit konvenci pro zápis textu programu. Při provádění programu se malá písmena abecedy převedou na velká. Výjimku tvoří text uzavřený do apostrofů nebo uvozovek - zápis řetězcové konstanty - a text poznámky.

Cvičení 3

Práce na textu článku zahrnuje rušení, přesuny a doplňování vět. Často se mi stává, že stejná formulace je nakonec uvedena v téměř sousedících větách. Upravte funkci SLOVA na podprogram, který zobrazí všechny posloupnosti slov začínající a končící týmž slovem a obsahující zadaný počet K nebo méně slov. Využijte vestavěnou funkci SUBWORD(řetězec, n, d), která vrací podřetězec řětězce obsahující d slov řetězce počínaje jeho n-tým slovem.

Co je až tak zajímavého na jazyku Rexx ...

..., aby stálo za to se jej učit?

Programy v jazyce Rexx jsou snadno přenositelné do prostředí jiných operačních systémů (důkaz najdete na webovské stránce tvůrce jazyka Mike Cowlishawa).
Výrazovými prostředky jazyka lze zapsat i složitý algoritmus krátkým programem.
Krátké programy mohou být užitečné jako prototypy.
Rexx umožňuje vytvářet různá prostředí. Příkladem může být program USHER - prostředí pro výuku a studium jazyka a interakci s operačním systémem.
Je vhodný pro výuku programování. Domnívám se, že by mohl být vynikajícím pomocníkem při studiu základů kybernetiky, matematické teorie programů nebo konstrukce kompilátorů (viz implementace univerzálního Turingova stroje). Pokusem o ucelený důkaz možností jazyka při popisu, definici a kódování algoritmů je Album algoritmů a technik.
Je ideálním nástrojem pro vývoj a testování algoritmů. Praktickou ukázkou je můj článek FIND, SELECT, MODIFIND.
Začínající programátor(ka) bude považovat asociativní pole a interpretaci za přirozené prostředky, i když J. Bentley zahrnul jejich využití mezi perly programování.
B. W. Kernighan a P. J. Plauger radí v knize The Elements of Programming Style (v druhém vydání je to dvacáté první přikázání): Program napište nejprve v jednoduchém pseudojazyce a teprve potom jej převeďte do jazyka, který používáte. Pro mě je jazyk Rexx ideálním "pseudojazykem": vyhovuje mi jeho syntaxe a správnost i fragmentů programů může otestovat počítač.

 

Přitom všechna kouzla jazyka vyplývají z důsledného uplatňování jen několika málo obecných výrazových prostředků. V povídce Zánik domu Usherů napsal E. A. Poe: ... nesnášel žádnou hudbu kromě jistých akordů hraných na strunné nástroje. Snad právě z tohoto úzkého výběru, kterým se také omezoval při hře na kytaru, vznikl do značné míry fantastický styl jeho přednesu.

Řešení cvičení

1. Program KOLIK

/* Rexx program KOLIK */ say 9 ** (9 ** 9)

zobrazí na displeji 4.28124773E+369693099; 9**(9**9) má tedy 369 693 100 číslic.

2.
interpret "say -(-" Typ")"

3.

do J = 1 to WORDS(Text)
  Slovo = WORD(Text, J)
  L = Seznam.Slovo
  if L <> 0
    then do
      V = J - L + 1
      if V <= K then say SUBWORD(Text, L, V)
    end
    Seznam.Slovo = J
end


Jak vyslovovat slovo "Rexx"?

Gerard Shildberger z Hankinsonu v Severní Dakotě mi na tento dotaz odpověděl:
REXX se vyslovuje jako "hex" ale s "R" na začátku. Rýmuje se to třeba se slovem flex (kabel). Mike Cowlishaw nazval svůj jazyk REX, ale tento název už byl chráněnou značkou a tak firma IBM přidala další "X".

Poznámky a poděkování

První verze "Úvodu ..." byla publikována v časopise Softwarove noviny, r. 6, č. 12 (1995), 114-118. Některé informace jsem převzal ze svých příspěvků uveřejněných v Archive of REXXLIST REXX & E. A. Poe 98/10/09, Complements to Words, words, words 98/10/26. Dále jsem použil tuto literaturu:


M. F. Cowlishaw: The REXX Language - A Practical Approach to Programming

Prentice-Hall, inc., Engelwood Cliffs, New Jersey 1985

J. Bentley: Associative Arrays
CACM, Vol. 28, No. 6 (June 1985), 570-576

F. Clarke: Words, words, words...
The RexxLA Newsletter, October 1998, Issue 199810

Helpy z Personal REXX for Windows(TM)
Version 3.50, Quercus System

H. F. Ledgard, M. Marcotty: A Genealogy of Control Structures
CACM, Vol. 18, No. 11 (November 1975), 629-639


hlavní stránka english

změněno 10. listopadu 2003
Copyright © 1998-2003 Vladimír Zábrodský